Net Core教程

ASP.NET Core 使用 Claim 认证详解

本文主要是介绍ASP.NET Core 使用 Claim 认证详解,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

微软在早期 .NET Framework 时代,针对 ASP.NET 的用户登录身份认证,提供了 Forms 认证实现方案。后来在推出 ASP.NET Core 之后,采用 Claim 认证替代了 Forms 认证,两者本质上都是基于 Cookie 加解密的认证方式,学习和使用起来非常简单,比较适合在小型项目中使用,主要是方便。

假设我们现在已经创建好了一个基于 .NET5 模型-视图-控制器ASP.NET Core Web 应用 (这里就不介绍创建过程了),下面我就基于 .NET5 网站,介绍一下 Claim 认证的具体实现方式:


1 修改 appsettings.json 配置文件,增加有关 Cookie 的相关配置

在实际开发场景中,我们一般将 Cookie 相关信息进行配置,所以我们增加以下配置信息:

{
  // 这里采用了两级嵌套的 json 配置方式
  "web": {
    // 用户未登录时,自动跳转的目标路由地址
    "loginUrl": "/Home/Login", 
    // Cookie 的名字
    "cookieName": "UserAuth",
    // Cookie 保存的路径,这里保存在根路径
    "cookiePath": "/",
    // Cookie 的所属的域名
    "cookieDomain": ".demo.com"
  }
}

其实上面的 json 配置中, Cookie 的保存路径,所属域名,都可以配置为空,这样不影响 Claim 认证的实现。

但是有一种情况例外,那就是万恶的 IE 浏览器。对于 IE 浏览器来说,上面的 json 配置中,必须配置好 Cookie 的保存路径和域名,否则无法生成 Cookie,无法实现 Claim 认证。

如果你实施的项目不考虑 IE 浏览器的话,那就很幸运了。但是目前国内的很多银行、政府、国企,未来很长一段时间仍然还在使用 IE 浏览器,所以有时候还得被迫考虑 IE 浏览器。


2 修改 Startup.cs 文件,增加 Claim 认证支持

需要修改两个地方 ConfigureServices 方法Configure方法

ConfigureServices 方法 中添加 Cookie 认证方式,在 Configure方法 中使用认证和授权。

注意:Configure 方法每行代码的顺序位置很重要,新增加的两行代码(app.UseAuthentication 和 app.UseAuthorization 必须在 app.UseRouting 之后,app.UseEndpoints 之前)

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    //添加 Cookie 认证方式
    services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => 
    {
        //从配置节中读取配置的 Cookie 信息
        options.LoginPath = Config["web:loginUrl"];
        options.Cookie.Name = Config["web:cookieName"];
        options.Cookie.Path = Config["web:cookiePath"];
        options.Cookie.Domain = Config["web:cookieDomain"];
    });
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseStaticFiles();
    app.UseRouting();

    //使用认证和授权
    app.UseAuthentication();
    app.UseAuthorization();

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

3 在相关 Controller 中的 Action 方法添加 Claim 认证的代码

假设我们在登录页面,输入了用户名密码,提交到后台的 Home/Login 中,该 Action 已经在数据库中验证了用户名和密码的正确性,接下来就要生成 Claim 认证的 Cookie,代码如下:

public IActionResult Login(string name, string pwd)
{
    //......此处省略了去数据库验证用户名和密码,以及获取用户的权限的相关代码

    //可以添加额外的信息存储在cookie中
    //这里把从数据库中获取的【用户角色】和【权限码】进行存储
    var claims = new[] { new Claim("Power", power), new Claim("Role", role) };

    //这里存储【用户名】
    //这样后面就可以通过 User.Identity.Name 获取到用户名了
    GenericIdentity gi = new GenericIdentity(name);
    ClaimsIdentity ci = new ClaimsIdentity(gi, claims, 
        CookieAuthenticationDefaults.AuthenticationScheme, "", "");
    ClaimsPrincipal cp = new ClaimsPrincipal(ci);

    Task.Run(async () =>
    {
        //生成 Cookie 并保存到硬盘中,指定 Cookie 的过期时间
        await HttpContext.SignInAsync(
        CookieAuthenticationDefaults.AuthenticationScheme,cp, new AuthenticationProperties()
        {
            IsPersistent = true,
            ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(60),
            AllowRefresh = true
        });
    }).Wait();
    return Content("login success");
}

