实时

您的位置:首页>产品 >

热头条丨使用 IdentityServer 保护 Vue 前端

前情提要

《使用 IdentityServer 保护 Web 应用(AntD Pro 前端 + SpringBoot 后端)》中记录了使用 IdentityServer 保护前后端的过程,其中的前端工程是以 UMI Js 为例。今天,再来记录一下使用 IdentityServer 保护 Vue 前端的过程,和 UMI Js 项目使用 umi plugin 的方式不同,本文没有使用 Vue 相关的插件,而是直接使用了 oidc-client js。

另外,我对 Vue 这个框架非常不熟,在 vue-router 这里稍微卡住了一段时间,后来瞎试居然又成功了。针对这个问题,我还去 StackOverflow 上问了,但并没有收到有效的回复:https://stackoverflow.com/questions/74769607/how-to-access-vues-methods-from-navigation-guard

准备工作

首先,需要在 IdentityServer 服务器端注册该 Vue 前端应用,仍然以代码写死这个客户端为例:


(相关资料图)

new Client{ClientId = "vue-client",ClientSecrets = { new Secret("vue-client".Sha256()) },ClientName = "vue client",AllowedGrantTypes = GrantTypes.Implicit,AllowAccessTokensViaBrowser = true,RequireClientSecret = false,RequirePkce = true,RedirectUris ={"http://localhost:8080/callback","http://localhost:8080/static/silent-renew.html",},AllowedCorsOrigins = { "http://localhost:8080" },AllowedScopes = { "openid", "profile", "email" },AllowOfflineAccess = true,AccessTokenLifetime = 90,AbsoluteRefreshTokenLifetime = 0,RefreshTokenUsage = TokenUsage.OneTimeOnly,RefreshTokenExpiration = TokenExpiration.Sliding,UpdateAccessTokenClaimsOnRefresh = true,RequireConsent = false,};

在 Vue 工程里安装 oidc-client

yarn add oidc-client

在 Vue 里配置 IdentityServer 服务器信息

在项目里添加一个 src/security/security.js文件:

import Oidc from "oidc-client"function getIdPUrl() {return "https://id6.azurewebsites.net";}Oidc.Log.logger = console;Oidc.Log.level = Oidc.Log.DEBUG;const mgr = new Oidc.UserManager({authority: getIdPUrl(),client_id: "vue-client",redirect_uri: window.location.origin + "/callback",response_type: "id_token token",scope: "openid profile email",post_logout_redirect_uri: window.location.origin + "/logout",userStore: new Oidc.WebStorageStateStore({store: window.localStorage}),automaticSilentRenew: true,silent_redirect_uri: window.location.origin + "/silent-renew.html",accessTokenExpiringNotificationTime: 10,})export default mgr

在 main.js 里注入登录相关的数据和方法数据

不借助任何状态管理包,直接将相关的数据添加到 Vue 的 app 对象上:

import mgr from "@/security/security";const globalData = {isAuthenticated: false,user: "",mgr: mgr}

方法

const globalMethods = {async authenticate(returnPath) {console.log("authenticate")const user = await this.$root.getUser();if (user) {this.isAuthenticated = true;this.user = user} else {await this.$root.signIn(returnPath)}},async getUser() {try {return await this.mgr.getUser();} catch (err) {console.error(err);}},signIn(returnPath) {returnPath ? this.mgr.signinRedirect({state: returnPath}) : this.mgr.signinRedirect();}}

修改 Vue 的实例化代码

new Vue({router,data: globalData,methods: globalMethods,render: h => h(App),}).$mount("#app")

修改 router

在 src/router/index.js中,给需要登录的路由添加 meta 字段:

Vue.use(VueRouter)const router = new VueRouter({{path: "/private",name: "private page",component: resolve => require(["@/pages/private.vue"], resolve),meta: {requiresAuth: true}}});export default router

接着,正如在配置中体现出来的,需要一个回调页面来接收登录后的授权信息,这可以通过添加一个 src/views/CallbackPage.vue文件来实现:

<script>export default {async created() {try {const result = await this.$root.mgr.signinRedirectCallback();const returnUrl = result.state ?? "/";await this.$router.push({path: returnUrl})}catch(e){await this.$router.push({name: "Unauthorized"})}}}</script>

然后,需要在路由里配置好这个回调页面:

import CallbackPage from "@/views/CallbackPage.vue";Vue.use(VueRouter)const router = new VueRouter({routes: {path: "/private",name: "private page",component: resolve => require(["@/pages/private.vue"], resolve),meta: {requiresAuth: true}},{path: "/callback",name: "callback",component: CallbackPage}});export default router

同时,在这个 router 里添加一个所谓的“全局前置守卫”(https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%85%A8%E5%B1%80%E5%89%8D%E7%BD%AE%E5%AE%88%E5%8D%AB),注意就是这里,我碰到了问题,并且在 StackOverflow 上提了这个问题。在需要调用前面定义的认证方法时,不能使用 router.app.authenticate,而要使用 router.apps[1].authenticate,这是我通过 inspect router发现的:

...router.beforeEach(async function (to, from, next) {let app = router.app.$data || {isAuthenticated: false}if(app.isAuthenticated) {next()} else if (to.matched.some(record => record.meta.requiresAuth)) {router.apps[1].authenticate(to.path).then(()=>{next()})}else {next()}})export default router

到了这一步,应用就可以跑起来了,在访问 /private 时,浏览器会跳转到 IdentityServer 服务器的登录页面,在登录完成后再跳转回来。

添加 silent-renew.html

注意 security.js,我们启用了 automaticSilentRenew,并且配置了 silent_redirect_uri的路径为 silent-renew.html。它是一个独立的引用了 oidc-client js 的 html 文件,不依赖 Vue,这样方便移植到任何前端项目。

oidc-client.min.js

首先,将我们安装好的 oidc-client 包下的 node_modules/oidc-client/dist/oidc-client.min.js文件,复制粘贴到 public/static目录下。

然后,在这个目录下添加 public/static/silent-renew.html文件。

Silent Renew Token<script src="oidc-client.min.js"></script><script>console.log("renewing tokens");new Oidc.UserManager({userStore: new Oidc.WebStorageStateStore({ store: window.localStorage })}).signinSilentCallback();</script>

给 API 请求添加认证头

