登录使用 Azure AD B2C 从 Angular 应用程序和 msal.js 重定向用户
Login redirect a user with Azure AD B2C from an Angular application and msal.js
我正在尝试让 Angular 4 应用正确地使用 Azure AD B2C 进行隐式身份验证。我正在使用 msal.js 来尝试让它工作。我检查了非常有限的 official sample code,但它没有实际用处,因为它使用弹出窗口登录,我想进行重定向。
我现在拥有的是我在我的应用程序中注入的以下身份验证服务,它应该负责所有身份验证。
import { Injectable } from '@angular/core';
import * as Msal from 'msal';
@Injectable()
export class AuthenticationService {
private tenantConfig = {
tenant: "example.onmicrosoft.com",
clientID: "redacted (guid of the client)",
signUpSignInPolicy: "b2c_1_signup",
b2cScopes: ["https://example.onmicrosoft.com/demo/read", "openid"]
}
private authority = "https://login.microsoftonline.com/tfp/" + this.tenantConfig.tenant + "/" + this.tenantConfig.signUpSignInPolicy;
private clientApplication: Msal.UserAgentApplication;
constructor() {
this.clientApplication = new Msal.UserAgentApplication(this.tenantConfig.clientID, this.authority, this.authCallback);
}
public login(): void {
this.clientApplication.loginRedirect(this.tenantConfig.b2cScopes);
}
public logout(): void {
this.clientApplication.logout();
}
public isOnline(): boolean {
return this.clientApplication.getUser() != null;
}
public getUser(): Msal.User {
return this.clientApplication.getUser();
}
public getAuthenticationToken(): Promise<string> {
return this.clientApplication.acquireTokenSilent(this.tenantConfig.b2cScopes)
.then(token => {
console.log("Got silent access token: ", token);
return token;
}).catch(error => {
console.log("Could not silently retrieve token from storage.", error);
return this.clientApplication.acquireTokenPopup(this.tenantConfig.b2cScopes)
.then(token => {
console.log("Got popup access token: ", token);
return token;
}).catch(error => {
console.log("Could not retrieve token from popup.", error);
this.clientApplication.acquireTokenRedirect(this.tenantConfig.b2cScopes);
return Promise.resolve("");
});
});
}
private authCallback(errorDesc: any, token: any, error: any, tokenType: any) {
console.log("Callback")
if (token) {
console.log("Id token", token);
}
else {
console.log(error + ":" + errorDesc);
}
this.getAuthenticationToken();
}
}
但它不起作用。我正确地获得了 ID 令牌,它是有效的,所以“Id 令牌”确实收到了一个我可以使用的值,但时间有限。
问题出在我尝试获取身份验证令牌时。第一次调用 acquireTokenSilent
returns 一个错误:Token renewal operation failed due to timeout: null
.
然后,我收到一个弹出窗口,要求输入用户名和密码,过了一会儿,它消失了,我收到一条错误消息,显示 User does not have an existing session and request prompt parameter has a value of 'None'.
。
编辑:
所以,我想我完全了解发生了什么,并在您可以在此处获得的示例应用程序上重现该问题:https://github.com/Gimly/NetCoreAngularAzureB2CMsal
如果您从主页连接然后转到 fetchData 页面(带有天气预报的页面),您可以看到 acquireTokenSilent
正确兑换了身份验证令牌(打开浏览器控制台以获取所有日志)。但是,如果您直接在 fetchData 上刷新页面,您会看到与我描述的相同的行为,acquireTokenSilent
失败并出现超时错误。
我最好的猜测是,出于某种原因,即使 getUser
returns 是一个正确的值,在我调用 getAuthenticationToken
之前 msal 没有完全初始化,这就是它完全失败。
现在真正的问题是......在尝试获取令牌之前如何确保它已完全初始化?
查看 MSAL js 的 source code,您应该能够使用 acquireTokenRedirect 而不是 acquireTokenPopup。
好的,我遇到的问题是由两件事引起的:
1) msal.js 中的一个错误导致初始化过程在构造函数调用结束时未完全完成,而我在 acquireTokenSilent()
完全初始化之前就调用了它。这已在最新版本中修复(截至撰写本文时,仍在项目的开发分支中)。 See this GitHub issue for more info.
2) 我没有修复重定向 URI,这导致库将当前 URL 作为重定向 URI,这将失败,因为它不在允许的重定向 URI 列表中。
这两个问题解决后,我在问题中发布的代码按预期工作。
我正在尝试让 Angular 4 应用正确地使用 Azure AD B2C 进行隐式身份验证。我正在使用 msal.js 来尝试让它工作。我检查了非常有限的 official sample code,但它没有实际用处,因为它使用弹出窗口登录,我想进行重定向。
我现在拥有的是我在我的应用程序中注入的以下身份验证服务,它应该负责所有身份验证。
import { Injectable } from '@angular/core';
import * as Msal from 'msal';
@Injectable()
export class AuthenticationService {
private tenantConfig = {
tenant: "example.onmicrosoft.com",
clientID: "redacted (guid of the client)",
signUpSignInPolicy: "b2c_1_signup",
b2cScopes: ["https://example.onmicrosoft.com/demo/read", "openid"]
}
private authority = "https://login.microsoftonline.com/tfp/" + this.tenantConfig.tenant + "/" + this.tenantConfig.signUpSignInPolicy;
private clientApplication: Msal.UserAgentApplication;
constructor() {
this.clientApplication = new Msal.UserAgentApplication(this.tenantConfig.clientID, this.authority, this.authCallback);
}
public login(): void {
this.clientApplication.loginRedirect(this.tenantConfig.b2cScopes);
}
public logout(): void {
this.clientApplication.logout();
}
public isOnline(): boolean {
return this.clientApplication.getUser() != null;
}
public getUser(): Msal.User {
return this.clientApplication.getUser();
}
public getAuthenticationToken(): Promise<string> {
return this.clientApplication.acquireTokenSilent(this.tenantConfig.b2cScopes)
.then(token => {
console.log("Got silent access token: ", token);
return token;
}).catch(error => {
console.log("Could not silently retrieve token from storage.", error);
return this.clientApplication.acquireTokenPopup(this.tenantConfig.b2cScopes)
.then(token => {
console.log("Got popup access token: ", token);
return token;
}).catch(error => {
console.log("Could not retrieve token from popup.", error);
this.clientApplication.acquireTokenRedirect(this.tenantConfig.b2cScopes);
return Promise.resolve("");
});
});
}
private authCallback(errorDesc: any, token: any, error: any, tokenType: any) {
console.log("Callback")
if (token) {
console.log("Id token", token);
}
else {
console.log(error + ":" + errorDesc);
}
this.getAuthenticationToken();
}
}
但它不起作用。我正确地获得了 ID 令牌,它是有效的,所以“Id 令牌”确实收到了一个我可以使用的值,但时间有限。
问题出在我尝试获取身份验证令牌时。第一次调用 acquireTokenSilent
returns 一个错误:Token renewal operation failed due to timeout: null
.
然后,我收到一个弹出窗口,要求输入用户名和密码,过了一会儿,它消失了,我收到一条错误消息,显示 User does not have an existing session and request prompt parameter has a value of 'None'.
。
编辑:
所以,我想我完全了解发生了什么,并在您可以在此处获得的示例应用程序上重现该问题:https://github.com/Gimly/NetCoreAngularAzureB2CMsal
如果您从主页连接然后转到 fetchData 页面(带有天气预报的页面),您可以看到 acquireTokenSilent
正确兑换了身份验证令牌(打开浏览器控制台以获取所有日志)。但是,如果您直接在 fetchData 上刷新页面,您会看到与我描述的相同的行为,acquireTokenSilent
失败并出现超时错误。
我最好的猜测是,出于某种原因,即使 getUser
returns 是一个正确的值,在我调用 getAuthenticationToken
之前 msal 没有完全初始化,这就是它完全失败。
现在真正的问题是......在尝试获取令牌之前如何确保它已完全初始化?
查看 MSAL js 的 source code,您应该能够使用 acquireTokenRedirect 而不是 acquireTokenPopup。
好的,我遇到的问题是由两件事引起的:
1) msal.js 中的一个错误导致初始化过程在构造函数调用结束时未完全完成,而我在 acquireTokenSilent()
完全初始化之前就调用了它。这已在最新版本中修复(截至撰写本文时,仍在项目的开发分支中)。 See this GitHub issue for more info.
2) 我没有修复重定向 URI,这导致库将当前 URL 作为重定向 URI,这将失败,因为它不在允许的重定向 URI 列表中。
这两个问题解决后,我在问题中发布的代码按预期工作。