ASP.NET Web API 和 OpenID Connect:如何从授权码中获取访问令牌
Posted
技术标签:
【中文标题】ASP.NET Web API 和 OpenID Connect:如何从授权码中获取访问令牌【英文标题】:ASP.NET Web API and OpenID Connect: how to get Access Token from Authorization Code 【发布时间】:2014-10-05 17:32:26 【问题描述】:我试图让 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 组件。
【问题讨论】:
我不清楚你想要完成什么。您是在询问 Web API 的 OWIN 中间件吗?还是某个调用 API 的客户端应用? 好的,我刚刚更新了我的问题。 【参考方案1】:看起来推荐的方法是使用AuthorizationCodeReceived
事件将身份验证代码交换为访问令牌。 Vittorio has a blog entry 概述了整个流程。
这是一个来自this sample app on 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 才能强制执行此事件。
【讨论】:
谢谢,有道理。但是,在我的情况下,AuthorizationCodeReceived 永远不会触发......我想我必须以某种方式将授权码从 SPA 传递到网络服务......【参考方案2】: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 未过期并存储在会话中。
你需要做的是调用AcquireTokenByAuthorizationCodeAsync
,它将缓存它并在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
非常快。
【讨论】:
如果调用AcquireTokenSilentAsync
时抛出异常二重奏authorizationCode
已过期。接下来具体做什么?获取新的授权码?在我的应用程序中,当它发生时,我使用了AcquireToken
,它返回了一个错误令牌
@HiepLam,您需要先调用 AcquireTokenByAuthorizationCodeAsync(),如示例所示。调用 AcquireTokenSilentAsync() 是为了在请求处理期间进行进一步调用,因此您不存储“授权代码”。但是,也有可能是您没有对该资源的权限,因此例外。
但是它需要通过验证然后认证服务器发回authorization code
对(OnOpenIdAuthorizationCodeReceived
OWIN 管道上的事件)?那么,当代码过期时,我如何获得另一个 authorization code
?
@HiepLam,您不必存储authorization code
。调用 AcquireTokenByAuthorizationCodeAsync() 会将其放入内部缓存中,进一步调用 AcquireTokenSilentAsync() 在内部使用此缓存(因此您不必自己存储它)。
我理解你的想法。第一次,我在AuthorizationCodeReceived
事件中打电话给AcquireTokenByAuthorizationCodeAsync
,一切正常。一段时间后,authorization code
过期,调用AcquireTokenSilentAsync
时抛出异常。所以当时我想知道如何获得一个新的authorization code
。或者有其他方法可以解决这个问题吗?【参考方案3】:
你需要绕过默认的owin验证来做自定义授权:
new OpenIdConnectAuthenticationOptions
...,
TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
ValidateIssuer = false
,
【讨论】:
【参考方案4】:TokenValidationParameters = new TokenValidationParameters NameClaimType = "name", RoleClaimType = ClaimTypes.Role ,
这行代码解决了我的问题。我们需要验证颁发者是否为假。
【讨论】:
以上是关于ASP.NET Web API 和 OpenID Connect:如何从授权码中获取访问令牌的主要内容,如果未能解决你的问题,请参考以下文章
Asp.Net Core API OpenId-Connect 身份验证与 JWT 令牌使用 IdentityModel
如何通过 IdentityServer4 将 OpenId Connect 添加到 ASP.NET Core 服务器端 Blazor Web 应用程序?
Asp.Net Web API 2第六课——Web API路由和动作选择