在之前的快速入门中我们探讨了 API 访问和用户认证。现在我们想要把这两部分结合起来。
OpenID Connect和OAuth 2.0组合的优点在于,您你既可以使用单一的协议,也可以向令牌服务做一次往返交互。
之前我们使用的是 OpenID Connect 隐式流。在隐式流中所有令牌都通过浏览器来传输,这对于 身份令牌 来说是完全没有问题的。现在我们还想要请求一个 访问令牌。
与身份令牌相比,访问令牌即accesstoken更加敏感,如果没有必要,我们是不会想将他们暴露给“外部世界”的。OpenID Connect 包含了一个叫做 “混合流(Hybrid flowe)” 的流,它为我们提供了两方面优点 —— 身份令牌通过浏览器频道来传输,这样客户端就能够在做任何工作前验证它;如果验证成功了,客户端就会打开一个后端通道来连接令牌服务以检索访问令牌。
其实我们常见的做法,在申请令牌的时候还可以将客户端id等信息隐藏起来,通过中间环节隐藏客户端id,再由中间环节去申请token。
没有必要做太多的修改。 首先,我们希望允许客户端使用Hybrid Flow,另外我们还希望客户端允许服务器到服务器API调用,这些调用不在用户的上下文中(这与我们的客户端认证模式的quickstart非常相似)。 这是使用AllowedGrantTypes属性表示的。
接下来我们需要添加一个客户端密钥。 这将用于反向检索通道上的AccessToken。
最后,我们还让客户端访问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"); }