ASP.NET Web API and OpenID Connect: how to get Access Token from Authorization Code

混江龙づ霸主 提交于 2019-12-02 23:22:09

BenV already answered the question, but there's more to consider.

class partial Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        // ...

        app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
          {
            ClientId = clientId,
            Authority = authority,
            Notifications = new OpenIdConnectAuthenticationNotifications() {
                AuthorizationCodeReceived = (context) => {
                   string authorizationCode = context.Code;
                   // (tricky) the authorizationCode is available here to use, but...
                   return Task.FromResult(0);
                }
            }
          }
    }
}

Two problems:

  • First of all, authorizationCode will get expired quickly. There's no sense in storing it.
  • The second problem is that AuthorizationCodeReceived event will not get fired for any of the page reloads as long as authorizationCode is not expired and stored inside the session.

What you need to do is to call AcquireTokenByAuthorizationCodeAsync which will cache it and handle properly inside TokenCache.DefaultShare:

AuthorizationCodeReceived = (context) => {
    string authorizationCode = context.Code;
    AuthenticationResult tokenResult = await context.AcquireTokenByAuthorizationCodeAsync(authorizationCode, new Uri(redirectUri), credential);
    return Task.FromResult(0);
}

Now, before every call to the resource, invoke AcquireTokenSilentAsync to get the accessToken (it will use TokenCache or silently use refreshToken ). If token is expired, it will raise AdalSilentTokenAcquisitionException exception (invoke access code renew procedure).

// currentUser for ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier")
AuthenticationResult authResult = await context.AcquireTokenSilentAsync(resourceUri, credential, currentUser);

Calling AcquireTokenSilentAsync is very fast if token is cached.

Looks like the recommended approach is to use the AuthorizationCodeReceived event to exchange the Auth code for an Access Token. Vittorio has a blog entry that outlines the overall flow.

Here's an example from this sample app on GitHub of the Startup.Auth.cs code to set this up:

app.UseOpenIdConnectAuthentication(
    new OpenIdConnectAuthenticationOptions
    {
        ClientId = clientId,
        Authority = Authority,
        Notifications = new OpenIdConnectAuthenticationNotifications()
        {
            AuthorizationCodeReceived = (context) =>
           {
               var code = context.Code;
               ClientCredential credential = new ClientCredential(clientId, appKey);
               string tenantID = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
               string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
               AuthenticationContext authContext = new AuthenticationContext(string.Format("https://login.windows.net/{0}", tenantID), new EFADALTokenCache(signedInUserID));
               AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(
                           code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, graphResourceID);

               return Task.FromResult(0);
            },
            ...
    }

Note: The AuthorizationCodeReceived event is invoked only once when authorization really takes place. If the auth code is already generated and stored, this event is not invoked. You have to logout or clear cookies to force this event to take place.

You need to bypass the default owin validation to do custom Authorization:

           new OpenIdConnectAuthenticationOptions
            {
                ...,
                TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
                {
                    ValidateIssuer = false
                },
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!