使用 cookie 而无需 ASP.NET Core 标识的身份验证Use cookie authentication without ASP.NET Core Identity

本文内容

作者:Rick Anderson

ASP.NET Core 标识是完整、功能齐全的身份验证提供程序,用于创建和维护登录名。但是,可以使用不带 ASP.NET Core 标识的基于 cookie 的身份验证提供程序。有关详细信息,请参阅 ASP.NET Core 上的标识简介

查看或下载示例代码如何下载

出于演示目的,在示例应用程序中,假设用户(Maria Rodriguez)的用户帐户已硬编码到应用中。使用电子邮件地址 maria.rodriguez@contoso.com 和任何密码来登录用户。用户在页面/帐户/登录名. .cs文件的 AuthenticateUser 方法中进行身份验证。在实际的示例中,用户将对数据库进行身份验证。

配置Configuration

如果应用程序不使用AspNetCore 元包,请在 AspNetCore 包的项目文件中创建包引用(& c )。

Startup.ConfigureServices 方法中,创建具有 AddAuthenticationAddCookie 方法的身份验证中间件服务:

  1. services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
  2. .AddCookie();

AuthenticationScheme 传递到 AddAuthentication 设置应用程序的默认身份验证方案。如果有多个 cookie 身份验证实例,并且你想要使用特定方案进行授权AuthenticationScheme 会很有用。AuthenticationScheme 设置为CookieAuthenticationDefaults。 AuthenticationScheme为方案提供值 "cookie"。可以提供任何用于区分方案的字符串值。

应用的身份验证方案不同于应用的 cookie 身份验证方案。如果未向 AddCookie提供 cookie 身份验证方案,则使用 CookieAuthenticationDefaults.AuthenticationScheme ("Cookie")。

默认情况下,身份验证 cookie 的 IsEssential 属性设置为 true当站点访问者未同意数据收集时,允许使用身份验证 cookie。有关详细信息,请参阅 在 ASP.NET Core中的常规数据保护法规 (GDPR) 支持

Startup.Configure中,调用 UseAuthenticationUseAuthorization 设置 HttpContext.User 属性,并为请求运行授权中间件。调用 UseEndpoints之前调用 UseAuthenticationUseAuthorization 方法:

  1. app.UseAuthentication();
  2. app.UseAuthorization();
  3. app.UseEndpoints(endpoints =>
  4. {
  5. endpoints.MapControllers();
  6. endpoints.MapRazorPages();
  7. });

CookieAuthenticationOptions 类用于配置身份验证提供程序选项。

在服务配置中设置 CookieAuthenticationOptions,以便在 Startup.ConfigureServices 方法中进行身份验证:

  1. services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
  2. .AddCookie(options =>
  3. {
  4. ...
  5. });

Cookie 策略中间件Cookie Policy Middleware

Cookie 策略中间件支持 cookie 策略功能。将中间件添加到应用处理管道是区分顺序的—它仅影响在管道中注册的下游组件。

  1. app.UseCookiePolicy(cookiePolicyOptions);

使用提供给 Cookie 策略中间件的 CookiePolicyOptions 来控制 cookie 处理的全局特性并在附加或删除 cookie 时挂钩到 cookie 处理处理程序。

默认 MinimumSameSitePolicy 值为 SameSiteMode.Lax 以允许 OAuth2 authentication。若要严格实施 SameSiteMode.Strict的同一站点策略,请设置 MinimumSameSitePolicy尽管此设置会中断 OAuth2 和其他跨源身份验证方案,但它为不依赖于跨源请求处理的其他类型的应用提升了 cookie 安全级别。

  1. var cookiePolicyOptions = new CookiePolicyOptions
  2. {
  3. MinimumSameSitePolicy = SameSiteMode.Strict,
  4. };

MinimumSameSitePolicy 的 Cookie 策略中间件设置会根据下面的矩阵影响 CookieAuthenticationOptions 设置中 Cookie.SameSite 的设置。

MinimumSameSitePolicyCookie.SameSite生成的 SameSite 设置
SameSiteMode.NoneSameSiteMode.NoneSameSiteMode.LaxSameSiteMode.StrictSameSiteMode.NoneSameSiteMode.LaxSameSiteMode.Strict
SameSiteMode.LaxSameSiteMode.NoneSameSiteMode.LaxSameSiteMode.StrictSameSiteMode.LaxSameSiteMode.LaxSameSiteMode.Strict
SameSiteMode.StrictSameSiteMode.NoneSameSiteMode.LaxSameSiteMode.StrictSameSiteMode.StrictSameSiteMode.StrictSameSiteMode.Strict

创建身份验证 cookieCreate an authentication cookie

若要创建保存用户信息的 cookie,请构造一个 ClaimsPrincipal将对用户信息进行序列化并将其存储在 cookie 中。

使用任何所需的 Claim创建 ClaimsIdentity,并调用 SignInAsync 以登录用户:

  1. var claims = new List<Claim>
  2. {
  3. new Claim(ClaimTypes.Name, user.Email),
  4. new Claim("FullName", user.FullName),
  5. new Claim(ClaimTypes.Role, "Administrator"),
  6. };
  7. var claimsIdentity = new ClaimsIdentity(
  8. claims, CookieAuthenticationDefaults.AuthenticationScheme);
  9. var authProperties = new AuthenticationProperties
  10. {
  11. //AllowRefresh = <bool>,
  12. // Refreshing the authentication session should be allowed.
  13. //ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(10),
  14. // The time at which the authentication ticket expires. A
  15. // value set here overrides the ExpireTimeSpan option of
  16. // CookieAuthenticationOptions set with AddCookie.
  17. //IsPersistent = true,
  18. // Whether the authentication session is persisted across
  19. // multiple requests. When used with cookies, controls
  20. // whether the cookie's lifetime is absolute (matching the
  21. // lifetime of the authentication ticket) or session-based.
  22. //IssuedUtc = <DateTimeOffset>,
  23. // The time at which the authentication ticket was issued.
  24. //RedirectUri = <string>
  25. // The full path or absolute URI to be used as an http
  26. // redirect response value.
  27. };
  28. await HttpContext.SignInAsync(
  29. CookieAuthenticationDefaults.AuthenticationScheme,
  30. new ClaimsPrincipal(claimsIdentity),
  31. authProperties);

若要查看翻译为非英语语言的代码注释,请在 此 GitHub 讨论问题中告诉我们。

SignInAsync 创建加密的 cookie,并将其添加到当前响应中。如果未指定 AuthenticationScheme,则使用默认方案。

ASP.NET Core 的数据保护系统用于加密。对于托管在多台计算机上的应用程序、跨应用程序或使用 web 场进行负载平衡,请将数据保护配置为使用相同的密钥环和应用程序标识符。

注销Sign out

若要注销当前用户并删除其 cookie,请调用 SignOutAsync

  1. await HttpContext.SignOutAsync(
  2. CookieAuthenticationDefaults.AuthenticationScheme);

如果 CookieAuthenticationDefaults.AuthenticationScheme (或 "Cookie")不用作方案(例如 "ContosoCookie"),请提供配置身份验证提供程序时所使用的方案。否则,将使用默认方案。

对后端更改作出反应React to back-end changes

创建 cookie 后,cookie 就是单一标识源。如果在后端系统中禁用用户帐户:

  • 应用的 cookie 身份验证系统将继续根据身份验证 cookie 处理请求。
  • 只要身份验证 cookie 有效,用户就会保持登录到应用。

ValidatePrincipal 事件可用于截获和重写 cookie 标识的验证。验证每个请求的 cookie 会降低吊销用户访问应用的风险。

Cookie 验证的一种方法是基于跟踪用户数据库更改的时间。如果在颁发用户 cookie 后数据库尚未更改,则无需重新对用户进行身份验证,前提是其 cookie 仍然有效。在示例应用中,数据库在 IUserRepository 中实现并存储 LastChanged 值。当在数据库中更新用户时,LastChanged 值设置为当前时间。

为了使数据库根据 LastChanged 值更改时使 cookie 无效,请使用包含数据库中当前 LastChanged 值的 LastChanged 声明创建 cookie:

  1. var claims = new List<Claim>
  2. {
  3. new Claim(ClaimTypes.Name, user.Email),
  4. new Claim("LastChanged", {Database Value})
  5. };
  6. var claimsIdentity = new ClaimsIdentity(
  7. claims,
  8. CookieAuthenticationDefaults.AuthenticationScheme);
  9. await HttpContext.SignInAsync(
  10. CookieAuthenticationDefaults.AuthenticationScheme,
  11. new ClaimsPrincipal(claimsIdentity));

若要为 ValidatePrincipal 事件实现替代,请在从 CookieAuthenticationEvents派生的类中编写具有以下签名的方法:

  1. ValidatePrincipal(CookieValidatePrincipalContext)

下面是 CookieAuthenticationEvents的示例实现:

  1. using System.Linq;
  2. using System.Threading.Tasks;
  3. using Microsoft.AspNetCore.Authentication;
  4. using Microsoft.AspNetCore.Authentication.Cookies;
  5. public class CustomCookieAuthenticationEvents : CookieAuthenticationEvents
  6. {
  7. private readonly IUserRepository _userRepository;
  8. public CustomCookieAuthenticationEvents(IUserRepository userRepository)
  9. {
  10. // Get the database from registered DI services.
  11. _userRepository = userRepository;
  12. }
  13. public override async Task ValidatePrincipal(CookieValidatePrincipalContext context)
  14. {
  15. var userPrincipal = context.Principal;
  16. // Look for the LastChanged claim.
  17. var lastChanged = (from c in userPrincipal.Claims
  18. where c.Type == "LastChanged"
  19. select c.Value).FirstOrDefault();
  20. if (string.IsNullOrEmpty(lastChanged) ||
  21. !_userRepository.ValidateLastChanged(lastChanged))
  22. {
  23. context.RejectPrincipal();
  24. await context.HttpContext.SignOutAsync(
  25. CookieAuthenticationDefaults.AuthenticationScheme);
  26. }
  27. }
  28. }

Startup.ConfigureServices 方法中,在 cookie 服务注册期间注册事件实例。提供 CustomCookieAuthenticationEvents 类的作用域服务注册

  1. services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
  2. .AddCookie(options =>
  3. {
  4. options.EventsType = typeof(CustomCookieAuthenticationEvents);
  5. });
  6. services.AddScoped<CustomCookieAuthenticationEvents>();

请考虑这样一种情况:用户的名称更新—不会以任何方式影响安全性的决策。如果要以非破坏性的更新用户主体,请调用 context.ReplacePrincipal,并将 context.ShouldRenew 属性设置为 true

警告

此处所述的方法在每个请求时触发。验证每个请求的所有用户的身份验证 cookie 可能会导致应用程序的性能下降。

永久性 cookiePersistent cookies

你可能希望 cookie 在浏览器会话之间保持不变。仅当登录或类似机制上出现 "记住我" 复选框时,才应启用此持久性。

下面的代码片段创建一个标识,并在浏览器闭包置了相应的 cookie。预先配置的任何可调过期设置都将起作用。如果关闭浏览器时 cookie 过期,则在重新启动后,浏览器将清除 cookie。

IsPersistent 设置为 trueAuthenticationProperties中:

  1. // using Microsoft.AspNetCore.Authentication;
  2. await HttpContext.SignInAsync(
  3. CookieAuthenticationDefaults.AuthenticationScheme,
  4. new ClaimsPrincipal(claimsIdentity),
  5. new AuthenticationProperties
  6. {
  7. IsPersistent = true
  8. });

绝对 cookie 过期Absolute cookie expiration

绝对过期时间可使用 ExpiresUtc设置。若要创建持久性 cookie,还必须设置 IsPersistent否则,cookie 是使用基于会话的生存期创建的,并且可能会在它所包含的身份验证票证之前或之后过期。设置 ExpiresUtc 后,它将覆盖 CookieAuthenticationOptionsExpireTimeSpan 选项的值(如果已设置)。

下面的代码片段将创建一个标识和对应的 cookie,此 cookie 持续20分钟。这将忽略以前配置的任何可调过期设置。

  1. // using Microsoft.AspNetCore.Authentication;
  2. await HttpContext.SignInAsync(
  3. CookieAuthenticationDefaults.AuthenticationScheme,
  4. new ClaimsPrincipal(claimsIdentity),
  5. new AuthenticationProperties
  6. {
  7. IsPersistent = true,
  8. ExpiresUtc = DateTime.UtcNow.AddMinutes(20)
  9. });

