使用 vuex-oidc 在 Vue 项目中对接 Duende IdentityServer

前情提要

上次,在《使用 IdentityServer 保护 Vue 前端 - Jeff Tian的文章 - 知乎 》中记录了直接在 Vue 项目里,不使用任何状态管理包,直接使用 oidc-client js 来对接 Duende IdentityServer,并且使用了 OAuth 2.0 的隐式许可模式。
今天,继续记录一下在 Vue 项目中对接 Duende IdentityServer (或者任何的其他的 OAuth 2.0 服务器。这次,我们使用 vuex 状态管理包,以及对应的 vuex-oidc 来对接 Duende IdentityServer,并且尝试一下 OAuth 2.0 的授权码许可模式。

步骤 0: 授权服务器端的配置工作

首先,需要在 Duende IdentityServer 中为该 Vue 项目配置好客户端。需要注意的是,不能直接复用在《使用 IdentityServer 保护 Vue 前端 - Jeff Tian的文章 - 知乎 》中使用的那个客户端。那个客户端已经配置了隐式许可。
尽管在授权服务器端可以直接为客户端添加一个授权码许可,并保存成功,然而,在实际对接过程中会碰到麻烦,即在从前端页面跳转到 Duende IdentityServer 页面后,会得到一个 invalid request 页面。
所以,需要为这个 Vue 项目专门配置一个使用授权码许可模式的客户端。

步骤 1: Vue 项目添加相关的依赖

这一次,我们不直接使用 oidc-client js,而是使用 oidc-client-ts 这个使用 TypeScript 的包,并且引入 vuex 和 vuex-oidc:

"oidc-client-ts": "^2.0.6",
"vuex": "^3.0.1",
"vuex-oidc": "^4.0.0"

步骤 2: 为 Vue 项目添加多环境支持

如果有多个对接环境,可以再引入 dotenv,并且在项目中可以添加多个不同的 .env 文件。比如用 .env.local 和 .env.live 来分别存储本地和线上环境的配置,那么,可以同步为这两个环境准备两套不同的启动命令,用来加载对应的配置:

"serve:local": "dotenv -e .env.local vue-cli-service serve",
"serve:live": "dotenv -e .env.live vue-cli-service serve",

步骤 3: 配置 OIDC 信息

以 env.local 为例:

VUE_APP_BASE_API=http://localhost:3000
VUE_APP_OIDC_CONFIG={
"accessTokenExpiringNotificationTime":30,
"authority":"https://id6.azurewebsites.net/",
"clientId":"xxx",
"clientSecret": "yyy", 
"redirectUri":"http://localhost:3000/oidc-callback",
"responseType":"code", 
"scope":"openid email profile","automaticSilentRenew":true,
"automaticSilentSignin":false,
"silentRedirectUri":"http://localhost:3000/silent-renew-oidc.html"
}

为了从项目中读取配置好的 OIDC 信息,添加一个 src/oidc/oidc_config.js文件:

export const oidcSettings = JSON.parse(process.env.VUE_APP_OIDC_CONFIG)

步骤 4: 添加 silent renew 页面

前文《使用 IdentityServer 保护 Vue 前端 - Jeff Tian的文章 - 知乎 》中使用了拷贝 oidc-client js 的方式,这一次我们不用这么做了。添加一个 src/oidc/silent-renew.js 文件:

import 'core-js/fn/promise'
import { vuexOidcProcessSilentSignInCallback } from 'vuex-oidc'

import { oidcSettings } from './oidc_config'

vuexOidcProcessSilentSignInCallback(oidcSettings)

步骤 5: main.js、App.vue 等文件的改造

上一次,我们没有使用状态管理工具,于是引入了一个 security js,并且通过 globalMethods 的方式注入了 OIDC 相关的方法,这一次,不再需要 security js,在实例化 Vue 时,也不再传递 data 和 methods,而是传递 store(因为用了 vuex 状态管理工具):

...
import App from './App.vue'
import store from './oidc/store'
import router from "@/router";

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

其中,src/oidc/store.js文件如下:

import Vue from 'vue'
import Vuex from 'vuex'
import { vuexOidcCreateStoreModule } from 'vuex-oidc'
import { oidcSettings } from './oidc_config'

Vue.use(Vuex)

export default new Vuex.Store({
    modules: {
        oidcStore: vuexOidcCreateStoreModule(
            oidcSettings,
            {
                namespaced: true,
                dispatchEventsOnWindow: true
            },
            // Optional OIDC event listeners
            {
                userLoaded: (user) => console.log('OIDC user is loaded:', user),
                userUnloaded: () => console.log('OIDC user is unloaded'),
                accessTokenExpiring: () => console.log('Access token will expire'),
                accessTokenExpired: () => console.log('Access token did expire'),
                silentRenewError: () => console.log('OIDC user is unloaded'),
                userSignedOut: () => console.log('OIDC user is signed out'),
                oidcError: (payload) => console.log('OIDC error', payload),
                automaticSilentRenewError: (payload) => console.log('OIDC automaticSilentRenewError', payload)
            }
        )
    }
})

这一次,我们使用了 vuex 做状态管理,在实例化 Vue 时,可以将 oidc 相关的方法直接映射过去(src/App.vue):

import {mapGetters} from "vuex";

export default {
  name: 'App',
    computed: {
      ...mapGetters('oidcStore', [
          'oidcAccessToken',
          'oidcIsAuthenticated',
          'oidcAuthenticationIsChecked',
          'oidcUser',
          'oidcIdToken',
          'oidcIdTokenExp'
      ]),
      userDisplay: function () {
          return this.oidcUser?.email ?? 'User'
      }
    },
  components: {
  },
  data() {
...

步骤 6: 改造 router

上一次,我们给私有路由添加了 meta 属性,并用 requiresAuth 来标记需要登录。这一次,我们使用 vuex-oidc 提供的 vuexOidcCreateRouterMiddleware 来达到同样的效果。src/router/index.js

import Vue from 'vue'
import OidcCallback from "@/views/OidcCallback.vue";
import Router from "vue-router";
import {vuexOidcCreateRouterMiddleware} from "vuex-oidc";
import store from "@/oidc/store";

Vue.use(Router)
onst router = new Router({
    mode: 'history',
    base: '/ars-notification-dashboard',
    routes:  [
        {
            path: '/',
        },
        {
            path: '/private',
            name: 'private page',
            component: resolve => require(['@/pages/private.vue'], resolve)
        },
        {
            path: '/oidc-callback', 
            name: 'oidcCallback',
            component: OidcCallback,
            meta: {
                isPublic: true
            }
        }
]
});

router.beforeEach(vuexOidcCreateRouterMiddleware(store, 'oidcStore'))
export default router;

注意,这一次我们首先假定所有页面都需要登录,而对于登录回调页面,通过 meta 中的 isPublic 来标记允许匿名访问。对于登录回调页面,其代码如下。src/views/OidcCallback.vue

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

<script>
import { mapActions } from 'vuex'

export default {
  name: 'OidcCallback',
  methods: {
    ...mapActions('oidcStore', [
      'oidcSignInCallback'
    ])
  },
  created () {
    this.oidcSignInCallback()
      .then((redirectPath) => {
        this.$router.push(redirectPath)
      })
      .catch((err) => {
        console.error(err)
        this.$router.push('/signin-oidc-error') // Handle errors any way you want
      })
  }
}
</script>

步骤 7: 给 API 请求添加认证头

这一步其实是与前文《使用 IdentityServer 保护 Vue 前端 - Jeff Tian的文章 - 知乎 》一致的,只是取 token 的写法略有调整。src/api/request.js

import store from '@/oidc/store'

service.interceptors.request.use(config => {
    const accessToken = store.state.oidcStore.access_token
    if(accessToken){
        config.headers.Authorization = `Bearer ${accessToken}`;
    }
    return config
})

  • 21
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Vue OIDC 是一个 Vue.js 应用程序的 OpenID Connect 客户端。OIDC 是一种身份验证协议,允许用户使用他们的身份验证凭据(如用户名和密码)登录到一个 Web 应用程序,而无需在每个应用程序注册一个新的帐户。 Vue OIDC使用方法如下: 1. 安装 Vue OIDC: ```bash npm install vue-oidc-client --save ``` 2. 在 Vue.js 应用程序的 main.js 文件导入 Vue OIDC 并初始化: ```javascript import { createOidcAuth } from 'vue-oidc-client' const oidcAuth = createOidcAuth('auth0', { clientId: 'YOUR_CLIENT_ID', issuer: 'YOUR_ISSUER', redirectUri: 'http://localhost:8080/callback', scope: 'openid profile email', responseType: 'code' }) ``` 3. 在 Vue.js 应用程序的 App.vue 文件使用 Vue OIDC: ```vue <template> <div> <button v-if="!$oidc.isAuthenticated()" @click="$oidc.login()">Login</button> <button v-if="$oidc.isAuthenticated()" @click="$oidc.logout()">Logout</button> <div v-if="$oidc.isAuthenticated()"> <p>Welcome, {{ $oidc.user.profile.name }}!</p> <p>Your email is {{ $oidc.user.profile.email }}.</p> </div> </div> </template> <script> export default { mounted () { this.$oidc.userManager.getUser().then(user => { if (user) { console.log('User is logged in', user) } else { console.log('User is not logged in') } }) } } </script> ``` 在上面的示例,我们使用 $oidc 对象来访问用户的身份验证状态和个人资料信息。如果用户已经登录,我们可以使用 $oidc.user 对象访问用户的个人资料信息。 总的来说,Vue OIDC 提供了一个方便的方式来使用 OpenID Connect 身份验证协议来保护您的 Vue.js 应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值