从 Angular 4 SPA 请求 Web api 时,范围声明为空
Posted
技术标签:
【中文标题】从 Angular 4 SPA 请求 Web api 时,范围声明为空【英文标题】:Scope claim is null when requesting web api from Angular 4 SPA 【发布时间】:2018-12-10 17:39:27 【问题描述】:我正在尝试使用 Azure B2C AD 保护我的 web api,并使用 Angular 4 SPA 使用 web api。但是,出于某种原因,即使其他声明运行良好,范围声明也始终为空。
我在 Angular 应用程序中使用 MSAL 库版本 0.1.6 并一直遵循本指南:https://github.com/Azure-Samples/active-directory-b2c-javascript-angular2.4-spa
这是我的 web api startup.auth:
public partial class Startup
// These values are pulled from web.config
public static string AadInstance = ConfigurationManager.AppSettings["ida:AadInstance"];
public static string Tenant = ConfigurationManager.AppSettings["ida:Tenant"];
public static string ClientId = ConfigurationManager.AppSettings["ida:ClientId"];
public static string SignUpSignInPolicy = ConfigurationManager.AppSettings["ida:SignUpSignInPolicyId"];
public static string DefaultPolicy = SignUpSignInPolicy;
/*
* Configure the authorization OWIN middleware.
*/
public void ConfigureAuth(IAppBuilder app)
TokenValidationParameters tvps = new TokenValidationParameters
// Accept only those tokens where the audience of the token is equal to the client ID of this app
ValidAudience = ClientId,
AuthenticationType = Startup.DefaultPolicy
;
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
// This SecurityTokenProvider fetches the Azure AD B2C metadata & signing keys from the OpenIDConnect metadata endpoint
AccessTokenFormat = new JwtFormat(tvps, new OpenIdConnectCachingSecurityTokenProvider(String.Format(AadInstance, Tenant, DefaultPolicy))),
);
这是我的控制器:
[Authorize]
[EnableCors(origins: "*", headers: "*", methods: "*")] // tune to your needs
public class ValuesController : ApiController
// GET api/values
public IEnumerable<string> Get()
string owner = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
var scopes = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/scope");
return new string[] "value1", "value2";
所有者变量包含预期的 GUID,但范围变量始终为 NULL。
这是我的 auth.service.ts:
import Injectable from '@angular/core';
import environment from '../../../environments/environment';
import * as Msal from 'msal'
declare var bootbox: any;
// declare var Msal:any;
const B2CTodoAccessTokenKey = "b2c.api.access.token";
const tenantConfig =
tenant: environment.b2cTenant,
clientID: environment.b2cClientID,
signUpSignInPolicy: environment.b2cSignUpSignInPolicy,
b2cScopes: environment.b2cScopes
;
@Injectable()
export class AuthService
// Configure the authority for Azure AD B2C
private authority = "https://login.microsoftonline.com/tfp/" + tenantConfig.tenant + "/" + tenantConfig.signUpSignInPolicy;
private loggerCallback(logLevel, message, piiLoggingEnabled)
console.log(message);
private logger = new Msal.Logger(this.loggerCallback, level: Msal.LogLevel.Verbose );
clientApplication = new Msal.UserAgentApplication(
tenantConfig.clientID,
this.authority,
function(errorDesc: any, token: any, error: any, tokenType: any)
console.log('calling acquireTokenSilent with scopes: ' + tenantConfig.b2cScopes);
console.log('idtoken: ' + token)
if (token)
this.acquireTokenSilent(tenantConfig.b2cScopes).then(function (accessToken)
// Change button to Sign Out
console.log('acquireTokenSilent');
sessionStorage.setItem("b2c.api.access.token", accessToken);
, function (error)
console.log(error);
this.acquireTokenPopup(tenantConfig.b2cScopes).then(function (accessToken)
console.log('acquireTokenPopup');
sessionStorage.setItem("b2c.api.access.token", accessToken);
, function (error)
console.log(error);
);
);
else if (errorDesc || error)
console.log(error + ':' + errorDesc);
,
logger: this.logger,
);
loginRedirect(): void
console.log('scopes: ' + tenantConfig.b2cScopes);
this.clientApplication.loginRedirect(tenantConfig.b2cScopes);
login() : void
var _this = this;
this.clientApplication.loginPopup(tenantConfig.b2cScopes).then(function (idToken: any)
_this.clientApplication.acquireTokenSilent(tenantConfig.b2cScopes).then(
function (accessToken: any)
_this.saveAccessTokenToCache(accessToken);
, function (error: any)
_this.clientApplication.acquireTokenPopup(tenantConfig.b2cScopes).then(
function (accessToken: any)
_this.saveAccessTokenToCache(accessToken);
, function (error: any)
//bootbox.alert("Error acquiring the popup:\n" + error);
console.log("Error acquiring the popup:\n" + error)
);
)
, function (error: any)
//bootbox.alert("Error during login:\n" + error);
console.log("Error during login:\n" + error);
);
getTokenFromCache() : string
return sessionStorage.getItem(B2CTodoAccessTokenKey);
saveAccessTokenToCache(accessToken: string): void
sessionStorage.setItem(B2CTodoAccessTokenKey, accessToken);
logout(): void
this.clientApplication.logout();
isLoggedIn(): boolean
var user = this.clientApplication.getUser();
console.log('isLogged In: ' + (user != null));
console.log('token in cache ' + (this.getTokenFromCache() != null))
//console.log('token: ' + this.getTokenFromCache());
return this.clientApplication.getUser() != null && this.getTokenFromCache() != null;
最后,这是我的环境值:
export default
b2cTenant: "[tenant].onmicrosoft.com",
b2cClientID: '[app-id]',
b2cSignUpSignInPolicy: "[policy]",
b2cScopes: ["https://[tenant].onmicrosoft.com/apidemo/read", "https://[tenant].onmicrosoft.com/apidemo/user_impersonation"]
;
这是 Azure 设置的图片:
API 属性:
API 发布范围:
客户端 API 访问:
为什么作用域变量的值为NULL?我错过了什么? 所有者变量包含一个值!
最好的问候
【问题讨论】:
在 Azure AD B2C 门户中,您是否使用 API 访问 刀片(请参阅 docs.microsoft.com/en-us/azure/active-directory-b2c/…)授予 Web 应用访问 Web API 的权限? 我不确定我是否正确 - 我将使用当前设置的屏幕截图更新 psot 我会先从门户开始,从图片中删除你的应用代码:***.com/a/49307987/185123 您能否从填写了范围声明的门户获取访问令牌?如果不是,那么 B2C 配置似乎是错误的。如果是,您的应用代码似乎有误。 感谢您的回复。我按照你的建议做了,现在我可以获得访问令牌,但是当我调用 API 时没有填写范围声明。那我在portal里的B2C配置错了? 【参考方案1】:尝试运行 fiddler 看看发生了什么。
-
您可能需要定义用户和角色来完成此操作。见this guide。
您的某个配置设置可能与您在应用注册中的设置不匹配。确保 ClientID/AppID 在所有实例中都匹配。
确保您的代码中的回复网址与您在应用注册中的网址匹配。
请查看this issue 是否与您相关。
【讨论】:
谢谢。问题不在于访问令牌为空,而在于范围声明为空。关于选项 2 + 3,我确认它们在所有实例(.NET 应用程序、SPA、Azure 门户)中都匹配。关于选项 1,我不确定您指的是哪个部分,因为它们在这里似乎都没有真正相关 - 或者我错过了什么?【参考方案2】:使用不同的客户端库解决了这个问题:https://github.com/damienbod/angular-auth-oidc-client
如果有人使用 MSAL 库发布解决方案,我当然会将其标记为解决方案
【讨论】:
以上是关于从 Angular 4 SPA 请求 Web api 时,范围声明为空的主要内容,如果未能解决你的问题,请参考以下文章
Web API系列教材1.3 — 实战:用ASP.NET Web API和Angular.js创建单页面应用程序(上)