我正在开发一个使用AD B2C作为OpenID Connect Provider的云应用程序。
在我的配置环境下面:
AD B2C
在我的AD B2C中,我创建了两个应用程序:
API网关
我创建了一个API Management。在API导入之后,我添加了一个如下的策略:
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
<openid-config url="https://login.microsoftonline.com/{myTenantAzureId}/.well-known/openid-configuration?p={myPolicies}" />
</validate-jwt>
MyClient
我的客户端是Angular 4应用程序。我正在使用MSAL.js Microsoft官方库。
这是我的授权服务TypeScript类:
import { Injectable } from '@angular/core';
declare var bootbox: any;
declare var Msal: any;
@Injectable()
export class MsalService {
public access_token: string;
private logger = new Msal.Logger(this.loggerCallback, { level: Msal.LogLevel.Verbose });
tenantConfig = {
tenant: "{myTenant}.onmicrosoft.com",
clientID: '{MyClientClientId}',
signUpSignInPolicy: "{myPolicies}",
b2cScopes: ["openid"]
};
options = {
logger: this.logger,
postLogoutRedirectUri: window.location.protocol + "//" + window.location.host
}
//authority = null;
authority = "https://login.microsoftonline.com/tfp/" + this.tenantConfig.tenant + "/" + this.tenantConfig.signUpSignInPolicy;
clientApplication = new Msal.UserAgentApplication(
this.tenantConfig.clientID,
this.authority,
this.authCallback,
this.options
);
public login(callback: Function): void {
var _this = this;
this.clientApplication.loginPopup(this.tenantConfig.b2cScopes).then(function (idToken: any) {
_this.clientApplication.acquireTokenSilent(_this.tenantConfig.b2cScopes).then(
function (accessToken: any) {
_this.access_token = accessToken;
localStorage.setItem("access_token", accessToken);
if (callback) {
callback(accessToken);
}
}, function (error: any) {
_this.clientApplication.acquireTokenPopup(_this.tenantConfig.b2cScopes).then(
function (accessToken: any) {
_this.access_token = accessToken;
console.log(accessToken);
}, function (error: any) {
bootbox.alert("Error acquiring the popup:\n" + error);
});
})
}, function (error: any) {
console.log(error);
bootbox.alert("Error during login:\n" + error);
});
}
public logout(callback: Function): void {
this.clientApplication.logout();
if (callback) {
callback();
}
}
private loggerCallback(logLevel, message, piiLoggingEnabled) {
console.log(message);
}
private authCallback(errorDesc: any, token: any, error: any, tokenType: any) {
if (token) {
}
else {
console.error(error + ":" + errorDesc);
}
}
}
问题
如果我尝试使用带有访问令牌的Authorization标头调用一个API Management的API,我会收到此错误:
{ "statusCode": 401, "message": "Unauthorized. Access token is missing or invalid." }
但如果我尝试直接通过Developer Portal访问,我可以成功调用相同的API。
为什么我的API管理员没有授权我的申请?
非常感谢
答案 0 :(得分:1)
我认为上述错误正在发生,因为API网关无法识别从Angular客户端传递的访问令牌的aud
(受众)声明。
上述方案类似于"Azure AD B2C: Call a .NET web API from a .NET web app",其中Angular客户端是Web应用程序,API网关是Web API。
我建议你:
1)代表API网关的Create an Azure AD B2C app。输入此应用的应用ID ID以标识API网关。
2)Add one or more permission scopes到此网关应用和/或保留user_impersonation
的默认权限范围。
3)代表Angular客户端的Create an Azure AD B2C app。您已经创建了此客户端应用程序。
4)Grant access by the client app to the gateway app以便客户端应用可以获取访问令牌以代表已登录的用户来呼叫网关应用。
5)Update the validate-jwt
policy,其中包含网关应用的应用ID。
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
<openid-config url="https://login.microsoftonline.com/tfp/{tenant}/{policy}/v2.0/.well-known/openid-configuration" />
<audiences>
<audience><!-- Paste the app ID for the gateway app --></audience>
</audiences>
</validate-jwt>
6)包括在步骤2中添加的任何权限范围,以发布到tenantConfig.b2cScopes
数组的客户端应用程序。
答案 1 :(得分:0)
基于
{“statusCode”:401,“message”:“未经授权。访问令牌丢失或无效。” }
在发出http请求时,您似乎没有从Angular应用程序发送令牌。在Angular中执行此操作的一种方法是使用interceptor。
@Injectable()
export class AuthenticationHttpInterceptor implements HttpInterceptor {
constructor(private authenticationService: AuthenticationService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return Observable.fromPromise(this.authenticationService.getAuthenticationToken())
.switchMap(token => {
req = req.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
return next.handle(req);
});
}
}