ASP.NET Core 标识是完整、功能齐全的身份验证提供程序,用于创建和维护登录名。但是,可以使用不带 ASP.NET Core 标识的基于 cookie 的身份验证提供程序。有关详细信息,请参阅 ASP.NET Core 上的标识简介

查看或下载示例代码如何下载

出于演示目的,在示例应用程序中,假设用户(Maria Rodriguez)的用户帐户已硬编码到应用中。使用电子邮件地址 maria.rodriguez@contoso.com 和任何密码来登录用户。用户在页面/帐户/登录名. .cs文件的 AuthenticateUser 方法中进行身份验证。在实际的示例中,用户将对数据库进行身份验证。

配置Configuration

如果应用程序不使用AspNetCore 元包,请在 AspNetCore 包的项目文件中创建包引用(& c )。

Startup.ConfigureServices 方法中,创建具有 AddAuthenticationAddCookie 方法的身份验证中间件服务:

  1. services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
  2. .AddCookie();

AuthenticationScheme 传递到 AddAuthentication 设置应用程序的默认身份验证方案。如果有多个 cookie 身份验证实例,并且你想要使用特定方案进行授权AuthenticationScheme 会很有用。AuthenticationScheme 设置为CookieAuthenticationDefaults。 AuthenticationScheme为方案提供值 "cookie"。可以提供任何用于区分方案的字符串值。

应用的身份验证方案不同于应用的 cookie 身份验证方案。如果未向 AddCookie提供 cookie 身份验证方案,则使用 CookieAuthenticationDefaults.AuthenticationScheme ("Cookie")。

默认情况下,身份验证 cookie 的 IsEssential 属性设置为 true当站点访问者未同意数据收集时,允许使用身份验证 cookie。有关详细信息,请参阅 在 ASP.NET Core中的常规数据保护法规 (GDPR) 支持

Startup.Configure 方法中,调用 UseAuthentication 方法来调用设置 HttpContext.User 属性的身份验证中间件。在调用 UseMvcWithDefaultRouteUseMvc之前调用 UseAuthentication 方法:

  1. app.UseAuthentication();

CookieAuthenticationOptions 类用于配置身份验证提供程序选项。

在服务配置中设置 CookieAuthenticationOptions,以便在 Startup.ConfigureServices 方法中进行身份验证:

  1. services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
  2. .AddCookie(options =>
  3. {
  4. ...
  5. });

Cookie 策略中间件Cookie Policy Middleware

Cookie 策略中间件支持 cookie 策略功能。将中间件添加到应用处理管道是区分顺序的—它仅影响在管道中注册的下游组件。

  1. app.UseCookiePolicy(cookiePolicyOptions);

使用提供给 Cookie 策略中间件的 CookiePolicyOptions 来控制 cookie 处理的全局特性并在附加或删除 cookie 时挂钩到 cookie 处理处理程序。

默认 MinimumSameSitePolicy 值为 SameSiteMode.Lax 以允许 OAuth2 authentication。若要严格实施 SameSiteMode.Strict的同一站点策略,请设置 MinimumSameSitePolicy尽管此设置会中断 OAuth2 和其他跨源身份验证方案,但它为不依赖于跨源请求处理的其他类型的应用提升了 cookie 安全级别。

  1. var cookiePolicyOptions = new CookiePolicyOptions
  2. {
  3. MinimumSameSitePolicy = SameSiteMode.Strict,
  4. };

MinimumSameSitePolicy 的 Cookie 策略中间件设置会根据下面的矩阵影响 CookieAuthenticationOptions 设置中 Cookie.SameSite 的设置。

MinimumSameSitePolicyCookie.SameSite生成的 SameSite 设置
SameSiteMode.NoneSameSiteMode.NoneSameSiteMode.LaxSameSiteMode.StrictSameSiteMode.NoneSameSiteMode.LaxSameSiteMode.Strict
SameSiteMode.LaxSameSiteMode.NoneSameSiteMode.LaxSameSiteMode.StrictSameSiteMode.LaxSameSiteMode.LaxSameSiteMode.Strict
SameSiteMode.StrictSameSiteMode.NoneSameSiteMode.LaxSameSiteMode.StrictSameSiteMode.StrictSameSiteMode.StrictSameSiteMode.Strict

