首页 > 快讯 >

世界快讯:使用 IdentityServer 保护 Vue 前端

2022-12-19 22:09:23 来源:
前情提要

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

上一篇:

世界快看:新宙邦董秘回复:公司惠州四期建设内容为电池及半导体等电子化学品生产、研发和中试基地;项目建设周期预计2年

下一篇:

2023-2028年中国产后康复行业市场深度分析及投资潜力预测报告

x
推荐阅读

蚂蚁集团概念股板块12月20日跌1.2%,新华联领跌,主力资金净流出6.73亿元

世界热讯:上证50股指期权有哪些基本策略?

2023-2028年中国产后康复行业市场深度分析及投资潜力预测报告

世界快讯:使用 IdentityServer 保护 Vue 前端

世界快看:新宙邦董秘回复:公司惠州四期建设内容为电池及半导体等电子化学品生产、研发和中试基地;项目建设周期预计2年

Copilot 与 ChatGPT,让程序员如虎添翼 —— 让 AI 们为我们打工! 讯息

精彩看点:37万人被骗230亿!汪涵道歉,想极力撇清?

浓眉:健康+心态助我爆发 魔术师:AD领跑MVP争夺战|讯息

今日快讯:做证明条和借条有什么区别?

乐宝得尿促性素价格,乐宝得尿促性素针作用_全球即时

灵康药业: 2022年第二次临时股东大会会议资料

江苏银行被责令整改 部分业务员未取得基金从业资格

有“小巩俐”之称的刘敏涛,出演《活着》能超越巩俐吗?

全球微头条丨丽尚国潮(600738)12月15日主力资金净卖出2059.75万元

全球今头条!万泽股份:12月14日获融资买入165.57万元,占当日流入资金比例12.4%

野生刀鱼多少钱一斤,10元一斤普通刀鱼

没有找到尸体的子女过世财产怎么分配_世界讯息

【机构调研记录】东海基金调研龙磁科技|世界播资讯

北京海淀查处首例高价销售抗原试剂盒案件,拟处罚30万元

中旗新材:普通硅晶新材料可应用于建筑、装修装饰材料、光伏玻璃、陶瓷以及工业硅等领域-环球通讯

天天要闻:130亿卖掉银泰黄金!浙商大佬沈国军清仓式离场,身家565亿频登富豪榜

全球最新:挑战权威?雅博股份原董事长被终身禁入市场后仍担任公司“负责人”

世界滚动:普源精电(688337):科技股份有限公司公司董事会及监事会换届

中光学(002189)12月8日主力资金净卖出792.74万元

机构策略:A股震荡整固 预计将维持震荡格局 当前看点

全球最新:股票行情快报:协创数据(300857)12月6日主力资金净卖出784.51万元

贵阳发布“无废城市”建设实施方案 将实施7项主要任务

从手绘到AI技术突破 虚拟人撑起千亿级市场

2.4秒内完成怠速功率加载!深圳氢能企业突破核心技术

智能杆可路边充电 深圳路边充电服务上线运营

流程简化“交地即拿证” 渝北区跑出产业项目审批“加速度”

如何识别假银行理财产品?“飞单”现象屡禁不止

信贷投放呈现“五升一降” 数字金融助力“新市民”

蜜雪冰城推出扶持政策 为加盟商“减负”

双降!2月合肥新建商品住宅销售价格环比下降0.7%

每升涨0.6元!3月17日起 安徽省成品油价格调整

合肥循环经济示范园铆劲为企服务打造一流营商环境

蚌埠市推进“双招双引”大力吸引蚌商回归

徽州区“精准化”招才“高端化”引智为经济发展添动能

前两个月 安徽重点项目建设平稳推进

前两月温州进出口总值432.4亿元增速居全省第3

建立困难企业帮扶白名 单助力受俄乌局势影响企业走出困境

首批“浙江省博士创新站”公布 温州市三家建站企业入选

鹿城文化产业助力打响“千年商港、幸福温州”品牌

天津调整成品油价格 89号汽油(标准品)最高零售价格上调750元

市民“宅家阅读”热情高涨 移动端数字阅读馆访问量也达到29万人次

浙江外贸再度迎来“开门红” 1月至2月出口总值同比增长25.8%

中国结算将股票类业务最低结算备付金缴纳比例调降至16%

上海:临港数字孪生城全面启动建设 首批成果将展现在世人面前

我国1~2月份国民经济运行好于预期 为一季度开好局奠定了基础