【问题标题】:Vue.js oidc-client-ts UserManager events not firingVue.js oidc-client-ts UserManager 事件未触发
【发布时间】:2022-12-24 04:32:30
【问题描述】:

我目前正在构建一个 Vue3 SPA 并尝试使用 oidc-client-ts javascript 库对用户进行身份验证。到目前为止,我已经成功地使用我现有的代码实现了登录/注销功能。我遇到的问题是我无法连接到 UserManager 提供的 addUserLoaded 或 addUserSignedIn 事件 (https://authts.github.io/oidc-client-ts/classes/UserManagerEvents.html)。 需要注意的一点是,当您登陆我的域时,我们会说 myapp.mydomain.com,您将被重定向到我们位于 myid.mydomain.com 的身份服务器,然后在成功登录后重定向回来。



在启动时我有以下内容

fetch("config.json", {'method': "GET"})
.then(response => { 
  if(response.ok) {
    response.json().then(appConfigData => {
      window.appConfig = appConfigData;
      createApp(App)
      .use(store)
      .use(router)
      .use(AccordionPlugin)
      .component("font-awesome-icon", FontAwesomeIcon)
      .mount("#app");
    });    
  } else{
      alert("Server returned " + response.status + " : " + response.statusText);
  }                
});

此 window.appConfig 具有用于初始化 UserManager 的设置对象



这是我导出的 AuthService.ts 类。请注意我正在向 UserManager 注册的构造函数中的事件。

import { UserManager, WebStorageStateStore, User, UserManagerEvents } from "oidc-client-ts";
import jwt_decode from "jwt-decode";
import store from "@/store";

export default class AuthService {

private userManager: UserManager;

constructor(configuration: any) {

const IDP_URL: string = configuration.IDP_URL;
const REDIRECT_URI: string = configuration.REDIRECT_URI;
const AUTH_TOKEN_URI: string = configuration.AUTH_TOKEN_URI;
const CLIENT_ID: string = configuration.CLIENT_ID;
const SILENT_RENEW_REDIRECT_URI: string = configuration.SILENT_RENEW_REDIRECT_URI;
const POPUP_REDIRECT_URI: string = configuration.POPUP_REDIRECT_URI;

const settings: any = {
  userStore: new WebStorageStateStore({ store: window.localStorage }),
  authority: IDP_URL,
  client_id: CLIENT_ID,
  redirect_uri: REDIRECT_URI,
  popup_redirect_uri: POPUP_REDIRECT_URI,
  response_type: "code",
  automaticSilentRenew: true,
  silent_redirect_uri: SILENT_RENEW_REDIRECT_URI,
  scope: "openid profile ContactCenterApi.READ_WRITE",
  post_logout_redirect_uri: AUTH_TOKEN_URI,
  loadUserInfo: true
};

this.userManager = new UserManager(settings);

this.userManager.events.addUserLoaded(_args => {
  console.log("USER LOADED EVENT");
  debugger;
  this.userManager.getUser().then(usr => {
    store.dispatch("getProducts", usr?.profile.sub) // load the users products
  });
});

this.userManager.events.addUserSignedIn(() => {
  console.log("USER SIGNED IN EVENT");
  debugger;
  this.userManager.getUser().then(usr => {
    store.dispatch("getProducts", usr?.profile.sub) // load the users products
  });
});
}

public getUser(): Promise<User|null> {
  return this.userManager.getUser();
}

public async login(): Promise<void> {
  return this.userManager.signinRedirect();
}

public logout(): Promise<void> {
  return this.userManager.signoutRedirect();
}


在我的 router/index.ts 文件中,我有以下内容

const auth = new AuthService(window.appConfig);

router.beforeEach(async (to, from, next) => {
  const user = await auth.getUser();
  const baseUri = window.appConfig.BASE_URI + "/#";

  console.log("redirectedUri = " + baseUri + to.fullPath);
  if (user) {
    if (!user.expired) {
      next();
    } else {
      sessionStorage.setItem("redirectedUri", baseUri + to.fullPath);
      await auth.login();
    }
  } else {
    sessionStorage.setItem("redirectedUri", baseUri + to.fullPath);
    await auth.login();
  }
});

export default router;


我的注销按钮非常简单

import  AuthService  from "@/auth/AuthService";

onselect: async function(event: MenuEventArgs) {
      var authService = new AuthService(window.appConfig); // settings are stored in the window when the app mounts
      if(event.item.text === 'Logout') {
        await authService.logout();
      }
}

例如,我想挂钩的事件之一是 addUserSignedIn 事件。但是,即使注销并重新登录,该事件也不会触发。我想使用此事件对用户数据进行一些基本的初始化。关于为什么这些事件没有触发的任何想法?

【问题讨论】:

  • 你有没有解决这个问题,我面临着完全相同的问题?
  • @franck102 我刚刚回答了我自己的问题。请看看我的回答,希望它能解决您的任何问题!

标签: vue.js vuejs3 openid-connect oidc-client-js


【解决方案1】:

这是最终为我工作的东西。这是我在代码库周围使用的 AuthService.ts 类。

    // AuthService.ts
    import { UserManager, WebStorageStateStore, User } from "oidc-client-ts";
    import jwt_decode from "jwt-decode";
    import store from "@/store";
    
    let userManager: UserManager;
    
    const currentURL = document.location.origin;
    fetch(currentURL + "/config.json", { 'method': "GET" })
      .then(config => {
        config.json()
          .then(configuration => {
            configuration['SSO_SETTINGS']['userStore'] = new WebStorageStateStore({ store: window.localStorage });
            userManager = new UserManager(configuration['SSO_SETTINGS']);
    
            userManager.events.addUserLoaded(newUser => {
              console.log("USER LOADED EVENT");
              userManager.storeUser(newUser);
              userManager.getUser().then(usr => {
                store.dispatch("getUserInfo", usr?.profile.sub) // load the user from my api
              });
            });
    
            userManager.events.addAccessTokenExpired(() => {
              userManager.signoutRedirect();
            })
    
            userManager.events.addSilentRenewError(error => {
              console.log("ERROR RENEWING ACCESS TOKEN.");
              console.log(error);
            })
          })
      })

export default class AuthService {

  public static getUser(): Promise<User | null> {
    return userManager.getUser();
  }

  public static async login(): Promise<void> {
    return userManager.signinRedirect();
  }

  public static logout(): Promise<void> {
    localStorage.clear();
    sessionStorage.clear();
    return userManager.signoutRedirect();
  }
}

我的 config.json 中更新的 SSO 设置对象被传递给用户管理器

"SSO_SETTINGS": {
    "userStore": "",
    "authority": "https://myauthorityurl.com",
    "client_id": "MyClientName",
    "redirect_uri": "http://localhost:8080/callback.html",
    "response_type": "code",
    "response_mode": "query",
    "automaticSilentRenew": true,
    "monitorSession": true,
    "silent_redirect_uri": "http://localhost:8080/silent-renew.html",
    "scope": "openid profile",
    "post_logout_redirect_uri": "http://localhost:8080",
    "loadUserInfo": true,
    "metadata": {
      "issuer": "https://myauthorityurl.com",
      "jwks_uri": "https://myauthorityurl.com/.well-known/openid-configuration/jwks",
      "authorization_endpoint": "https://myauthorityurl.com/connect/authorize",
      "end_session_endpoint": "https://myauthorityurl/Account/Logout",
      "token_endpoint": "https://iddev02.carexm.com/connect/token",
      "userinfo_endpoint": "https://iddev02.carexm.com/connect/userinfo"
    }
  },

为了完整起见,这里是我的 callback.html 和 silent-redirect.html 页面。这两个文件与您的 config.json 和 oidc-client-ts.min.js 文件一起放置在顶级公共文件夹中。

回调.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Waiting...</title>
</head>
<body>
    <script src="oidc-client-ts.min.js"></script>
    <script>

        var config = fetch("config.json", {'method': "GET"})
        .then(config =>
        {
            config.json().then(settings => {
                var mgr = new oidc.UserManager(settings['SSO_SETTINGS']);
                mgr.settings.userStore = new oidc.WebStorageStateStore({ store: window.localStorage });
                mgr.signinRedirectCallback()
                .then(() =>
                { 
                    window.location.href = sessionStorage.getItem("redirectedUri") ?? "../";
                })
            })
        });

    </script>
</body>
</html>

静默更新.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Waiting...</title>
</head>
<body>
    <script src="oidc-client-ts.min.js"></script>
    <script>

        var config = fetch("config.json", {'method': "GET"})
        .then(config =>
        {
            config.json().then(settings => {
                var mgr = new oidc.UserManager(settings['SSO_SETTINGS']).signinSilentCallback();
            })
        });

    </script>
</body>
</html>

【讨论】:

    猜你喜欢
    • 2017-07-19
    • 2019-04-30
    • 1970-01-01
    • 2016-04-15
    • 2019-09-15
    • 1970-01-01
    • 2019-10-07
    • 2015-11-02
    • 2010-11-08
    相关资源
    最近更新 更多