目录

  1. 如何使用角色,用户,策略,等进行验证
  2. jwt自定义逻辑验证和上面原生的验证对比

学有所得

  1. 使用jwt自定义完整自己任何想要的严谨认证
  2. 了解原生验证的本质

如何使用角色,用户,策略,等进行验证

经过前篇的介绍,大家对jwt应该有很清晰的认识了,接下来我们如何让代码更清晰,以便以后面的扩展和对比;

首先,我们先把一篇的自定义策略验证进行封装,放到一个静态扩展方法中去,和上一节还是有点区别,多加了一点东西,如下:

    public static class ConfigServiceExtension
    {
        public static void AddInnerAuthorize(this IServiceCollection services, IConfiguration config)
        {
           
            services.AddAuthorization(option =>
            {
                //自定义一些策略,原理都是基于申明key和value的值进行比较或者是否有无
                #region 键值对对比的一些验证策略
                option.AddPolicy("onlyRober", policy => policy.RequireClaim("name", "rober"));
                option.AddPolicy("onlyAdminOrSuperUser", policy => policy.RequireClaim(ClaimTypes.Role, "Admin", "SuperUser"));
                //多申明共同,申明中包含aud:rober或者申明中值有等于Rober的都可以通过
                option.AddPolicy("multiClaim", policy => policy.RequireAssertion(context =>
                {
                    return context.User.HasClaim("aud", config["JwtOption:Audience"]) || context.User.HasClaim(c => c.Value == config["JwtOption:Name"]);
                }));
                #endregion

                #region 自定义验证策略
                option.AddPolicy("ageRequire", policy => policy.Requirements.Add(new AgeRequireMent(20)));
                option.AddPolicy("common", policy => policy.Requirements.Add(new CommonAuthorize()));
                #endregion


            }).AddAuthentication(option =>
            {
                option.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(option =>
            {
                if (!string.IsNullOrEmpty(config["JwtOption:SecurityKey"]))
                {
                    TokenContext.securityKey = config["JwtOption:SecurityKey"];
                }
                //设置需要验证的项目
                option.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,//是否验证Issuer
                    ValidateAudience = true,//是否验证Audience
                    ValidateLifetime = true,//是否验证失效时间
                    ValidateIssuerSigningKey = true,//是否验证SecurityKey
                    ValidAudience = config["JwtOption:Audience"],//Audience
                    ValidIssuer = config["JwtOption:Issuer"],//Issuer,这两项和前面签发jwt的设置一致
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(TokenContext.securityKey))//拿到SecurityKey
                };
            });

            //自定义策略IOC添加
            services.AddSingleton<IAuthorizationHandler, AgeRequireHandler>();
            services.AddSingleton<IAuthorizationHandler, CommonAuthorizeHandler>();
        }
    }

    /// <summary>
    /// jwt配置项目(从配置文件中初始化)
    /// </summary>
    public class JwtOption
    {
        public string Issuer { get; set; } = "rober";
        public string Audience { get; set; } = "rober";
        public TimeSpan Expiration { get; set; } = TimeSpan.FromMinutes(50);
        public string SecurityKey { get; set; } = "www.rober.com(welcome you)";
        public string Name { get;  set; }
    }

第一、在以前的基础上添加了几个简单的自定义策略(onlyRober,onlyAdminOrSuperUser,multiClaim),

  1. onlyRober:jwt的申明部分有name=rober就能通过,也就是payLoad["name"]="rober"
  2. onlyAdminOrSuperUser:只有Admin和SuperUser角色的用户才能通过,实质上就是payLoad["http://schemas.microsoft.com/ws/2008/06/identity/claims/role"]="Admin"或者“SuperUser”;
  3. multiClaim:多申明同时满足,实质上也就是payLoad["aud"]=“roberAudience”(通过config["JwtOption:Audience"]获取),或者,有name这个申明项,payLoad["name"],不管它的值是多少,当然这里的或者,也可以改为并且,把||改为&&,请仔细看上面的验证diamante

第二、还有个自定义策略AgeRequireMent,这个和上一篇讲的类似,也是两个重要的类组成(AgeRequireHandler 和 AgeRequireMent )请自行参考代码,如下:

 /// <summary>
    /// 访问者年龄要求自定义策略
    /// </summary>
    public class AgeRequireHandler : AuthorizationHandler<AgeRequireMent>
    {

        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AgeRequireMent requirement)
        {

            if (!context.User.HasClaim(c => c.Type == "age"))
            {
                return Task.CompletedTask;
            }
            int.TryParse(context.User.Claims.FirstOrDefault(c => c.Type == "age").Value, out int age);

            if (age >= requirement.Age)
            {
                context.Succeed(requirement);//标识验证成功

            }
            return Task.CompletedTask;
        }
    }
    public class AgeRequireMent : IAuthorizationRequirement
    {
        public int Age { get; set; }
        public AgeRequireMent(int age) => this.Age = age;
    }
View Code

相关文章: