日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

使用 Vue 3 插件(Plugin)实现 OIDC 登录和修改密码(OIDC 系统以 Keycloak 为例)

發布時間:2023/11/5 C# 78 coder
生活随笔 收集整理的這篇文章主要介紹了 使用 Vue 3 插件(Plugin)实现 OIDC 登录和修改密码(OIDC 系统以 Keycloak 为例) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

背景

目前單位系統常用 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 为例)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。