背景

目前单位系统常用 Keycloak 作为认证系统后端,而前端之前写的也比较随意,这次用 Vue 3 插件以及 Ref 响应式来编写这个模块。另外,这个可能是全网唯一使用 keycloak 的 OIDC 原生更新密码流的介绍代码。

设计

依赖库选择

OIDC 客户端,这里选择 oidc-client-ts 来提供 OIDC 相关的服务,根据目前的调研这个算是功能比较齐全、兼容性比较好的 OIDC 客户端了。像 keycloak.js,其实也没有修改密码和自动刷新 token 的功能。另外像 Auth0 Vue SDK 则只能用于 Auth0,但他设计上还是不错的,也是通过 Vue 3 原生的插件功能实现的。

具体设计

根据 Vue 3 的官方插件文档,主要需要两部分组成,一个是需要定义一个 Plugin 并在里面使用 provide 来提供对象,另一个则是需要定义一个方法使用 inject 来接收提供的对象。

这里给原本的 oidc-client-ts 里的 UserManager 来个套娃,外层这个套一层,叫 AuthManager 。这样就可以将一些初始化时加载 LocalStorage 里的 token 等等逻辑封装在这里面,同时也可以对外暴露一些 Ref 让其他组件可以监听变化。

代码

废话不多说了,咱还是老样子,直接上代码

auth-manager.ts

import { UserManager, UserManagerSettings } from 'oidc-client-ts';
import { Plugin, inject, ref } from 'vue'; /**
* 用于注入的 key
*/
const PROVIDE_KEY = Symbol('oidc-provider');
/**
* 用户信息
*/
interface UserInfo {
/**
* 用户 id
*/
userId: string;
/**
* 用户名
*/
username: string;
/**
* token
*/
token: string;
/**
* 姓
*/
lastName: string;
/**
* 名
*/
firstName: string;
/**
* 邮箱
*/
email: string;
/**
* 认证时间
*/
authTime: number;
/**
* 角色
*/
roles: Array<string>;
}
/**
* 认证管理器
*/
class AuthManager {
/**
* token
*/
accessToken = ref('');
/**
* 用户信息
*/
userInfo = ref<UserInfo>();
/**
* oidc 客户端
*/
private oidc: UserManager;
/**
* 构造函数
* @param settings oidc 客户端配置
*/
constructor(settings: UserManagerSettings) {
this.oidc = new UserManager(settings);
// 当用户登录时,更新 token 和用户信息
this.oidc.events.addUserLoaded((user) => {
this.accessToken.value = user.access_token;
this.userInfo.value = {
userId: user.profile.sub,
username: user.profile.preferred_username || '',
token: user.access_token,
lastName: '',
firstName: '',
email: user.profile.email || '',
authTime: user.profile.auth_time || +new Date(),
roles: (user.profile.roles as Array<string>) || [],
};
// 开启静默刷新,清除过期状态
this.oidc.startSilentRenew();
this.oidc.clearStaleState();
});
// 当更新 token 失败时,退出登录
this.oidc.events.addSilentRenewError(() => {
this.logout();
});
// 当 token 过期时,退出登录
this.oidc.events.addAccessTokenExpired(() => {
this.logout();
});
// 初始化时加载用户信息
this.loadUser();
}
/**
* 加载用户信息
*/
async loadUser() {
const user = await this.oidc.getUser();
// 如果能加载出来则将信息放到 Ref 里
if (user) {
this.accessToken.value = user.access_token;
this.userInfo.value = {
userId: user.profile.sub,
username: user.profile.preferred_username || '',
token: user.access_token,
lastName: '',
firstName: '',
email: user.profile.email || '',
authTime: user.profile.auth_time || +new Date(),
roles: (user.profile.roles as Array<string>) || [],
};
this.oidc.startSilentRenew();
this.oidc.clearStaleState();
}
}
/**
* 登录
*/
login() {
return this.oidc.signinRedirect();
}
/**
* 检查是否已登录
* @returns 是否已登录
*/
async checkLogin(): Promise<boolean> {
const user = await this.oidc.getUser();
return user != null && !user.expired;
}
/**
* 退出登录
*/
logout() {
this.oidc.stopSilentRenew();
this.accessToken.value = '';
this.userInfo.value = undefined;
return this.oidc.signoutRedirect();
}
/**
* 刷新 token
* @param force 是否强制刷新
*/
async refresh(force?: boolean) {
// 如果不是强制刷新,则先检查用户可用,如果用户可用则不刷新
if (!force) {
const user = await this.oidc.getUser();
if (user != null && !user.expired) {
return user;
}
}
return this.oidc.signinSilent();
}
/**
* 登录回调
*/
loginCallback() {
return this.oidc.signinCallback();
}
/**
* 重置密码
*/
resetPassword() {
// 这里使用 keycloak 登录流中的更新密码流实现
this.oidc.signinRedirect({
scope: 'openid',
extraQueryParams: {
// 这里设置额外参数时,带上 keycloak 的更新密码流
kc_action: 'UPDATE_PASSWORD',
},
});
}
} /**
* 认证插件
*/
const authPlugin: Plugin<UserManagerSettings> = {
install: (app, options) => {
const auth = new AuthManager(options);
app.provide(PROVIDE_KEY, auth);
},
}; /**
* 使用认证管理器
* @returns 认证管理器
*/
const useAuthManager = () => {
return inject<AuthManager>(PROVIDE_KEY);
}; export { authPlugin, useAuthManager };

使用 Vue 3 插件(Plugin)实现 OIDC 登录和修改密码(OIDC 系统以 Keycloak 为例)的更多相关文章

  1. Android基于XMPP Smack Openfire下学习开发IM(一)实现用户注册、登录、修改密码和注销等

    http://blog.csdn.net/h7870181/article/details/8653865 以前学习过用Scoket 建立聊天,简单的建立聊天是没问题的,但如果要实现多人复杂的聊天,后 ...

  2. openfire Android学习(一)----实现用户注册、登录、修改密码和注销等

    以前学习过用Scoket 建立聊天,简单的建立聊天是没问题的,但如果要实现多人复杂的聊天,后台服务器代码就比较复杂,对于我这新手来讲就比较难了.后来在网上看到用openfire做服务器,利用强大的Sm ...

  3. node+mysql+express实现登录/注册/修改密码/删除用户 接口

    实现用户的注册.登录.修改密码.删除用户操作 用到的数据库:nodecms:表:user 目录结构: db目录下存放数据库操作语句: userSQL.js 用户有关的操作语句 router目录 接口路 ...

  4. 使用手机登录OWA修改密码的问题

    最近发现使用手机端登录OWA,安卓手机是可以修改密码的,如图1,但是iPhone就不成,safari和第三方都不可以,如图二. 图一 图二

  5. Mysql 免密码登录,修改密码及忘记密码操作

    ----免密码登陆 方式一 my.cnf增加[client]标签 [client] user="root" password="你的密码" 单对定义不同的客户端 ...

  6. 测试点常用用例设计(登录、修改密码、输入框、上传视频、XSS、URL篡改)

    1.无效-视频文件测试点: 视频大小过大 视频大小过小 视频名称过长 视频名称包含特殊字符 视频名称包含中文.中英混合 视频文件格式错误 视频文件重复性上传 2.有效-视频文件测试点: 选择符合要求的 ...

  7. Vue 两个字段联合校验典型例子--修改密码

    1.前言   本文是前文<Vue Element-ui表单校验规则,你掌握了哪些?>针对多字段联合校验的典型应用.   在修改密码时,一般需要确认两次密码一致,涉及2个属性字段.类似的涉及 ...

  8. Email接收验证码,以实现登录/注册/修改密码

    要求 1)实现Email形式的注册功能和相应的登录功能:2)实现忘记密码时的密码找回功能:3)存在数据库中的密码不能以明文形式存放,即建议在浏览器端发送请求前,调用js代码对用户的密码做md5加密 分 ...

  9. mysql免密登录和修改密码

    (1)停止mysql服务      /etc/init.d/mysqld   stop (2)跳过密码验证      mysqld_safe  --skip-grant-tables  & ( ...

  10. mysql 登录后 修改密码

随机推荐

  1. 如何使用CCXT交易数字货币现货

    更多精彩内容,欢迎关注公众号:数量技术宅,也可添加技术宅个人微信号:sljsz01,与我交流. 数字货币现货标准化接口 数字货币市场与股票.期货市场最大的不同点在于数字货币主流交易所数量很多.举个例子 ...

  2. java中Object 类

    一. Object类简介 Object类是Java.java.lang包下的核心类,Object类是所有类的父类,任何一个类如果没有明确的继承一个父类的话,那么它就是Object的子类: (使用无需导 ...

  3. 【WebGL系列-02】创建program上下文

    WebGL程序program对象的创建 program对象由顶点着色器对象和片元着色器对象构成,因此,创建program对象包含了两部分,一个是着色器对象的创建,一个是program对象的创建. 总体 ...

  4. EF 管理数据库架构

    本章会主要了解EF提供的独立迁移项目,用独立迁移项目自动创建dgml设计关系图和sql脚本. 迁移项目通常也叫(CodeFirst代码优先),在EF中迁移项目是在,在代码中设计数据库,每次对数据库的设 ...

  5. [Arch小贴士]在这里记录一些自己使用的小技巧

    哈喽!Arch 目录 0x00 设置开机自启动软件 首先 最后 0x01 ASLR开关 0x00 设置开机自启动软件 首先 首先进入目录/usr/share/applications,找到你要的那个软 ...

  6. C#利用Refit实现JWT自动续期

    前言 笔者之前开发过一套C/S架构的桌面应用,采用了JWT作为用户的登录认证和授权.遇到的唯一问题就是JWT过期了该怎么办?设想当一个用户正在进行业务操作,突然因为Token过期失效,莫名其妙地跳转到 ...

  7. Iphone常用工具

    iFunBox itools 百度助手 崩溃日志的路径 /var/mobile/Library/Logs/CrashReporter

  8. Unity 性能优化Shader分析处理函数:ShaderUtil.GetShaderGlobalKeywords用法

    Unity 性能优化Shader分析处理函数:ShaderUtil.GetShaderGlobalKeywords用法 点击封面跳转下载页面 简介 Unity 性能优化Shader分析处理函数:Sha ...

  9. Solution -「洛谷 P6287」「COCI 2016-2017」Mag

    Description Link. 定义一条链的价值为链上点权乘积除以节链上点数,求一条价值最小的链. Solution 结论:答案链上最多包含一个 \(2\)(其余全为 \(1\)),并且不在链的两 ...

  10. ModbusTCP 转 Profinet 主站网关控制汇川伺服驱动器配置案例

    ModbusTCP 转 Profinet 主站网关控制汇川伺服驱动器配置案例 ModbusTCP Client 通过 ModbusTCP 控制 Profinet 接口设备,Profinet 接口设备接 ...