最后,给 API 请求添加上认证头。前提是,后端接口也使用同样的 IdentityServer 来保护(如果是 SpringBoot 项目,可以参考《[使用 IdentityServer 保护 Web 应用(AntD Pro 前端 + SpringBoot 后端) - Jeff Tian的文章 - 知乎](https://zhuanlan.zhihu.com/p/533197284) 》);否则,如果 API 是公开的,就不需要这一步了。

对于使用 axios 的 API 客户端,可以利用其 request interceptors,来统一添加这个认证头,比如:

import router from "../router"import Vue from "vue";const v = new Vue({router})const service = axios.create({// 公共接口--这里注意后面会讲baseURL: process.env.BASE_API,// 超时时间 单位是ms,这里设置了3s的超时时间timeout: 20 * 1000});service.interceptors.request.use(config => {const user = v.$root.user;if(user) {const authToken = user.access_token;if(authToken){config.headers.Authorization = `Bearer ${authToken}`;}}return config;}, Promise.reject)export default service

关键词:

推荐阅读
前情提要《使用IdentityServer保护Web应用(AntDPro前端+SpringBoot后端)》中记录了使用IdentitySer

2022-12-20 00:21:05

富春染织:富春染织2022年第四次临时股东大会会议资料

2022-12-19 16:19:04

在自动售(取)票机,请将乘车人的居民身份证原件,放在机器标明的位置,由机器自动识读后,按提示操作,即可换取纸质车票自助售票机系统由微

2022-12-19 14:25:50

1、在电脑的百度上搜索长春市政府,找到官方网站点击进入。2、进入到长春市政府的官网以后,点击上方的办事服务进入。3、页面跳转以后点击

2022-12-19 14:25:46

闺蜜节是2015年10月10日在北京发起的一个文化节日。该节日由全球闺蜜联盟的张驰先生发起,是在中华传统节日西方洋节侵蚀的大背景下,传承中

2022-12-19 14:25:43

按照西方的划代法,第四代战机主要特点是具有突出的隐身性能、超音速巡航能力、超常规机动性和敏捷性、短距起降能力。我国的第四代战机均在

2022-12-19 14:25:39

痛风除了平时禁止吃心、肝、肾等动物内脏和所有豆制品外,减少吃海产品,禁酒就可以了。痛风除了以上几类不可食用外,其他没有过多的限制。

2022-12-19 14:25:36

分解地点:西海岸的达芙妮。分解方法:1、装扮栏都被时装填满时,游戏会提醒大家物品栏空间不足。2、这时,大家需要找到游戏里的一个NPC,

2022-12-19 14:25:24

歌词:主啊我赞美你因为你拣选了我在这茫茫的人海中是你把我找寻主啊我赞美你因为你爱了我你的爱充满整个宇宙充满整个山河你的爱曾拯救多少

2022-12-19 14:25:20

绿谷雅园属于湖东街道,湖东街道属于河南省信阳市浉河区西南,南湖以东,湖东街道办事处由原信阳市湖东经济技术开发区更名而来(湖东开发区

2022-12-19 14:25:14

浙江查处一批哄抬涉疫物资价格违法案件商品最高涨幅超600%针对近期涉疫物资市场出现价格异常波动情况,浙江省市场监督管理局加大涉疫医疗药品

2022-12-19 10:50:08

网贷逾期一般会上征信,有些借贷机构在用户逾期后一天后就会上报给征信机构,而有些借贷机构则是会在几天后上报给征信机构,因为有些借贷机构可

2022-12-19 01:11:58

近期,大家都非常担心一件事,不知道什么时候会变“阳”!当某天有人告诉你所购买的快递检测新冠病毒为“阳性”,你会有什么反应?临安一女子

2022-12-18 14:16:10

买卖人口,是严重的刑事犯罪,被查处后绝对要判刑。相关链接:《刑法》第二百四十条拐卖妇女、儿童的,处五年以上十年以下有期徒刑,并处罚金

2022-12-17 15:44:21

截至12月9日,今年以来医药行业涨幅靠后,累计涨幅-17 09%,排名申万一级行业第21 31位。同时,估值已处于行业相对较低水平,当前市盈率为24 4

2022-12-17 01:15:22

花旗银行在一些地方也是十分常见的,但最近听说花旗将关闭在大陆个人银行业务,看看具体情况是什么样的?花旗是哪个国家的银行?

2022-12-16 16:38:45

新尊贵型740Li指导价:141分,大灯不一样。百公里加速7 8秒。所以看你对车的要求。豪华型137 8万。很简单。区别双涡轮730是2 9排量自然吸气!增

2022-12-16 10:38:18

乡村工匠丨“一见钟琴”守匠心---从2008年白玉昆选择返乡创业投身马头琴制作行业,到如今成为内蒙古兴安盟内首屈一指的民族手工艺非遗传承人,

2022-12-15 22:51:10

截至2022年12月15日收盘,邦德股份(838171)报收于9 07元,上涨0 11%,换手率1 1%,成交量0 33万手,成交额294 85万元。

2022-12-15 15:30:02

《人身损害赔偿解释》在赔偿项目方面和赔偿标准方面贯彻了全面赔偿的原则。其中赔偿项目方面增加了康复费、后续治疗费两项,并用“残疾赔偿金

2022-12-15 10:16:17