Hybrid Flow 和 implicit flow是OIDC(OpenID Connect)协议中的术语,Implicit Flow是指使用OAuth2的Implicit流程获取Id Token和Access Token;Hybrid Flow是指混合Authorization Code Flow(OAuth授权码流程)和Implici Flow。
在之前的文章,我们探索了API访问控制和身份认证。 现在我们要把这两个部分结合在一起。
OpenID Connect和OAuth 2.0组合的优点在于,您可以使用单一协议和令牌服务进行单一交换。
在前一篇文章中,我们使用了OpenID Connect implicit flow。 在implicit流程中,所有的令牌都通过浏览器传输,这对于身份令牌来说是完全不错的。 现在我们也想要一个访问令牌。访问令牌比身份令牌更加敏感,如果不需要,我们不想让它们暴露于“外部”世界。 OpenID Connect包含一个名为“混合流”的流程,它可以让我们两全其美,身份令牌通过浏览器通道传输,因此客户端可以在做更多的工作之前验证它。 如果验证成功,客户端会打开令牌服务的后端通道来检索访问令牌。
没有必要做太多的修改。 首先,我们希望允许客户端使用混合流,另外我们还希望客户端允许服务器到服务器API调用,这些调用不在用户的上下文中(这与我们的客户端证书quickstart非常相似)。 这是使用AllowedGrantTypes
属性表示的。
接下来我们需要添加一个客户机密钥。 这将用于反向检索通道上的访问令牌。
最后,我们还让客户端访问offline_access作用域 - 这允许为长时间的API访问请求刷新令牌:
- new Client
- {
- ClientId = "mvc",
- ClientName = "MVC Client",
- AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
-
- ClientSecrets =
- {
- new Secret("secret".Sha256())
- },
-
- RedirectUris = { "http://localhost:5002/signin-oidc" },
- PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
-
- AllowedScopes =
- {
- IdentityServerConstants.StandardScopes.OpenId,
- IdentityServerConstants.StandardScopes.Profile,
- "api1"
- },
- AllowOfflineAccess = true
- };
在MVC客户端的修改也是最小的 - ASP.NET Core OpenID Connect处理程序已经内置支持混合流程,所以我们只需要改变一些配置值。
我们配置ClientSecret密钥和IdentityServer上匹配。 添加offline_access
和api1
作用域,并将ResponseType
设置为代码id_token
(基本意思是“使用混合流”)
- .AddOpenIdConnect("oidc", options =>
- {
- options.SignInScheme = "Cookies";
-
- options.Authority = "http://localhost:5000";
- options.RequireHttpsMetadata = false;
-
- options.ClientId = "mvc";
- options.ClientSecret = "secret";
- options.ResponseType = "code id_token";
-
- options.SaveTokens = true;
- options.GetClaimsFromUserInfoEndpoint = true;
-
- options.Scope.Add("api1");
- options.Scope.Add("offline_access");
- });
当你运行MVC客户端时,不会有太大的区别,除了同意界面现在要求你提供额外的API和offline access访问作用域。
OpenID Connect中间件会自动为您保存令牌(标识,访问和刷新)。 这就是SaveTokens
设置的作用。
技术上,令牌存储在cookie。 访问它们的最简单方法是使用Microsoft.AspNetCore.Authentication
命名空间的扩展方法。
例如在View上获取Token:
- <dt>access token</dt>
- <dd>@await ViewContext.HttpContext.GetTokenAsync("access_token")</dd>
-
- <dt>refresh token</dt>
- <dd>@await ViewContext.HttpContext.GetTokenAsync("refresh_token")</dd>
要使用访问令牌访问API,您只需检索令牌,并将其设置在您的HttpClient上:
- public async Task
CallApiUsingUserAccessToken() - {
- var accessToken = await HttpContext.GetTokenAsync("access_token");
-
- var client = new HttpClient();
- client.SetBearerToken(accessToken);
- var content = await client.GetStringAsync("http://localhost:5001/identity");
-
- ViewBag.Json = JArray.Parse(content).ToString();
- return View("json");
- }