Cookie 的授权认证是一种兼容性较高的一种方式,并且前端请求中无需额外配置,也会在 Header 中自动带上程序生成针对用户唯一标识的加密Cookie

下面是基于 .Net Core 的实现方式

第一步,在 Startup.cs 添加中间件
ConfigureServices 中

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).
    AddCookie(option =>
    {
        option.LoginPath = new PathString("/api/login");//未登录时,进行跳转的url
        option.AccessDeniedPath = new PathString("/api/login");//身份认证不通过时,进行跳转的url
        option.ExpireTimeSpan = TimeSpan.FromDays(1);//指定Cookie的过期时间
        option.SlidingExpiration = true;//当Cookie过期时间已达一半时,是否重置为ExpireTimeSpan
        option.Cookie.Name = "AuthCookie";//Cookie的名称
    }
);

Configure 中

app.UseAuthentication();//必须在 app.UseMvc(); 前面
app.UseMvc();

第二步,登陆

[HttpGet("Login")]
public async Task Login(string userName,string pwd)
{ 
    //Todo
    //校验账号密码是否正确

    //用户身份
    var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);

    identity.AddClaim(new Claim(ClaimTypes.Name, userName)); //取值 User.Identity.Name
    identity.AddClaim(new Claim(ClaimTypes.UserData, "用户账号其他数据")); // User.Claims.Select(t => new { t.Type, t.Value }).ToList();
    identity.AddClaim(new Claim(ClaimTypes.Role, "admin"));// 用于区分账号权限,如[Authorize(Roles = "admin")]

    //用户登录成功后颁发一个证书(加密的用户凭证),用来标识用户的身份,该凭证(cookie)将会写入到客户端浏览器
    await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity), new AuthenticationProperties
    {
        IsPersistent = true, //true:保持登陆不过期 false:关闭浏览器就过期
        ExpiresUtc = DateTime.UtcNow.AddDays(1),//过期时间
        AllowRefresh = true
    });

    return "succeed";
}

第三步,API的授权控制
如果此时未登录,访问该 api 的话会跳转到 LoginPath 指定的url
如果此时已登录,但 Roles 不为 “admin” 的情况下,访问该 api 的话会跳转到 AccessDeniedPath 指定的url

如果是通过异步请求,则会返回 http 401 Unauthorized 的错误

需要注意的是,跨域的异步请求是直接返回 http 302 重定向的,这个与 CookieAuthenticationEvents 类的处理方式有关,代码中有关于是否是 Ajax 请求的判断,如果请求的 QueryString 或者 Header 中包含 X-Requested-With 并且值为 XMLHttpRequest 的话, 则会被判断为 AjaxRequest , 将不会返回重定向结果
所以,解决办法有两种

一种是在请求的头部 headers 加上 ‘X-Requested-With’:”XMLHttpRequest” 即可

[HttpGet("AdminWelcome")]
[Authorize(Roles = "admin")]
public string AdminWelcome()
{
    var user = HttpContext.User.Identity.Name;
    return $"welcome "{user};
}

 

另外一种是 AddAuthentication 中针对这种会自动跳转的情况进行事件重写,直接返回 401

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).
AddCookie(option =>
{
    option.LoginPath = new PathString("/home/admin");//登陆地址
    option.AccessDeniedPath = new PathString("/home/admin");//授权不通过跳转地址
    option.ExpireTimeSpan = TimeSpan.FromDays(1);//指定Cookie的过期时间
    option.SlidingExpiration = true;//当Cookie过期时间已达一半时,是否重置为ExpireTimeSpan
    option.Cookie.Name = "AuthCookie";//cookie名称
    option.Events.OnRedirectToAccessDenied = option.Events.OnRedirectToLogin = c =>
    {
        c.Response.StatusCode = StatusCodes.Status401Unauthorized;
        return Task.FromResult<object>(null);
    };
});