简体   繁体   English

向Angular 4 SPA请求Web API时,范围声明为空

[英]Scope claim is null when requesting web api from Angular 4 SPA

I am trying to protect my web api using Azure B2C AD and consume the web api using an Angular 4 SPA. 我正在尝试使用Azure B2C AD保护我的Web api,并使用Angular 4 SPA使用该Web api。 However, for some reason the scope claim is always null even though other claims are working just fine. 但是,由于某些原因,即使其他声明工作得很好,范围声明也始终为空。

I am using the MSAL library version 0.1.6 in the Angular app and have been following this guide: https://github.com/Azure-Samples/active-directory-b2c-javascript-angular2.4-spa 我在Angular应用中使用的MSAL库版本为0.1.6,并且一直在遵循此指南: https : //github.com/Azure-Samples/active-directory-b2c-javascript-angular2.4-spa

This is my web api startup.auth: 这是我的网络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))),

        });
    }
}

This is my controller: 这是我的控制器:

[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"};
    }
}

The owner variable contains a GUID as expected, however the scopes variable is always NULL. owner变量包含预期的GUID,但是scope变量始终为NULL。

This is my auth.service.ts: 这是我的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; 

    }
}

Finally, this is my environment values: 最后,这是我的环境价值观:

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"]
};

Here is pictures of the Azure setup: 这是Azure安装程序的图片:

API properties: API属性: API属性

API published scopes: API发布范围: API发布范围

Client API access: 客户端API访问: 客户端API访问

Why is the value of the scopes variable NULL? 为什么范围变量的值为NULL? What did I miss? 我错过了什么? The owner variable contains a value! owner变量包含一个值!

Best regards 最好的祝福

Try running fiddler to see what is going on. 尝试运行提琴手,看看发生了什么。

  1. You may need to define Users and Roles to accomplish this. 您可能需要定义用户和角色来完成此任务。 See this guide . 请参阅本指南
  2. One of your config settings may not match what you have in your app registration. 您的一种配置设置可能与您的应用注册中的设置不匹配。 Ensure that the ClientID/AppID matches in all instances. 确保在所有实例中ClientID / AppID都匹配。
  3. Make sure that the reply urls in your code match what you have in the app registration. 确保您代码中的回复网址与您在应用程序注册中的网址匹配。

Please see if this issue is relevant to you. 请查看此问题是否与您有关。

Solved it by using a different client library: https://github.com/damienbod/angular-auth-oidc-client 通过使用其他客户端库解决了它: https : //github.com/damienbod/angular-auth-oidc-client

In case anyone posts a solution, using the MSAL library, I will ofcourse mark it as the solution 万一有人使用MSAL库发布解决方案,我当然会将其标记为解决方案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Web API facebook,电子邮件声明返回null - Web API facebook, email claim returns null 从Angular发布到Web API时,字符串是否为null? - string is null when posting from Angular to Web API? Azure B2C Authentication (angular + .net core Web API) - Neither scope or roles claim was found in the bearer token - Azure B2C Authentication (angular + .net core Web API) - Neither scope or roles claim was found in the bearer token Azure AD - 在 C# Web API 中使用来自 Angular SPA 的图 API 访问令牌 - Azure AD - Using Graph API access token from Angular SPA in C# Web API Web API 从 angular 获取 NULL 值为“NULL”? - Web API is getting NULL value as "NULL" from angular? .NET Core 3.0 Web API 连接问题上的 Angular SPA - Angular SPA on .NET Core 3.0 Web API Connection issues 基本 Angular SPA 与 .NET Web ZDB974238714CA8DE634A7CE1SSOD083A14FZ 连接 - 实现 - Basic Angular SPA connected with .NET Web API - implement SSO 使用.NET web api路由使用Angular SPA投掷404 - Getting .NET web api route to work with Angular SPA throwing 404 从Xamarin Forms请求Web API中的JWT时收到错误请求 - Getting Bad Request when requesting JWT in web API from Xamarin Forms IDW10201:在不记名令牌中找不到 scope 或角色声明。 定制web api芯 - IDW10201: Neither scope or roles claim was found in the bearer token. custom web api core
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM