前言

上一篇文章介绍ASP.NET Core Authentication的三个重要概念,分别是Claim, ClaimsIdentity, ClaimsPrincipal,以及claims-base authentication是怎么工作的。

这篇文章来介绍一下如何基于claims-base authentication来实现认证、登录和注销功能的。源代码从这里下载。

认证票据

认证是一个确定发送请求的访问者身份的过程,与认证相关的还有另外两个基本操作:登录和注销。

ASP.NET Core应用的认证实现在一个名为AuthenticationMiddleware的中间件中,该中间件在处理分发给它的请求时会按照指定的 认证方案(Authentication Scheme) 从请求中提取能够验证用户真实身份的数据,我们一般将该数据称为 安全令牌(Security Token) 。ASP.NET Core应用下的安全令牌被称为 认证票据(Authentication Ticket) ,所以ASP.NET Core应用采用基于票据的认证方式。

AuthenticationMiddleware中间件的整个认证过程涉及下图的三种操作:认证票据的颁发、检验和撤销。

image

ASP.NET Core应用的认证系统旨在构建一个标准的模型来完成针对请求的认证以及与之相关的登录和注销操作。接下来我们就通过一个简单的实例来演示如何在一个ASP.NET Core应用中实现认证、登录和注销的功能。

基于Cookie的认证

大多数Web应用采用的是Cookie来保存认证票据,因此我们采用基于Cookie的认证方案。

配置

Startup.ConfigureServices方法里,添加AuthenticationMiddleware中间件:

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

然后在Startup.Configure方法里,调用UseAuthenticationUseAuthorization来设置HttpContext.User属性以及允许请求经过AuthenticationMiddleware,并且要在UseEndpoints之前调用:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // ...
    
    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
        
    // ...
}
    

登录

接下来实现登录方法,常见是使用“用户名+密码”,这里使用一个静态字典来模拟用户表。

public class AccountController : Controller
{
    // ....

    private static Dictionary<string, string> _accounts;

    static AccountController()
    {
        _accounts = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        _accounts.Add("Foo", "password");
        _accounts.Add("Bar", "password");
        _accounts.Add("Baz", "password");
    }

    [HttpGet]
    public IActionResult Login()
    {
        LoginModel model = new LoginModel();

        return View(model);
    }

    [HttpPost]
    public async Task<IActionResult> Login(LoginModel model)
    {
        if (_accounts.TryGetValue(model.UserName, out var pwd) && pwd == model.Password)
        {
            var claimsIdentity = new ClaimsIdentity(
                new Claim[] { new Claim(ClaimTypes.Name, model.UserName) }, "Basic");
            var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);                
            await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal);

            return Redirect("/");
        }
        else
        {
            model.ErrorMessage = "Invalid user name or password!";

            return await Task.Run(() => View(model));
        }
    }

    // ....
}

这段代码的关键在于下面三行代码:

  1. 创建ClaimType为Name,值为用户名的Claim。
  2. 创建ClaimsIdentity,注意AuthorizeType="Basic"。
  3. 创建ClaimsPrincipal。
  4. 调用HttpContext.SignInAsync登录,其中认证方案为CookieAuthenticationDefaults.AuthenticationScheme,与配置时一致。
var claimsIdentity = new ClaimsIdentity(
    new Claim[] { new Claim(ClaimTypes.Name, model.UserName) }, "Basic");
var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); 
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal);

认证

需要授权访问的功能要验证登录状态,如果没有登录则不允许访问,使用方法很简单,只需要在Action上加上特性[Authorize]

[Authorize]
public IActionResult Index()
{
    return View();
}

未登录会跳转到/Account/Login(默认设置,可修改),避免未授权访问。

注销

用户注释,即将具有认证票据的Cookie设置为过期,直接调用HttpContext.SignOutAsync,注意认证方案要与配置和登录的一致:CookieAuthenticationDefaults.AuthenticationScheme

public class AccountController : Controller
{
    // ....

    public async Task<IActionResult> Logout()
    {
        _logger.LogInformation("User {Name} logged out at {Time}.",
                User.Identity.Name, DateTime.UtcNow);

        await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

        return Redirect("/");
    }
    
    // ....
}

参考资料

 
 以上内容来源于网络
posted on 2020-11-02 11:40  湖东  阅读(161)  评论(0编辑  收藏  举报