全球微资讯!使用 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>Sign-in in progress... 正在登录中……
然后,需要在路由里配置好这个回调页面:
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文件。
给 API 请求添加认证头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 请求添加上认证头。前提是,后端接口也使用同样的 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
标签:
精彩推送
哈尔滨:新增新冠肺炎本土确诊病例5例 计划于23日完成全员核酸检测筛查
新华社哈尔滨9月22日电(记者强勇、杨思琪)9月22日,哈尔滨市应对新型冠状病毒感染肺炎疫情工作指挥...
新闻快讯
X 关闭
X 关闭
新闻快讯
- 全球微资讯!使用 IdentityServer 保护 Vue 前端
- 中恒集团(600252)12月19日主力资金净卖出2042.30万元|全球热推荐
- 天奈科技: 天奈科技关于向控股子公司提供财务资助的公告
- 诺邦股份董秘回复:公司控股子公司杭州国光旅游用品有限公司的杀菌消毒湿巾选用氯己定二葡糖酸盐成分_环球聚焦
- 2023年房企580亿美元债待偿 “内保外贷”重启下海外融资规模有望扩容
- 退烧药怎么吃?布洛芬和对乙酰氨基酚有啥区别?
- 广发e秒贷网贷逾期41年多久会上征信
- 红土创新新科技股票基金经理变动:增聘盖俊龙为基金经理
- 天天时讯:[快讯]卓易信息:江苏卓易信息科技股份有限公司持股5%以上股东集中竞价减持股份计划
- 热议:星源卓镁:公司新能源汽车产品应用的终端品牌有特斯拉Model S/X、福特纯电动“野马”、别克新能源、奥迪E-Tron、智己新能源、红旗E-QM5等
- 12月15日重庆要闻速览
- 澜起科技(688008.SH)股东嘉兴宏越及其关联方合计持股比例降至5%以下:环球今亮点
- 军人抵押贷款是多少(军人证)-每日热闻
- 碳化硅板块12月14日涨0.55%,国星光电领涨,主力资金净流出4.85亿元 前沿热点
- 高校学生陆续返乡 同程旅行推出“安心退”“免费接送机”等学生专属权益
- 自动离职员工有补偿金吗 当前看点
- 假期旅行计划存不利影响 捷蓝航空(JBLU.US)下调Q4业绩指引 全球即时
- 最贵9999元!AMD RX 7900系列太少买不到?厂商正补库存_天天新动态
- 今热点:向往的生活5:张艺兴“浪费”行为被黄磊看穿,何炅一旁机智解围!
- 华润电力(00836):“20华润Y2”将于12月14日本息兑付
- 等了30年!Windows 95展示的功能在Windows 11上正式落地:全球即时
- *ST天马: 简式权益变动报告书
- 惠云钛业: 向不特定对象发行可转换公司债券之上市保荐书
- 【环球聚看点】握指成拳,金融全力支持复工复产复商复市
- 环球速看:银信科技董秘回复:公司业务暂不涉及NFT、数字确权、数字脱敏领域
- 鄂州花湖机场正式投运 助推鄂州从临空经济迈向枢纽经济
- 浙江出台支持稳外贸稳外资的十条措施 推进国际贸易与投资结算便利化
- 潮起钱塘|2022全球跨境电商峰会即将在杭州举行
- 杭州8个项目斩获7项大奖 “中国创翼”创业创新大赛硕果累累
- 深圳市税务局聚焦小微市场主体 减税惠及100万户小微企业
- 国际金价持续走低 多家银行收紧个人贵金属业务
- 普瑞眼科启动申购 今年有望迎来眼科企业上市热潮
- 集聚“新人才”!雄安新区引进650余名优秀应届毕业生
- 2022年河北全省交通项目年度固定资产投资将完成860亿
- 河北省构建全方位多层次精准化智力援疆新格局
- 33.5877亿元!中铁四局本周完成建安产值
- 31省份新增确诊病例43例 其中本土病例28例
- 陕西华北黄淮有较强降水过程 热带低压影响海南岛等地
- 神舟十二号重返地球:“天地大搜救”
- 藏身网络平台 非法引流是如何“浇灌”黑灰产的?
- 黑龙江省22日12-24时新增新冠肺炎本土确诊病例3例
- 一大波雨水将至!北京今天白天有分散性阵雨 傍晚起降雨增多
- 久坐、体重大、锻炼少,腰椎间盘突出越来越年轻化
- 妈妈做手术带着26岁残障儿子住院 医院开“特殊病房”
- 清理入侵物种 恢复海岸生态
- 中秋国庆假期接踵而至 金九银十出行有哪些利与防?
- 当摄影遇到漫画,丰收画卷如此之美
- “社交牛掰症”有啥牛的?“梗”下的认同焦虑不能忽视
- 待遇跟上了,叫不叫“农民工”又何妨?
- “十一”出游最热门目的地:北京上海成都排前三