使用 MSAL v0.1.3 和 Aurelia 进行身份验证

Using MSAL v0.1.3 with Aurelia for Authentication

我找到了各种使用 MSAL 的示例,甚至找到了将 MSAL 与 SPA 应用程序(通常是 Angular 或 React)一起使用的示例,但我正在努力让它与 Aurelia 一起使用。

我执行了以下操作以确保该库确实按预期工作。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Test Page</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://secure.aadcdn.microsoftonline-p.com/lib/0.1.3/js/msal.min.js"></script>
    <style>
        .hidden {
            visibility: hidden;
        }
    </style>
  </head>
  <body>
      <div id="username"></div>
      <div id="token"></div>
      <button id="login" onclick="loginPopup()">Log In</button>
      <button id="logout" class="hidden">Log Out</button>
    <script>
        var authClient = new Msal.UserAgentApplication("my v2 endpoint client id",null);

       function loginPopup(){
           authClient.loginPopup(["openid","user.readbasic.all"])
           .then(token => {
               authClient.acquireTokenSilent(["user.readbasic.all"])
               .then(accessToken => {
                updateUI(token);
            },
            error => {
                authClient.acquireTokenPopup(["user.readbasic.all"])
                .then(accessToken => {
                    updateUI(token);
                },
                error => {
                    console.log("Token Error: " + error)
                })
            })

        },
        error =>{
            console.log("Login error " + error)
        })
    }

    function updateUI(token){
        var loginbutton = document.getElementById("login");
        loginbutton.className = "hidden";

        let usernamediv = document.getElementById("username");
        let tokendiv = document.getElementById("token");

        usernamediv.innerText = authClient.getUser().name;
        tokendiv.innerText = token;
    }
   </script>
  </body>
</html>

该代码效果很好。您单击“登录”按钮,显示“登录”弹出窗口,您 select 用户,输入您的密码,弹出窗口消失,UI 使用用户名和令牌适当更新。

现在我正尝试将其添加到我的 Aurelia 应用程序中,如下所示:

main.js

export async function configure(aurelia){
   aurelia.use
    .standardConfiguration()
    .developmentLogging();

   let msClient = new Msal.UserAgentApplication('my v2 endpoint client id",null);
   aurelia.use.instance("AuthService",msClient);

   await aurelia.start();

   if(msClient.getUser()) {
        await aurelia.setRoot(PLATFORM.moduleName("app"));
   else
        await aurelia.setRoot(PLATFORM.moduleName("login/login"));

login.js

export class Login {
   static inject = [Aurelia, "AuthService"]
   constructor(aurelia, auth){
        this.authService = auth
        this.app = aurelia
   }

   activate(){
        //Also tried this code in constructor
        this.authService.loginPopup(["openid","user.readbasic.all"])
         .then(token => {
             this.app.setRoot(PLATFORM.moduleName("app"))
         });
   }  
}

但是,使用此代码后,应用程序会加载并导航到弹出登录弹出窗口的登录页面。但是,一旦输入用户 enters/selects 名称和密码,弹出屏幕就不会消失。该应用程序(在弹出窗口后面)似乎重新加载并导航到 app.js 视图模型,但弹出窗口仍在屏幕上并且似乎要求用户输入 enter/select 用户名。

我也尝试过使用 loginRedirect 而不是 loginPopup,结果相似,因为即使在验证之后,应用程序也会不断地重定向到登录页面。

我猜这与 MSAL 尝试响应应用程序的方式以及 Aurelia 尝试处理导航的方式等有关,但我无法弄清楚哪里出了问题。

如有任何帮助,我们将不胜感激!

使用 attached() 生命周期回调

似乎一切正常,但弹出窗口并没有消失。如果没有看到实际的代码,很难知道为什么,但是您首先要尝试的是将相关代码移动到 attached() 回调,一旦视图和视图模型被绑定和添加,它就会被调用到 DOM.

不要returnactivate()

中的登录承诺

如果您 return 在 activate() 中输入了登录承诺,则在承诺完成之前激活不会完成。但是,app.setRoot() 在 promise 解析时也会被调用,这意味着您将在第一个导航完成之前开始一个新的导航。这很糟糕。

activate() {
  // THIS WOULD BREAK
  return this.authService.loginPopup(["openid","user.readbasic.all"])
    .then(token => {
      this.app.setRoot(PLATFORM.moduleName("app"))
    });
}

使用 detatched() 生命周期回调

如果这不起作用,下一步是检查 authService.loginPopup() 是否正确登录和解析。如果是这样,您始终可以继续并从 DOM 中手动删除弹出窗口,以防库未自行清理。您应该执行此 detatched() 生命周期回调。