Extend MSAL to support multiple Web APIs

2019-08-11 09:48发布

问题:

Hi I started with the sample here

https://github.com/Azure-Samples/active-directory-b2c-dotnet-webapp-and-webapi

And manqaged to get the TaskWebApp talking to the TaskService.

I now want to extend the solution to have a 3rd service

Im not sure if the problem is within the ConfidentialClientApplication as when it fails to get my tokens i get no exception.

I think the issue is the COnfigureApp method in my TaskWebApp is only expecting to manage tokens from the single TokenService.

Here is my web App Starttup.Auth ConfigureAuth method, this is unchanged from the sample app

 public void ConfigureAuth(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions());
        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

        app.UseOpenIdConnectAuthentication(
            new OpenIdConnectAuthenticationOptions
            {
                // Generate the metadata address using the tenant and policy information
                MetadataAddress = String.Format(AadInstance, Tenant, DefaultPolicy),

                // These are standard OpenID Connect parameters, with values pulled from web.config
                ClientId = ClientId,
                RedirectUri = RedirectUri,
                PostLogoutRedirectUri = RedirectUri,

                // Specify the callbacks for each type of notifications
                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    RedirectToIdentityProvider = OnRedirectToIdentityProvider,
                    AuthorizationCodeReceived = OnAuthorizationCodeReceived,
                    AuthenticationFailed = OnAuthenticationFailed,
                },

                // Specify the claims to validate
                TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType = "name"
                },

                // Specify the scope by appending all of the scopes requested into one string (seperated by a blank space)
                Scope = $"{OpenIdConnectScopes.OpenId} {ReadTasksScope} {WriteTasksScope}"
            }
        );
    }

Here is my OnAuthorizationCodeReceived method, again unchanged

 private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification notification)
    {
        // Extract the code from the response notification
        var code = notification.Code;

        var userObjectId = notification.AuthenticationTicket.Identity.FindFirst(ObjectIdElement).Value;
        var authority = String.Format(
                            AadInstance, 
                            Tenant, 
                            DefaultPolicy);
        var httpContext = notification.OwinContext.Environment["System.Web.HttpContextBase"] as HttpContextBase;

        // Exchange the code for a token. Make sure to specify the necessary scopes
        ClientCredential cred = new ClientCredential(ClientSecret);
        ConfidentialClientApplication app = new ConfidentialClientApplication(
                                            authority, 
                                            Startup.ClientId,
                                            RedirectUri, 
                                            cred, 
                                            new NaiveSessionCache(userObjectId, httpContext));

        var authResult = await app.AcquireTokenByAuthorizationCodeAsync(new string[]
        {
            ReadTasksScope,
            WriteTasksScope
        }, 
        code, 
        DefaultPolicy);



    }

The problem seems to be that my Readand write scope are referencing the TaskService directly and when i try to ask for appropriate scopes from other apps it complains.

in my controller

    private async Task<String> acquireToken(String[] scope)
    {

        try
        {
            string userObjectID = ClaimsPrincipal.Current.FindFirst(Startup.ObjectIdElement).Value;
            string authority = String.Format(Startup.AadInstance, Startup.Tenant, Startup.DefaultPolicy);

            ClientCredential credential = new ClientCredential(Startup.ClientSecret);

            // Retrieve the token using the provided scopes
            ConfidentialClientApplication app = new ConfidentialClientApplication(authority, Startup.ClientId,
                Startup.RedirectUri, credential,
                new NaiveSessionCache(userObjectID, this.HttpContext));

            AuthenticationResult result = await app.AcquireTokenSilentAsync(scope);

            return result.Token;
        }
        catch (Exception e)
        {
            Debug.WriteLine(e.Message);
            throw e;
        }

This method is used but My AuthorisationResult fails with the message couldnt get token silently with no inner exception.

So far I have tried removing the NaiveSessionCache as its optional and it still fails

To get past this I have registered a 4th service and then made my webapis use that single client id and secret to control access to their resources but this feels like it is not the correct way forward.

Any help would be great thanks