首页 >企业动态 > > 正文

使用 IdentityServer 保护 Vue 前端 世界速讯

来源: 2022-12-20 16:40:09
前情提要

《使用 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

上一篇: 下一篇:
x
推荐阅读

使用 IdentityServer 保护 Vue 前端 世界速讯

2022-12-20

小米11主板延保三年,保全机器“生命周期”,大厂风范彰显无遗

2022-12-20

波卡周报|31 项公投在 OpenGov 系统上提出,Bifrost 与 Astar & Shiden 开通 HRMP 通道!

2022-12-19

上海金山启动第二剂次新冠疫苗加强免疫接种,各街镇设临时接种点 全球简讯

2022-12-19

奇正藏药董秘回复:流感丸等抗疫产品根据市场需求,公司已经增加产量,保障患者用药需求

2022-12-19

【逝者】柳鸣九:一个90后的“灰姑娘”

2022-12-19

动态焦点:墨西哥赛三人20+热火击退马刺 巴特勒26+5希罗21+7

2022-12-18

五粮液曾从钦:白酒横跨一二三产业 推动产业融合发展 全球观点

2022-12-17

商品房买卖合同解除了后果是怎样的呢?

2022-12-17

【全球聚看点】斯坦森新片:《人之怒》节奏紧凑枪战火爆,好评热映中

2022-12-16

应对新冠疫情 钟南山提出8条个人防护建议

2022-12-16

金地集团: 董事会审计委员会工作制度(2022年12月修订)

2022-12-15

值得买(300785)12月15日主力资金净买入58.88万元|全球新要闻

2022-12-15

金达威:公司旗下品牌多特倍斯、Zipfizz、舞昆等产品通过跨境电商平台渠道进行销售

2022-12-15

长安汽车: 重庆长安汽车股份有限公司2022年面向专业投资者公开发行科技创新公司债券(第一期)发行公告 全球看点

2022-12-14

环球观点:粽子源于哪个朝代 粽子起源于哪个朝代

2022-12-14

新消息丨【机构调研记录】前海联合调研健之佳、龙磁科技

2022-12-14

12月13日佳沃食品(300268)龙虎榜数据:游资赵老哥上榜

2022-12-13

湘油泵董秘回复:公司没有该方面应披露的信息|天天简讯

2022-12-13

11月社融规模增量1.99万亿元 居民贷款环比改善

2022-12-12

借力新电商 西南山区有了新的致富经 全球观速讯

2022-12-12

思进智能: 国元证券股份有限公司关于思进智能成形装备股份有限公司首次公开发行前已发行股份上市流通的核查意见 今日视点

2022-12-11

涨停雷达:跨境电商个股异动 浔兴股份触及涨停

2022-12-09

南威软件董秘回复:公司在数字经济领域聚焦布局数字政府建设

2022-12-08

【环球时快讯】中远海控: 中远海控2022年中期权益分派实施公告

2022-12-06

安家补贴最高20万元!2022年度潮州市急需紧缺人才目录公布

2022-09-07

近日深圳成功发行政府债券58.98亿元 业内专家分析深圳地方债发行市场化水平持续提升中

2022-07-05

中消协发布2022年第一季度全国消协受理投诉分析报告

2022-05-24

总投资3172.5亿元 石家庄提前超额完成年度目标任务

2022-03-20

石家庄海关共签发RCEP原产地证书864份 货值3.9亿元

2022-03-20

蚌埠海关累计签发RCEP原产地证书35份 涉及金额2583.09万元

2022-03-20

绥化望奎以工业化思维为引领 推动肉类加工制造产业腾飞

2022-03-20

衡阳耒阳免费发放油茶苗 助推油茶产业稳步发展

2022-03-20

郴州安仁文旅项目集中开工 总投资1000万元

2022-03-20

2022年郴州计划重点推进文旅项目101个 总投资354亿元

2022-03-20

宿州泗县深入推进文旅融合发展 擦亮城市品牌

2022-03-20

汽车零部件产业“领头羊” 锦州力争一季度“开门红”

2022-03-20

油价或有望冲击“九元”大关 宁波新能源汽车市场如何

2022-03-20

从水塘到“云”端 全国最大高邮鸭养殖基地实现智慧养殖

2022-03-20

淡季不忘引流 京郊民宿市场有望迎来回暖

2022-03-20

镇江乡村一二三产业融合发展 闯出“镇江之路”

2022-03-20

总投资30亿元 盐城东台8个重大产业项目相继开工

2022-03-20

去年南京规上信息软件业企业实现营收7577.28亿元 同比增长10.3%

2022-03-20

2021年南京农业保险保费收入53.07亿元 同比增长19.13%

2022-03-20

安阳本土确诊病例上升至26例

2022-01-10