创建身份验证 cookieCreate an authentication cookie

若要创建保存用户信息的 cookie,请构造一个 ClaimsPrincipal将对用户信息进行序列化并将其存储在 cookie 中。

使用任何所需的 Claim创建 ClaimsIdentity,并调用 SignInAsync 以登录用户:

  1. var claims = new List<Claim>
  2. {
  3. new Claim(ClaimTypes.Name, user.Email),
  4. new Claim("FullName", user.FullName),
  5. new Claim(ClaimTypes.Role, "Administrator"),
  6. };
  7. var claimsIdentity = new ClaimsIdentity(
  8. claims, CookieAuthenticationDefaults.AuthenticationScheme);
  9. var authProperties = new AuthenticationProperties
  10. {
  11. //AllowRefresh = <bool>,
  12. // Refreshing the authentication session should be allowed.
  13. //ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(10),
  14. // The time at which the authentication ticket expires. A
  15. // value set here overrides the ExpireTimeSpan option of
  16. // CookieAuthenticationOptions set with AddCookie.
  17. //IsPersistent = true,
  18. // Whether the authentication session is persisted across
  19. // multiple requests. When used with cookies, controls
  20. // whether the cookie's lifetime is absolute (matching the
  21. // lifetime of the authentication ticket) or session-based.
  22. //IssuedUtc = <DateTimeOffset>,
  23. // The time at which the authentication ticket was issued.
  24. //RedirectUri = <string>
  25. // The full path or absolute URI to be used as an http
  26. // redirect response value.
  27. };
  28. await HttpContext.SignInAsync(
  29. CookieAuthenticationDefaults.AuthenticationScheme,
  30. new ClaimsPrincipal(claimsIdentity),
  31. authProperties);

SignInAsync 创建加密的 cookie,并将其添加到当前响应中。如果未指定 AuthenticationScheme,则使用默认方案。

ASP.NET Core 的数据保护系统用于加密。对于托管在多台计算机上的应用程序、跨应用程序或使用 web 场进行负载平衡,请将数据保护配置为使用相同的密钥环和应用程序标识符。

注销Sign out

若要注销当前用户并删除其 cookie,请调用 SignOutAsync

  1. await HttpContext.SignOutAsync(
  2. CookieAuthenticationDefaults.AuthenticationScheme);

如果 CookieAuthenticationDefaults.AuthenticationScheme (或 "Cookie")不用作方案(例如 "ContosoCookie"),请提供配置身份验证提供程序时所使用的方案。否则,将使用默认方案。

对后端更改作出反应React to back-end changes

创建 cookie 后,cookie 就是单一标识源。如果在后端系统中禁用用户帐户:

  • 应用的 cookie 身份验证系统将继续根据身份验证 cookie 处理请求。
  • 只要身份验证 cookie 有效,用户就会保持登录到应用。

ValidatePrincipal 事件可用于截获和重写 cookie 标识的验证。验证每个请求的 cookie 会降低吊销用户访问应用的风险。

Cookie 验证的一种方法是基于跟踪用户数据库更改的时间。如果在颁发用户 cookie 后数据库尚未更改,则无需重新对用户进行身份验证,前提是其 cookie 仍然有效。在示例应用中,数据库在 IUserRepository 中实现并存储 LastChanged 值。当在数据库中更新用户时,LastChanged 值设置为当前时间。

为了使数据库根据 LastChanged 值更改时使 cookie 无效,请使用包含数据库中当前 LastChanged 值的 LastChanged 声明创建 cookie:

  1. var claims = new List<Claim>
  2. {
  3. new Claim(ClaimTypes.Name, user.Email),
  4. new Claim("LastChanged", {Database Value})
  5. };
  6. var claimsIdentity = new ClaimsIdentity(
  7. claims,
  8. CookieAuthenticationDefaults.AuthenticationScheme);
  9. await HttpContext.SignInAsync(
  10. CookieAuthenticationDefaults.AuthenticationScheme,
  11. new ClaimsPrincipal(claimsIdentity));

