上一篇介绍了ClientCredentials这一最简单的grant type,通常应用在machine对machine的通信环境有安全保障的场景下。
对于Web Application,SAP以及native/mobile Application等有终端用户参与登录的场景下, 更多使用Authorization Code这一grant type。
在微服务架构下,一个公共的identity server也避免了每个微服务/应用自己重复实现auth功能,也保障了登录相关UI的一致用户体验。
什么叫授权码(Authorization Code)?
上一篇ClientCredentials 很容易理解,ClientCredential(clientId+ secret)相当于用户名密码换取access token。
在Authorization Code这授权工作流(flow) 中,到底哪一步用到了Authorization code呢?
简单地说,用户认证成功之后,授权服务器不会马上返回AccessToken,而是先返回一个授权码(code),然后浏览器再通过code再去获取Token。
这个code,只能使用一次,而且有时效性,所以是非常安全的。
步骤如下:
- 用户通过浏览器访问mvc
- mvc 将用户(浏览器)重定向redirect到认证服务器
- 用户在认证服务器上完成认证(输入用户名密码/扫描...)
- 认证服务器将用户导向浏览器事先指定的"重定向URI"(redirect_uri),同时附上一个授权码(code)。
- 浏览器收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端(mvc)的后台的服务器上完成的,对用户不可见。
- 认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token);
- 客户端返回cookie给浏览器,后者将token保存在本地cookie中。后续用户再需访问mvc(受保护资源 )时,直接在请求中带上AccessToken即可;
(A)用户访问客户端(mvc web application),后者将前者导向认证服务器。
(B)用户在认证服务器上完成认证(输入用户名密码/扫描...,并授权)。
(C)认证服务器将用户导向客户端(mvc)事先指定的"重定向URI"(redirect_uri),同时附上一个授权码。
(D)客户端(mvc)收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端(mvc)的后台的服务器上完成的,对用户不可见。
(E)认证服务器核对了授权码和重定向URI,确认无误后,向客户端(mvc)发送访问令牌(access token)和更新令牌(refresh token)
(F)
重定向到IdentityServer
可以看到重定向到IdentityServer请求的URL是 authorization_endpoint (https://localhost:5001/connect/authorize)
附带的参数包括:(也就是在mvc config配置的)
- client_id,
- redirect_uri(aka callback URL,通常是固定的 https://localhost:5002/signin-oidc)
- response_type
- scope
配置mvc 使用了基于cookie的认证方案
将从IdentityServer获取的AccessToken 保存到本地,
options.SaveTokens = true;
添加 可用于处理Cookies的handler,
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
完整的代码如下:
//MVC client Program.cs: builder.Services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = "oidc"; }) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme) .AddOpenIdConnect("oidc", options => { options.Authority = "https://localhost:5001"; options.ClientId = "mvc"; options.ClientSecret = "secret"; options.ResponseType = "code"; //to pull remaining claims from the UserInfo endpoint options.Scope.Add("profile"); options.GetClaimsFromUserInfoEndpoint = true; options.SaveTokens = true; }); JwtSecurityTokenHandler.DefaultMapInboundClaims = false; ... //to ensure the execution of the authentication services on each request app.UseAuthentication(); app.UseAuthorization(); //navigating to the default controller will trigger authentication handshake app.MapDefaultControllerRoute().RequireAuthorization();
参考
- 阮一峰:理解OAuth 2.0
- 理解ASP.NET Core - 基于Cookie的身份认证(Authentication)
- IdentityServer4 官网: Interactive Applications with ASP.NET Core