17

我尝试让 OpenID Connect 运行...我的 Web API 用户设法获得了 OpenID Connect 提供者的授权码。我应该如何将此代码传递给我的 ASP.NET Web API?如何配置 OWIN 中间件,以便我可以使用授权码获取访问令牌?

更新:SPA 使用 AJAX 与我的 Web 服务(ASP.NET Web API)进行通信。在我的网络服务中使用 OWIN 中间件。我将 OpenIDConnect 设置为身份验证机制。第一次调用 Web 服务时,它成功地将用户重定向到 OpenID Connect Provider 的登录页面。结果,用户可以登录并获得授权码。AFAIK 现在可以(由我的 Web 服务)将此代码用于访问令牌。但是,我不知道如何将此代码返回到我的 Web 服务(这是使用标头完成的吗?),然后如何配置以获取访问令牌。我想我可以手动调用令牌端点,但我想利用 OWIN 组件。

4

4 回答 4

12

看起来推荐的方法是使用该AuthorizationCodeReceived事件将 Auth 代码交换为访问令牌。 Vittorio 有一个博客条目,概述了整个流程。

以下是GitHub 上此示例应用程序中用于Startup.Auth.cs设置此代码的示例:

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);
            },
            ...
    }

注意:AuthorizationCodeReceived事件仅在授权真正发生时调用一次。如果已经生成并存储了验证码,则不会调用此事件。您必须注销或清除 cookie 才能强制执行此事件。

于 2014-08-12T18:29:53.730 回答
12

BenV 已经回答了这个问题,但还有更多需要考虑。

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);
                }
            }
          }
    }
}

两个问题:

  • 首先,authorizationCode会很快过期。存储它没有任何意义。
  • 第二个问题是,AuthorizationCodeReceived只要 authenticationCode 没有过期并存储在会话中,任何页面重新加载都不会触发事件。

您需要做的是调用AcquireTokenByAuthorizationCodeAsyncwhich 将缓存它并在内部正确处理TokenCache.DefaultShare

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

现在,在每次调用资源之前,调用AcquireTokenSilentAsync以获取 accessToken(它将使用 TokenCache 或静默使用 refreshToken )。如果令牌过期,它将引发AdalSilentTokenAcquisitionException异常(调用访问代码更新程序)。

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

如果缓存了令牌,则调用AcquireTokenSilentAsync非常快。

于 2016-01-11T20:46:32.700 回答
1

您需要绕过默认的 owin 验证来执行自定义授权:

           new OpenIdConnectAuthenticationOptions
            {
                ...,
                TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
                {
                    ValidateIssuer = false
                },
于 2015-09-02T21:14:46.833 回答
0
TokenValidationParameters = new TokenValidationParameters { NameClaimType = "name", RoleClaimType = ClaimTypes.Role },

这行代码解决了我的问题。我们需要验证颁发者是否为假。

于 2021-03-31T11:05:49.877 回答