使用cookie来做身份认证
2018-08-28 01:21
609 查看
文章是msdn的官方文档,链接在这里。其实也有中文的文档,这里还是想做一个记录。
文章有asp.net core 2.x 和1.x 版本,我这里就忽略1.x了。
下面先说几点额外的东西有助于理解。
Authentication:认证。
Authorization:授权。
简单来说,认证是用来证明一个人的身份,比如说他是一个学生,一个老师,一个boss,那么就需要这么一个认证。授权是用来表示这个用户能做什么事情,比如admin可以修改删除数据,normal user只能查看数据。
Audience:听众,这个 cookie 的受众是谁。
示例源码在这里。
因为我们这里只是做一个demo程序,所以写死一个假设的用户Maria Rodriguez到系统里面。邮箱相关的用户名是“maria.rodriguez@contoso.com”,密码任意。用户通过
更多如何从ASP.net Core 1.x 到2.0的信息参考这里.
想使用ASP.net Core Identity,参考这里.
在
传给
在
具体详细的通过
CookiePolicyOptions提供了程序全局特性相关的设置。并且可以在 cookie 添加或者删除的时候挂钩一些处理程序。 有以下一些属性。
用必要的 Claim来构造一个ClaimsIdentity,然后调用
加密是基于asp.net core 的Data Protection系统实现的,所以,如果程序是部署在多台机器或者做了负载均衡上的话,需要配置 data protection(和当年 asp.net 里面的类似。)
登录和登出需要使用相同的方案名称。也就是一样的AuthenticationScheme。
ValidatePrincipal事件可以用来拦截或者覆盖 cookie 的身份验证。这可以减少被收回权限的用户对系统损害的风险。可以通过如下方式实现这个功能。
首先修改一下 SignInAsync 方法里面获取到的用户相关的 claim。
然后创建一个
然后通过
考虑一种情况,如果说这个用户更新了之后不影响系统的安全,可以考虑替换
上面的实现方法会在每个请求的时候都触发,所以会对系统的性能造成一定的影响。
下面的代码用来实现 cookie 持久化。
如果 cookie 在浏览器关闭期间过期了,浏览器会在下次启动的时候自动删除 cookie。
AuthenticationProperties在
当在 SignInAsync 方法里面设置了
下面的代码设置了一个20min 有效期的持久化 cookie,其他有效期相关的设置都会被忽略。
文章有asp.net core 2.x 和1.x 版本,我这里就忽略1.x了。
下面先说几点额外的东西有助于理解。
Authentication 和 Authorization
这里先讲一下Authentication和Authorization两个词的区别。Authentication:认证。
Authorization:授权。
简单来说,认证是用来证明一个人的身份,比如说他是一个学生,一个老师,一个boss,那么就需要这么一个认证。授权是用来表示这个用户能做什么事情,比如admin可以修改删除数据,normal user只能查看数据。
Issuer 和 Audience
Issuer:发行者,这里来说就是 cookie 是谁分发的。Audience:听众,这个 cookie 的受众是谁。
正文
就像你前面看到认证相关的主题,Asp.net core Identity 是一个创建用户和维护用户登录的完备的认证解决方案。但有时你可能也想要自己的基于cookie的认证方式。你可以在不使用Asp.net core Identity的情况下使用cookie来实现一种独立的认证服务。示例源码在这里。
因为我们这里只是做一个demo程序,所以写死一个假设的用户Maria Rodriguez到系统里面。邮箱相关的用户名是“maria.rodriguez@contoso.com”,密码任意。用户通过
Pages/Account/Login.cshtml.cs文件中的
AuthenticateUser方法做认证。现实环境中应该基于数据库。
更多如何从ASP.net Core 1.x 到2.0的信息参考这里.
想使用ASP.net Core Identity,参考这里.
配置
如果程序没有使用Microsoft.AspNetCore.App元程序包,给程序引用一下Microsoft.AspNetCore.Authentication.Cookies(版本≥2.1.0)。在
ConfigureServices中,通过
Authentication和
AddCookie方法添加一下认证服务。
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie();
传给
AddAuthentication的
AuthenticationScheme值设置了程序默认使用的认证方案。
AuthenticationScheme在你有多个 cookie 认证实例或者你系统用某种特定的方案来做认证的时候是非常有用的。设置成为
CookieAuthenticationDefaults.AuthenticationScheme就表示用‘Cookies’来作为一个方案。你可以设置任意的 string 类型的值来区分不同的方案。
在
Configure方法中,使用
UseAuthentication来调用认证中间件用于设置
HttpContext.User属性。应在
UseMvcWithDefaultRoute和
UseMvc方法之前调用
UseAuthentication方法。
AddCookie 设置选项
大致是这么设置:services .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.ClaimsIssuer = "test"; options.ClaimsIssuer = "aa"; //以及其他... });
具体详细的通过
CookieAuthenticationOptions来设置相关的选项。着重看几个关键的设置,比如 AccessDeniedPath, LoginPath, LogoutPath, Domain, Name,
ExpireTimeSpan。
选项 | 描述 |
---|---|
AccessDeniedPath | 当HttpContext.ForbidAsync触发302时的跳转地址,默认 /Account/AccessDenied |
ClaimsIssuer | 用于设置 cookie 的Issuer 属性。 |
Cookie.Domain | cookie的有效域。默认是请求的服务器名。浏览器只会给符合的服务器发送 cookie。你可能会希望设置这个值来调整他的作用域。举个例子,设置成.contoso.com他的作用域就包括 contoso.com, www.contoso.com, staging.www.contoso.com等。 |
Cookie.Expiration | 获取或设置cookie的有效期。core 2.1+不建议使用。建议是使用ExpireTimeSpan来设置 cookie 的失效时间。 |
Cookie.HttpOnly | 设置 cookie 是否是只能被服务器访问,默认 true,可以设置成 false 给客户端js 脚本访问,但是有可能会造成XSS(跨站脚本攻击)。 |
Cookie.Name | cookie 的名字。 |
Cookie.Path | 用来隔离同一个服务器下面的不同站点。比如站点是运行在/app1下面,设置这个属性为 /app1,那么这个 cookie 就只在 app1下有效。 |
Cookie.SameSite | 表示浏览器是否允许 cookie 被附加到相同的站点。有几种枚举:SameSiteMode.Strict,只允许相同的站点。 SameSiteMode.Lax允许以安全的 http方式附加到不同站点或相同站点。为了支持 OAuth 认证,需要设置成 SameSiteMode.Lax。 |
Cookie.SecurePolicy | 设置是否只允许 https。 |
DataProtectionProvider | 用于设置创建TicketDataFormat(在表格最后) |
Events | 设置一些时间的处理程序。比如OnSignedIn, OnSigningOut等,默认是不做任何操作。 |
EventsType | Events的类型。 |
ExpireTimeSpan | 设置存储在 cookie 里面的认证票据的过期时间。服务端会验证加密的 ticket 的有效性。在设置了IsPersistent之后也能在 Set-Cookie 头里面返回。默认的过期时间是14天。 |
LoginPath | HttpContext.ChallengeAsync方法触发302跳转时候的地址。假设设置成 /account/login,比如当前访问 /secure返回401,那么会跳转地址 /account/login?returnUrl=/secure,当 login 页面生成一个新的登录身份之后,浏览器会跳转到 secure 页面。默认值是 /Account/login |
LogoutPath | 登出地址。 |
ReturnUrlParameter | 登录或登出之后页面可以做一个跳转,这个跳转地址作为一个参数传过去,这个就用来设置这个参数的名字。 |
SessionStore | 用来保存跨站点请求的身份信息。设置了之后只有 session 的标识符会发送到客户端。当身份标识比较多的时候可以用。 |
SlidingExpiration | 滑动过期。标识一个有新的过期时间的新 cookie是否可以被动态的分发。可以在SignInAsync方法里面使用 AuthenticationProperties。使用绝对的 cookie 有效期时间来增加应用的安全性。举个例子: await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), new AuthenticationProperties { IsPersistent = true, ExpiresUtc = DateTime.UtcNow.AddMinutes(20) }); |
TicketDataFormat | |
Validate | 验证当前 option是否是有效的。 |
Cookie Policy Middleware
Cookie 策略中间件。用于设置应用的 cookie的兼容性。和顺序有关,只会影响程序管道他后面的设置。如下方式使用。app.UseCookiePolicy(cookiePolicyOptions);
CookiePolicyOptions提供了程序全局特性相关的设置。并且可以在 cookie 添加或者删除的时候挂钩一些处理程序。 有以下一些属性。
属性 | 描述 |
---|---|
HttpOnly | 设置 cookie 是否是只能通过服务器访问的。默认是HttpOnlyPolicy.None |
CheckConsentNeeded | 一个返回 bool 的函数,如果返回 true 会在弹出一个页面让用户确认使用 cookie |
ConsentCookie | (这个文档上也没说。。。) |
MinimumSameSitePolicy | 同站点策略,默认是SameSiteMode.Lax, Asp.net Core2.0+ 可用。 |
OnAppendCookie | cookie 被追加的时候调用。 |
OnDeleteCookie | cookie 被删除的时候调用。 |
Secure | 标识 cookie 是否必须是https. |
创建一个认证 cookie
创建一个包含用户信息的 cookie需要构造一个ClaimsPrincipal。用户信息会被序列化然后保存在cookie 里面。用必要的 Claim来构造一个ClaimsIdentity,然后调用
SignInAsync方法。
var claims = new List<Claim> { new Claim(ClaimTypes.Name, user.Email), new Claim("FullName", user.FullName), new Claim(ClaimTypes.Role, "Administrator"), }; var claimsIdentity = new ClaimsIdentity( claims, CookieAuthenticationDefaults.AuthenticationScheme); var authProperties = new AuthenticationProperties { //AllowRefresh = <bool>, // Refreshing the authentication session should be allowed. //ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(10), //cookie 的绝对过期时间,会覆盖ExpireTimeSpan的设置。 //IsPersistent = true, //表示 cookie 是否是持久化的以便它在不同的 request 之间传送。设置了ExpireTimeSpan或ExpiresUtc是必须的。 //IssuedUtc = <DateTimeOffset>, // 凭证认证的时间。 //RedirectUri = <string> //http 跳转的时候的路径。 }; await HttpContext.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties);
SignInAsync方法创建一个加密过的 cookie 然后把他添加到当前的 response 中。没有设置AuthenticationScheme的话会使用默认的 scheme。
加密是基于asp.net core 的Data Protection系统实现的,所以,如果程序是部署在多台机器或者做了负载均衡上的话,需要配置 data protection(和当年 asp.net 里面的类似。)
登出
SignOutAsync用来登出当前用户并且删除 cookie。代码如下。
await HttpContext.SignOutAsync( CookieAuthenticationDefaults.AuthenticationScheme);
登录和登出需要使用相同的方案名称。也就是一样的AuthenticationScheme。
对后台的改变作出反应
当 cookie 被创建之后,它就成了身份标识的唯一来源。即使在后台禁用了当前用户,因为 已经分发的cookie 无法知晓,所以用户依旧可以保持登录状态直到 cookie 失效。ValidatePrincipal事件可以用来拦截或者覆盖 cookie 的身份验证。这可以减少被收回权限的用户对系统损害的风险。可以通过如下方式实现这个功能。
首先修改一下 SignInAsync 方法里面获取到的用户相关的 claim。
var claims = new List<Claim> { new Claim(ClaimTypes.Name, user.Email), new Claim("LastChanged", {数据库的值})//增加一个LastChanged,然后记录一下值 }; var claimsIdentity = new ClaimsIdentity( claims, CookieAuthenticationDefaults.AuthenticationScheme); await HttpContext.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity));
然后创建一个
CustomCookieAuthenticationEvents继承自
CookieAuthenticationEvents
using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; public class CustomCookieAuthenticationEvents : CookieAuthenticationEvents { private readonly IUserRepository _userRepository; public CustomCookieAuthenticationEvents(IUserRepository userRepository) { // 从DI 里面获取用户相关的. _userRepository = userRepository; } public override async Task ValidatePrincipal(CookieValidatePrincipalContext context) { var userPrincipal = context.Principal; // 查找上面的LastChanged相关的claim. var lastChanged = (from c in userPrincipal.Claims where c.Type == "LastChanged" select c.Value).FirstOrDefault(); if (string.IsNullOrEmpty(lastChanged) || !_userRepository.ValidateLastChanged(lastChanged))//调用的ValidateLastChanged来判断这个lastChanged 相关的额 cookie是否是一个有效的cookie { context.RejectPrincipal();//拒绝这个 cookie await context.HttpContext.SignOutAsync( CookieAuthenticationDefaults.AuthenticationScheme);// 自动登出 } } //其他的方法,都可以设置 public override Task SignedIn(CookieSignedInContext context) { return base.SignedIn(context); } }
然后通过
EventsType来调用这个设置,然后注入这个
CustomCookieAuthenticationEvents
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.EventsType = typeof(CustomCookieAuthenticationEvents); }); services.AddScoped<CustomCookieAuthenticationEvents>();
考虑一种情况,如果说这个用户更新了之后不影响系统的安全,可以考虑替换
context.RejectPrincipal()为
context.ReplacePrincipal,并且设置
context.ShouldRenew=true来无损的更新用户的principal。
上面的实现方法会在每个请求的时候都触发,所以会对系统的性能造成一定的影响。
持久化 cookie
你可能想要持久化 cookie 让他可以在浏览器的不同进程之间使用。cookie 的持久化应该用类似在界面上显示“记住我”的复选框,然后让用户点击的方式来实现。其他类似的机制也行。下面的代码用来实现 cookie 持久化。
await HttpContext.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), new AuthenticationProperties { IsPersistent = true });
如果 cookie 在浏览器关闭期间过期了,浏览器会在下次启动的时候自动删除 cookie。
AuthenticationProperties在
Microsoft.AspNetCore.Authentication命名空间里面。
绝对过期时间
可以用ExpiresUtc来设置绝对过期时间,但必须同时设置
IsPersistent,否者这个这个参数会被忽略,同时,这个 cookie 只是当前回话有效。
当在 SignInAsync 方法里面设置了
ExpiresUtc,它会覆盖
CookieAuthenticationOptions设置了的
ExpireTimeSpan。
下面的代码设置了一个20min 有效期的持久化 cookie,其他有效期相关的设置都会被忽略。
await HttpContext.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), new AuthenticationProperties { IsPersistent = true, ExpiresUtc = DateTime.UtcNow.AddMinutes(20) });
最后就是感慨一下,msdn 好强大。
相关文章推荐
- ASP.NET学习CORE中使用Cookie身份认证方法
- 使用 Cookie 而无需 ASP.NET 核心标识的身份验证
- 【译】使用Jwt身份认证保护 Asp.Net Core Web Api
- 使用内嵌IFrame,处理系统跨域身份认证的方案与实现
- goahead 的认证和自定义登陆页面的cookie使用
- 使用Session和Cookie实现登录认证
- goahead 的认证和自定义登陆页面的cookie使用
- 身份认证狗,在B/S结构系统中的使用
- 如何使用POST man模拟发送一个需要cookie认证的请求
- PHP和MySQL Web开发读书笔记---使用PHP和MySQL实现身份认证
- Sprint Boot使用OAuth和JWT实现身份认证【一】
- [转]IE11下Forms身份认证无法保存Cookie的问题
- 可使用两种方法之一生成窗体身份验证 Cookie,并将用户重定向到 cmdLogin_ServerClick 事件中的相应页。
- 使用nginx 的反向代理 给 kibana加上basic的身份认证
- 使用HttpMoudle和IPrincipal实现自定义身份及权限认证
- HttpClient支持使用代理服务器以及身份认证
- ASP.NET Core的身份认证框架IdentityServer4(7)- 使用客户端证书控制API访问
- 使用Windows活动目录为Samba做身份认证
- IE11下ASP.NET Forms身份认证无法保存Cookie的问题
- goahead 的认证和自定义登陆页面的cookie使用