6. JS客户端基于隐式授权码模式实现单点登录 (VUE SPA 使用 oidc-client.js)

1. 概述

  • 本例将在上一个实例基础上实现纯js客户端认证,使用vue-cli 脚手架创建客户端app.

  • 使用oidc-client.js 组件,默认使用cookie 保存客户端凭据。

2. 服务端添加Client

纯js客户端需要新增一个client,并需要显式声明允许浏览器url 传递accesstoken,Conig 类新增代码如下:

new Client
            {
                ClientId="js",
                ClientName="vue Client",
                RequireConsent=false,
                 AllowAccessTokensViaBrowser=true,
                AllowedGrantTypes= GrantTypes.Implicit, // 隐式授权码
                RedirectUris={"http://localhost:8080/callback"},
                PostLogoutRedirectUris={"http://localhost:8080/logout"},
                AllowedScopes= new List<string>
                {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile
                }

            }

3. Vue客户端

3.1 准备vue client 工程项目

// 使用vue-cli  脚手架创建工程
vue create authclient
// 引用router 组件
npm isntall vue-router --s
// 引用oidc-client 组件
npm install oidc-client --s

3.2 创建两个页面组件(home & callback)

import Vue from 'vue'
import Router from 'vue-router'

import callback from '@/pages/callBack.vue'

import home from '@/pages/home.vue'
Vue.use(Router)

export default new Router({
    mode: 'history',
    routes: [{
        path: '/',
        component: home,
    },
    {
        path:'/callback',
        name:'callback',
        component:callback
    }
    ]
})

3.3 创建路由页面组件

// home
<template>
  <div class="hello">
    <h1>home page</h1>   
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

// callback

<template>
  <div>callback</div>
</template>

<script>
export default {
  name: 'callback',
  mounted() {
    this.$userManager.signinRedirectCallback().then(
      (u) => {
        console.log(u);

        window.history.replaceState(
          {},
          window.document.title,
          window.location.origin + window.location.pathname
        );


        window.location = '/';
      },
      (error) => {
        console.log(error);
      }
    );
  },
};
</script>


3.4 添加sso 组件,用于配置oidc客户端

import Oidc from 'oidc-client'

const host = location.origin

const authsServer = 'http://localhost:5010'

const userManager = new Oidc.UserManager({
    authority: authsServer,  // server 地址
    client_id: 'js',  // client id
    post_logout_redirect_uri: `${host}/logout`, // 退出登录
    redirect_uri: `${host}/callback`,
    silent_redirect_uri: `${host}/callback`,
    accessTokenExpiringNotificationTime: 4,  // 超时
    silentRequestTimeout: 2000,  // 
    response_type: 'token id_token',
    scope: 'openid profile',
    filterProtocolClaims: true
})

userManager.events.addUserSignedOut(() => {
    userManager.removeUser().then(() => {
        userManager.signinRedirect().catch(()=>{
            console.error('error wihile logout')
        })
    })

})

export default userManager;

3.5 main.js 注册oidc 和路由

import Vue from 'vue'
import App from './App.vue'



import userManager from './sso.js'
import router from './router.js'



Vue.config.productionTip = false

Vue.prototype.$userManager = userManager

router.beforeEach(async (to, from, next) => {
  if (to.name === 'callback') {
    next()
  } else if (to.name === 'logout') {
    console.log('log out....')
  } else {
    const user = await userManager.getUser();
    if (user) {
      next()
    }
    else {
      userManager.signinRedirect().catch(error => {
        console.error(error)
      })
    }

  }
})


new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

最终项目目录如下:

4. 启动调试

  • 先启服务器,再启客户端,此时客户端路由拦截器会重定向到localhost:5010 登录页
  • 输入之前配置的用户名密码,认证成功后会经过callback页面,跳转到客户端首页,并写入cookie,sessionstorage

posted @ 2020-11-23 16:34  aimigi  阅读(3119)  评论(3编辑  收藏  举报