3次推迟婚期 满洲里抗疫民警兑现承诺:“我回来娶你了!”

2022-01-10

上海公安民警在岗位上迎接2022年“中国人民警察节”

2022-01-10

郑州核酸检测为中小学生开辟“绿色通道”

2022-01-10

反扒便衣警察“小曹”:藏在人海中的隐形“守护者”

2022-01-10

哥哥移植肾脏给病重弟弟 已在上海顺利康复

2022-01-10

网友与人裸聊被敲诈10万余元 被告人获刑5年

2022-01-10

1月10日起天津市暂停开展旅行社旅游业务活动

2022-01-10

“3·28”特大跨境电信网络诈骗案公开审理

2022-01-10

忠诚履职 守护万家灯火

2022-01-10

奥密克戎病例已涉天津、安阳 “动态清零”必须坚持!

2022-01-10

专家协作成功完成亲体肾移植 同“肾”兄弟顺利康复

2022-01-10

著名指挥陈燮阳携苏州交响乐团“相约北京”

2022-01-10

中国热科院选育出4个木薯新品种

2022-01-10

北京疾控:12月9日以来途经或旅居天津市人员请立即报备

2022-01-10

河南安阳本轮疫情累计报告确诊病例26例

2022-01-10

许勤批示黑土地保护不力问题:加快形成黑土地保护长效机制

2022-01-10

【挑战365天正能量速写画】第041期:当警娃难,当双警家庭的警娃更难

2022-01-10

重庆姐弟坠亡案两被告人5个月间聊天记录曝光

2022-01-10

因疫情防控措施落实不力 江苏金湖一超市被红牌警告

2022-01-10

江歌案一审判决刘鑫赔偿近70万元 有何依据?专家解读

2022-01-10

广东肇庆“毒驾连撞5车致1死”肇事司机被批捕

2022-01-10

一线工作近22年的缉毒警:我知道坏的是毒品不是人性

2022-01-10

青海保障门源地震后生活必需品应急物资

2022-01-10

江西最大文物倒卖案宣判:倒卖国家二级文物 9人获刑

2022-01-10

呼和浩特:寒假期间有条件的学校要开展校内托管服务

2022-01-10

广西东兴口岸恢复通关 入境需网上预约

2022-01-10

天津米面油存量由20天提高至30天 超市菜市场进货量翻倍

2022-01-10

天津市委市政府致全市父老乡亲的慰问信:我们一定能够打赢

2022-01-10

北京市十五届人大五次会议胜利闭幕

2022-01-10

“中国最后一个原始部落”翁丁老寨火灾原因公布

2022-01-10

天津:划定封控区 全市开展全员核酸检测

2022-01-10

重庆姐弟被生父扔下坠亡案上诉期结束 一审法院暂未收到两被告人上诉状

2022-01-10

子夜直击,天津寒天战“疫”

2022-01-10

兰州名师话“美育”:“尚乐立人”分层培优 以“美”润教

2022-01-10

中国边疆“北方第一所”:9名民警守护“生命禁区”

2022-01-10

江歌母亲江秋莲:尊重法院判决,法律认定在我意料之中

2022-01-10

河南安阳9日12时至24时新增11例本土确诊病例

2022-01-10

辟谣!网传“封控区管控区相继解封”通知并非西安

2022-01-10

铁路公安以110幅优秀书画作品庆祝人民警察节

2022-01-10

“中国最后一个原始部落”翁丁老寨火灾原因公布

2022-01-10

天津:划定封控区 全市开展全员核酸检测

2022-01-10

重庆姐弟被生父扔下坠亡案上诉期结束 一审法院暂未收到两被告人上诉状

2022-01-10

子夜直击,天津寒天战“疫”

2022-01-10

兰州名师话“美育”:“尚乐立人”分层培优 以“美”润教

2022-01-10

中国边疆“北方第一所”:9名民警守护“生命禁区”

2022-01-10

江歌母亲江秋莲:尊重法院判决,法律认定在我意料之中

2022-01-10

河南安阳9日12时至24时新增11例本土确诊病例

2022-01-10

辟谣!网传“封控区管控区相继解封”通知并非西安

2022-01-10

铁路公安以110幅优秀书画作品庆祝人民警察节

2022-01-10

老人5折环卫工8折生活困难免费 这家面馆背后有个暖心事

2022-01-10

亲手制作“城砖” 这群小学生期末测评“砌了一面明城墙”

2022-01-10

河南安阳本土确诊病例与奥密克戎变异株有关

2022-01-10

浙江北仑调整封控区后首轮核酸检测12528人 结果均为阴性

2022-01-10

广东加强春运期间重点交通场所疫情防控

2022-01-10

浙江永康第五轮“三区”核酸检测结果均为阴性

2022-01-10