ASP.NET Core 使用 Claim 认证

ASP.NET Core Web 应用下:

Program中:

复制代码
#region 配置鉴权
{
    builder.Services.AddAuthentication(option =>
    {
        option.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        option.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        option.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        option.DefaultForbidScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        option.DefaultSignOutScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    }).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, option => {
        option.LogoutPath = "/Account/Login";
    });
}
#endregion

app.UseAuthentication();//鉴权
app.UseAuthorization(); //授权

 
复制代码

 

登录验证结果:

复制代码
        [DataContract]
        [Serializable]
        public class LoginResult
        {
            /// <summary>
            /// 状态码
            /// </summary>
            [DataMember(Name = "statusCode", Order = 2)]
            public int StatusCode { get; set; }
            /// <summary>
            /// 是否访问成功
            /// </summary>
            [DataMember(Name = "isSuccessful", Order = 1)]
            public bool IsSuccess { get; set; }
            /// <summary>
            /// 系统返回状态说明
            /// </summary>
            [DataMember(Name = "message", Order = 3)]
            public string? Message { get; set; }
            /// <summary>
            /// 返回的页面
            /// </summary>
            [DataMember(Name = "returnUrl", Order = 4)]
            public string? ReturnUrl { get; set; }
        }
复制代码

登录验证:

复制代码
   [HttpPost]
        public JsonResult JsonLogin(string username, string password, string num)
        {
            var result = new LoginResult();
            result.IsSuccess = true;
            result.StatusCode = 200;
            result.Message = "";
            string cnum = HttpContext.Session.GetString("ValidateCode") == null ? "" : HttpContext.Session.GetString("ValidateCode");
            if (string.IsNullOrEmpty(num) || num.ToLower() != cnum.ToLower())
            {
                result.StatusCode = 401;
                result.Message = "验证码错误";
                return Json(result);
            }

            if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
            {
                result.StatusCode = 402;
                result.Message = "账号或密码不能为空";
                return Json(result);
            }

            var pass = Helper.GetMd5Str(password);
            var old = _manager.Login(username, pass);
            if (old == null)
            {
                result.Message = "账号密码错误";
                result.StatusCode = 403;
                return Json(result);
            }
            else
            {
                if (!old.IsUse)
                {
                    result.Message = "账号停用";
                    result.StatusCode = 404;
                    return Json(result);
                }
                var claims = new List<Claim>()//鉴别你是谁,相关信息
                    {
                        new Claim("uid",old.ManagerId.ToString()),
                        new Claim(ClaimTypes.Role,old.Role.RoleName),
                        new Claim(ClaimTypes.Role,"Manager"),
                        new Claim(ClaimTypes.Name,$"Manager_INFO"),
                        //new Claim(ClaimTypes.Email,$"1234@163.com"),
                        //new Claim("password",password),//可以写入任意数据
                        //new Claim("Account",old.LoginName),
                        new Claim("NikeName",old.NikeName),
                        new Claim("role",old.Role.RoleName)
                    };
                ClaimsPrincipal userPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, "Manager"));
                HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, userPrincipal, new AuthenticationProperties
                {
                    ExpiresUtc = DateTime.UtcNow.AddMinutes(30),//过期时间:30分钟

                }).Wait();
                return Json(result);
            }
        }
复制代码

我们可以通过在 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 必须用户登录后才能访问。

 
复制代码
        [Authorize]
        public IActionResult Index()
        {
            var user = HttpContext.User;
            //user.Identity.Name
            //user.Identity.AuthenticationType
            StringBuilder sb = new StringBuilder();

            // 遍历获取所有的存储信息
            foreach (var cl in HttpContext.User.Claims)
            {
                sb.AppendLine($"{cl.Type}|{cl.Value}");
            }
            _logger.LogInformation(sb.ToString());
            // 通过便捷的方式获取登录的用户名
            var a = User.Claims.FirstOrDefault(o => o.Type == "role")?.Value;
        
            return View();
        }
复制代码

 

User.Claims中的值

第一种

在view视图中将Claims转换成字典,这样就可以用键值的方式访问

@{

var currUser = User.Claims.ToDictionary(o => o.Type, o => o.Value);

}

@currUser.GetValueOrDefault("Manager")

注:RealName区分大小写

第二种 通过claims的linq查询

@User.Claims.FirstOrDefault(o => o.Type == "Manager")?.Value

注:字符串区分大小写;加问号?的意思是避免为空抛出异常,这里很巧妙。

第三种 通过User的方法

@User.FindFirstValue("Manager") 或 @User.FindFirst("Manager")?.Value

注:不区分大小写;注意问号的用法

综上所述:推荐使用第三种,很简略,另外读取系统ClaimTypes.Role注意引用相对应的命名空间:@using System.Security.Claims;

 

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

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

  • 后续项目肯定会涉及到各个系统之间的统一认证对接,以及与第三方的单点登录对接,这种情景使用 token + redis 的方案比较灵活简单,采用 Cookie 的实现方式比较麻烦。
  • 对于用户请求负载均衡分发的场景,token + redis 的方案是非常好的方案,因为其天然保证所有请求都是无状态的,不需要在负载均衡服务器上配置会话保持,这样负载均衡服务器就可以根据每台应用服务器的负载状况,随意使用任何负载请求分发策略。
  • 对于负载均衡来说, Claim 认证方案就不够灵活了,因为其 Cookie 只能在具体的服务器上进行加解密,从而识别登录用户。如果新的请求被负载均衡服务器分发到另一台应用服务器的话,那么就无法解密 Cookie 从而导致需要频繁重新登录,无法使用网站。只有在负载均衡服务器上配置会话保持,从而实现在一定的时间内将来自同一 ip 的请求分发到固定的应用服务器上,才能解决问题。
posted @   流氓大菠萝  阅读(391)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示