目录
什么是 Cookie?
它是如何运作的?
如何在.NET8中实现?
项目运行

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。
示例代码:https://download.csdn.net/download/hefeng_aspnet/92599924
什么是 Cookie?
在网络环境中,Cookie是存储用户信息的对象,用于根据用户在网站上的操作来识别、跟踪和个性化用户体验。
它是如何运作的?
当您登录网站时,处理您请求的服务器会在登录成功后创建一个包含 ID、用户数据以及一些信息(例如 cookie 类型、过期时间、刷新策略等)的 cookie。浏览器收到 cookie 后,会负责存储该 cookie 并将其在每次请求中发送给服务器。服务器会在每次请求时检查 cookie 的属性。

如何在.NET8中实现?
本教程需要您创建一个 ASP.NET Core Web API 并安装以下软件包:
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="2.3.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.16" />
我创建了一个简单的实体来表示用户,包含姓名、邮箱、密码和角色。您可以通过此链接查看。
对于表映射,请使用以下配置:
public class UserConfiguration : IEntityTypeConfiguration<User> { public void Configure(EntityTypeBuilder<User> builder) { builder.HasKey(x => x.Id); builder.HasIndex(x => x.Email).IsUnique();
builder.Property(x => x.Name).HasMaxLength(100).IsRequired(); builder.Property(x => x.Email).HasMaxLength(100).IsRequired(); builder.Property(x => x.Password).HasMaxLength(250).IsRequired(); } }
我将Email属性设置为索引,并将其标记为唯一,以确保不同用户无法使用相同的电子邮件地址注册。这样,它还可以有效地用作登录时的筛选参数。
在 DbContext 中,请确保按如下方式配置 UserRoles 关系:
public class AppDbContext : DbContext { public DbSet<User> Users { get; set; } public DbSet<Role> Roles { get; set; }
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>() .HasMany(u => u.Roles) .WithMany(r => r.Users) .UsingEntity<Dictionary<string, object>>( "UserRoles", j => j.HasOne<Role>().WithMany().HasForeignKey("RoleId"), j => j.HasOne<User>().WithMany().HasForeignKey("UserId"), j => { j.HasKey("UserId", "RoleId"); j.ToTable("UserRoles"); }); } }
在代码仓库中,我们只需要通过用户的电子邮件地址进行搜索:
public class UserRepository : IUserRespository { private readonly AppDbContext _context; private readonly DbSet<User> _users;
public UserRepository(AppDbContext context) { _context = context; _users = _context.Set<User>(); }
public async Task<User?> GetByEmail(string email) { return await _users .Where(x => x.Email == email) .Include(x => x.Roles) .FirstOrDefaultAsync(); } } 现在我们可以专注于登录服务了,它非常简单:它接收用户输入,根据电子邮件地址在数据库中查找用户,验证密码,然后返回该用户。以下是实现代码:
public class LoginService : ILoginService { protected readonly IUserRespository _respository;
public LoginService(IUserRespository respository) { _respository = respository; }
public async Task<TResult<User>> Login(LoginDto dto) { var result = new TResult<User>(); var user = await _respository.GetByEmail(dto.Email);
if (user == null) { result.AddError($"User {dto.Email} not found!"); return result; }
if (!user.IsPasswordMatch(dto.Password)) { result.AddError($"Password Incorrect!"); return result; }
result.Success(user); return result; } } 现在需要配置Cookie 身份验证,请打开Program.cs文件并添加以下配置:
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.Cookie.Name = "CookieAuthSystem"; options.Cookie.HttpOnly = true; options.Cookie.SecurePolicy = CookieSecurePolicy.Always; options.Cookie.SameSite = SameSiteMode.Strict; options.ExpireTimeSpan = TimeSpan.FromMinutes(5); options.SlidingExpiration = true; options.LoginPath = "/auth/login"; options.AccessDeniedPath = "/auth/access-denied"; // Hanlder the unauthorized access options.Events.OnRedirectToLogin = context => { context.Response.StatusCode = 401; return Task.CompletedTask; }; }) 配置说明: Cookie.HttpOnly = true >> 确保客户端 JavaScript 无法访问身份验证 cookie,从而有助于防止 XSS(跨站脚本)攻击。
Cookie.SecurePolicy = CookieSecurePolicy.Always >> Cookie 将仅通过 HTTPS 请求发送。
Cookie.SameSite = SameSiteMode.Strict >> 防止 cookie 随跨域请求发送,有助于防止 CSRF(跨站请求伪造)攻击。
ExpireTimeSpan = TimeSpan.FromMinutes(5) >> 设置 Cookie 生命周期为 5 分钟。
SlidingExpiration = true >> 如果当前 cookie 即将过期(剩余时间过半),则请求新的 cookie。这可以防止用户在连续访问网站期间重复登录,从而改善用户体验。
配置好Cookie 身份验证后,我们就可以实现生成 Cookie 的服务了:
public class CookieService : ICookieService {
public CookieDto GenerateCookie(User user) { var claims = new List<Claim> { new Claim(ClaimTypes.Name, user.Name), new Claim(ClaimTypes.Email, user.Email), };
foreach (var role in user.Roles) { claims.Add(new Claim(ClaimTypes.Role, role.Name)); }
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var authProperties = new AuthenticationProperties { IsPersistent = true, AllowRefresh = true, ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(5), };
return new CookieDto(claimsIdentity, authProperties); } 在声明身份中,我们提供用户名、电子邮件及其角色,并定义身份验证类型,即基于 cookie 的身份验证。
在 Cookie 属性中,我们设置了持久性、允许请求新 cookie 以及定义过期时间。
现在我们来看身份验证控制器:
[ApiController] [Route("auth")] public class AuthController : Controller { protected readonly ILoginService _loginService; protected readonly ICookieService _cookieService;
public AuthController(ILoginService loginService, ICookieService cookieService) { _loginService = loginService; _cookieService = cookieService; }
[HttpPost("login")] public async Task<IActionResult> Login([FromBody] LoginDto request) { var userResult = await _loginService.Login(request);
// Check if login is successful if (!userResult.IsSuccess || userResult.Value == null) { return BadRequest(userResult.ErrorMessage); }
var cookie = _cookieService.GenerateCookie(userResult.Value);
await HttpContext.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(cookie.Claims), cookie.Properties);
return LocalRedirect("/auth/logged"); }
[HttpPost("logout")] public async Task<IActionResult> Logout() { await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); return Ok("User Logout Successful"); }
[HttpGet("access-denied")] public IActionResult NotAllowed() { return Unauthorized("You not allowed to access this resource"); }
[Authorize] [HttpGet("logged")] public IActionResult Logged() { var userName = User.FindFirst(ClaimTypes.Name)?.Value;
return Ok($"Hello {userName}"); } }
登录:创建一个包含用户信息的 cookie,并将用户重定向到/logged页面,该页面包含存储在 brownser 中的 cookie。
注销:将 Cookie 变为无效并从浏览器中删除。
访问被拒绝:每当有人尝试访问未经授权的资源时,他们都会被重定向到此路径。
受保护的端点:
[ApiController] [Route("api")] public class ApiController : Controller {
[Authorize(Roles = "User")] [HttpGet("user")] public ActionResult UserController() { return Ok("Hello User"); }
[Authorize(Roles = "Manager")] [HttpGet("manager")] public ActionResult ManagerController() { return Ok("Hello Manager"); }
[Authorize(Roles = "Admin")] [HttpGet("admin")] public ActionResult AdminController() { return Ok("Hello Admin"); } }

项目运行
使用 Swagger 登录成功后,用户将收到以下内容:

您可以在浏览器中检查 cookie,打开浏览器的检查工具,进入应用程序,然后选择 cookie,您会看到类似这样的内容:

但是,如果您尝试使用以下 JavaScript 代码在浏览器控制台中访问 cookie:
document.cookie 你可能会收到一个空字符串,因为我们在 program.cs 文件中配置了 cookie,Cookie.HttpOnly = true。
如果用户尝试访问无权访问的资源,将被重定向到以下路径:

在本教程中,您注意到我们配置 cookie 以使其在 https 环境中工作,但我运行在 http 环境中,这是因为浏览器将 localhost 视为特殊情况。
如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。