若要为 ValidatePrincipal 事件实现替代,请在从 CookieAuthenticationEvents派生的类中编写具有以下签名的方法:

  1. ValidatePrincipal(CookieValidatePrincipalContext)

下面是 CookieAuthenticationEvents的示例实现:

  1. using System.Linq;
  2. using System.Threading.Tasks;
  3. using Microsoft.AspNetCore.Authentication;
  4. using Microsoft.AspNetCore.Authentication.Cookies;
  5. public class CustomCookieAuthenticationEvents : CookieAuthenticationEvents
  6. {
  7. private readonly IUserRepository _userRepository;
  8. public CustomCookieAuthenticationEvents(IUserRepository userRepository)
  9. {
  10. // Get the database from registered DI services.
  11. _userRepository = userRepository;
  12. }
  13. public override async Task ValidatePrincipal(CookieValidatePrincipalContext context)
  14. {
  15. var userPrincipal = context.Principal;
  16. // Look for the LastChanged claim.
  17. var lastChanged = (from c in userPrincipal.Claims
  18. where c.Type == "LastChanged"
  19. select c.Value).FirstOrDefault();
  20. if (string.IsNullOrEmpty(lastChanged) ||
  21. !_userRepository.ValidateLastChanged(lastChanged))
  22. {
  23. context.RejectPrincipal();
  24. await context.HttpContext.SignOutAsync(
  25. CookieAuthenticationDefaults.AuthenticationScheme);
  26. }
  27. }
  28. }

Startup.ConfigureServices 方法中,在 cookie 服务注册期间注册事件实例。提供 CustomCookieAuthenticationEvents 类的作用域服务注册

  1. services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
  2. .AddCookie(options =>
  3. {
  4. options.EventsType = typeof(CustomCookieAuthenticationEvents);
  5. });
  6. services.AddScoped<CustomCookieAuthenticationEvents>();

请考虑这样一种情况:用户的名称更新—不会以任何方式影响安全性的决策。如果要以非破坏性的更新用户主体,请调用 context.ReplacePrincipal,并将 context.ShouldRenew 属性设置为 true

警告

此处所述的方法在每个请求时触发。验证每个请求的所有用户的身份验证 cookie 可能会导致应用程序的性能下降。

永久性 cookiePersistent cookies

你可能希望 cookie 在浏览器会话之间保持不变。仅当登录或类似机制上出现 "记住我" 复选框时,才应启用此持久性。

下面的代码片段创建一个标识,并在浏览器闭包置了相应的 cookie。预先配置的任何可调过期设置都将起作用。如果关闭浏览器时 cookie 过期,则在重新启动后,浏览器将清除 cookie。

IsPersistent 设置为 trueAuthenticationProperties中:

  1. // using Microsoft.AspNetCore.Authentication;
  2. await HttpContext.SignInAsync(
  3. CookieAuthenticationDefaults.AuthenticationScheme,
  4. new ClaimsPrincipal(claimsIdentity),
  5. new AuthenticationProperties
  6. {
  7. IsPersistent = true
  8. });

绝对 cookie 过期Absolute cookie expiration

绝对过期时间可使用 ExpiresUtc设置。若要创建持久性 cookie,还必须设置 IsPersistent否则,cookie 是使用基于会话的生存期创建的,并且可能会在它所包含的身份验证票证之前或之后过期。设置 ExpiresUtc 后,它将覆盖 CookieAuthenticationOptionsExpireTimeSpan 选项的值(如果已设置)。

下面的代码片段将创建一个标识和对应的 cookie,此 cookie 持续20分钟。这将忽略以前配置的任何可调过期设置。

  1. // using Microsoft.AspNetCore.Authentication;
  2. await HttpContext.SignInAsync(
  3. CookieAuthenticationDefaults.AuthenticationScheme,
  4. new ClaimsPrincipal(claimsIdentity),
  5. new AuthenticationProperties
  6. {
  7. IsPersistent = true,
  8. ExpiresUtc = DateTime.UtcNow.AddMinutes(20)
  9. });

其他资源Additional resources