前端通过 Ajax 调用后端登录方法后,如果成功,然后跳转到网站主页即可。


4 控制 Controller 和 Action 的访问

我们可以通过在 Controller 上或 Action 上增加 [Authorize] 标记 或 [AllowAnonymous] 标记,来控制用户对具体 Controller 或 Action 的访问,这跟以前的 Forms 认证的控制方式一模一样。

[Authorize] 标记:

表示必须拥有 Claim 的 Cookie 才能访问,否则就会跳转到指定的页面,我们一般指定跳转到登录页面。可以放到 Controller 或 Action 上。如果该标记添加到 Controller 上,则该 Controller 下的所有 Action 都会验证是否拥有 Claim 的 Cookie。

[AllowAnonymous] 标记:

表示允许匿名用户访问,没有登录也可以访问,也就是不需要 Claim 的 Cookie 就可以访问。可以放到 Controller 或 Action 上。通常的使用场景是:在 Controller 上放了 [Authorize] 之后,在该 Controller 下具体的一小部分 Action 上放 [AllowAnonymous] 标记。这样就保证 Controller 下只有一小部分 Action 允许未登录用户访问,其它的 Action 必须用户登录后才能访问。


5 获取 Claim 的 Cookie 中的信息以及退出登录

在上面第 3 步中,我们通过 GenericIdentity gi = new GenericIdentity(name) 这行代码存储登录的用户名,因此我们可以通过 User.Identity.Name 获取到登录的用户名。

下面列出获取 Cookie 中存储的其它信息,比如上面存储的 Power 和 Role

[Authorize]
public IActionResult Display()
{
    StringBuilder sb = new StringBuilder();

    // 遍历获取所有的存储信息
    foreach (var cl in HttpContext.User.Claims)
    {
        sb.AppendLine($"{cl.Type}|{cl.Value}");
    }

    // 通过便捷的方式获取登录的用户名
    sb.AppendLine(User.Identity.Name);

    // 想要获取到具体的一项存储信息,比如仅仅想获取权限码和角色
    sb.AppendLine(User.FindFirstValue("Power"));
    sb.AppendLine(User.FindFirstValue("Role"));

    return Content(sb.ToString());
}

如果想要用户退出登录,销毁 Cookie 的话,可以采用以下代码:

public IActionResult LogOut()
{
    if (User.Identity.IsAuthenticated)
    {
        Task.Run(async () => { await HttpContext.SignOutAsync(); }).Wait();
    }

    //销毁 Claim 的 Cookie 后,可以跳转到登录页面
    return RedirectToAction("Index", "Web");
}

6 优缺点闲谈

到此为止,ASP.NET Core 网站使用 Claim 认证的方式,实现用户登录,访问时进行身份认证方案,已经介绍完了。如果你想要快速搭建轻量级网站应用的话,使用 Claim 认证方式是一种非常方便快速的方案。

但是不建议在大中型项目中使用,还是采用主流的 token + redis 的方案实现用户登录认证比较好,原因如下:

  • 后续项目肯定会涉及到各个系统之间的统一认证对接,以及与第三方的单点登录对接的话,这种情景使用 token + redis 的方案比较灵活简单。
  • 对于用户请求负载均衡分发的场景,token + redis 的方案是非常好的方案,因为其天然保证所有请求都是无状态的,不需要在负载均衡服务器上配置会话保持,这样负载均衡服务器就可以根据每台应用服务器的负载状况,随意使用任何负载请求分发策略。
  • 对于负载均衡来说, Claim 认证方案就不够灵活了,因为其 Cookie 只能在具体的服务器上进行加解密,从而识别登录用户。如果新的请求被负载均衡服务器分发到另一台应用服务器的话,那么就无法解密 Cookie 从而导致需要频繁重新登录,无法使用网站。只有在负载均衡服务器上配置会话保持,从事实现在一定的时间内将来自同一 ip 的请求分发到固定的应用服务器上,才能解决问题。(具体在各个不同的服务器之间,如何实现 Claim 的 Cookie 采用统一的加解密算法,我个人没有研究过。其实也没必要研究了,因为我们大部分情况下都会使用目前比较流行的 token + redis 方案,能够轻松解决任何问题)


这篇关于ASP.NET Core 使用 Claim 认证详解的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!