在 asp .net core web项目中,cookie认证由cookie认证中间Microsoft.AspNetCore.Authentication.Cookies完成,如下:
step 1: 安装cookie认证中间件 安装包
using Microsoft.AspNetCore.Authentication.Cookies;
step 2:配置项目的认证方式为cookie认证
#region 配置cookie认证方式
//see:https://docs.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x
// If you don't want the cookie to be automatically authenticated and assigned to HttpContext.User,
// remove the CookieAuthenticationDefaults.AuthenticationScheme parameter passed to AddAuthentication.
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/Customer/LogIn";
options.LogoutPath = "/Customer/LogOut";
#if !DEBUG
options.Cookie.Domain = ".iaspnetcore.com";//设置Cookie的域为根域,这样所有子域都可以发现这个Cookie
#endif
}
);
#endregion
step 3:启用认证
app.UseAuthentication();
app.UseAuthorization();
step 4:登陆
登陆采用HttpContext.SignInAsync(),我们要做的,只是构造出此函数需要的参数即可。
我们最终要构造的参数是一个ClaimsPrincipal对象。构造过程简述如下:把用户名和用户角色(权限信息)保存到一个claims对象,用claims对象构造出claimsIdentity 对象,用claimsIdentity 对象构造出ClaimsPrincipal对象。
调用HttpContext.SignInAsync方法登陆,登录成功后,这个方法会在HttpContext.Response的Header中响应头中添加Set-Cookie,cookie的内容就是ClaimsPrincipal对象加密后的字符串。
同时把这个ClaimsPrincipal对象保存到HttpContext.User
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginModel model)
{
this.TryValidateModel(model);
if (ModelState.IsValid)
{
//获取用户
var customer = await this._customerService.GetCustomerByUsernameAsync(model.Username.Trim());
if (customer == null)
{
ModelState.AddModelError("LogonUsernameNotExist", "用户名不存在");
return View(model);
}
var encryptPassword = model.Password;
if (customer.PasswordFormat== PasswordFormat.aspMd5)
{
encryptPassword = aspMD5.Encrypt(model.Password, 16);
}
if (!(customer.Password == encryptPassword))
{
ModelState.AddModelError("LogonErrorPassword", "密码不正确");
return View(model);
}
//cookie 登陆
// claims
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.Name, customer.Username));
//角色
foreach (var role in customer.CustomerRoles)
{
//添加角色时使用自带的ClaimTypes.Role就不需要在新建ClaimsIdentity时指定角色验证类型
claims.Add(new Claim(ClaimTypes.Role, role.SystemName));
}
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var authProperties = new AuthenticationProperties
{
};
// 登录
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProperties);
////修改登录信息
customer.LastLoginDateUtc = DateTime.UtcNow;
customer.LastIpAddress = _webHelper.GetCurrentIpAddress();
await this._customerService.UpdateCustomerAsync(customer);
_workContext.CurrentCustomer = customer;
return RedirectToAction("Index", "Home");
}
//If we got this far, something failed, redisplay form
return View(model);
}
NET Core中通过Microsoft.AspNetCore.Authentication.Cookies这个中间件识别HttpContext中认证相关的Cookie,以后浏览器访问时,HttpContext.Request都会带有这个Cookie,Cookie中间件会把Cookie取出来,解密并还原为ClaimsPrincipal对象,并把HttpContext.User设置为这个对象。后面MVC中间件在路由到相应Controller和Action的时候就可以根据Authorize特性中指定的认证和角色在HttpContext.User中进行检查,不满足检查则跳转至相应页面。因此需要注意的就是一定要把Cookie中间件放在MVC中间件之前。
logout
注销很简单,直接调用 _httpContextAccessor.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
注销,其原理是HttpContext.SignOutAsync()会在HttpContext.Response添加Set-Cookie,但cookie内容为空。
public async Task<IActionResult> Logout()
{
//external authentication
//注销 cookie
//and sign out from the current authentication scheme
await _httpContextAccessor.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return RedirectToAction("Index", "Home");
}