前言

学习ASP.NETCore,原链接

https://www.cnblogs.com/laozhang-is-phi/p/9511869.html

原教程是Core2.2,后期也升级到了Core3.0,但是文章中和GitHub的代码感觉有些乱,一直对应不上,

我创建的项目是Core3.0,而在Swagger中使用JWT一直访问401,此处做个笔记,供以后学习时查看。

参考博文,原链接

https://www.cnblogs.com/CreateMyself/p/11123023.html

步骤

默认映射方式给移除掉

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

 

Core3.0中Swagger使用JWT

Swagger响应头

这里需要Nuget引用Swashbuckle.AspNetCore.Filters,oauth2需要写死,SecurityRequirementsOperationFilter中默认securitySchemaName="oauth2";

未添加该配置时,Bearer一直无法加入到JWT发起的Http请求的头部,无论怎么请求都会是401;

用Postman在Authorization添加了Bearer,就会正常响应,

                #region Token绑定到ConfigureServices
                // 在header中添加token,传递到后台
                c.OperationFilter<SecurityRequirementsOperationFilter>();

                c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
                {
                    Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"",
                    Name = "Authorization",//jwt默认的参数名称
                    In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
                    Type = SecuritySchemeType.ApiKey
                });
                #endregion

 

Core3.0中Swagger使用JWT

 启用权限授权认证服务

            //JWT服务配置
            //读取配置文件
            var audienceConfig = Configuration.GetSection("Audience");
            var symmetricKeyAsBase64 = audienceConfig["Secret"];

            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
                .AddJwtBearer(o =>
                {
                    o.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuerSigningKey = true,
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(symmetricKeyAsBase64)),//参数配置在下边

                        ValidateIssuer = true,
                        ValidIssuer = audienceConfig["Issuer"],//发行人

                        ValidateAudience = true,
                        ValidAudience = audienceConfig["Audience"],//订阅人

                        ValidateLifetime = true,

                        //ClockSkew = TimeSpan.Zero,//这个是缓冲过期时间,也就是说,即使我们配置了过期时间,这里也要考虑进去,过期时间+缓冲,默认好像是7分钟,你可以直接设置为0
                        ClockSkew = TimeSpan.Zero,

                        RequireExpirationTime = true,
                    };
                });

 

Core3.0中Swagger使用JWT

Configure配置

这里的顺序,必须严格遵守

  public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseRouting();

            //启用认证中间件,
            app.UseAuthentication();
            //启用授权中间件,
            app.UseAuthorization();

            #region swagger
            // Enable middleware to serve generated Swagger as a JSON endpoint.
            app.UseSwagger();

            // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
            // specifying the Swagger JSON endpoint.
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
            });
            #endregion

            app.UseEndpoints(endpoints =>
            {
                //endpoints.MapControllers();

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

 

Core3.0中Swagger使用JWT

 授权方法

这里的区别,jwt对象,多加了audience和expires属性。

audience:就是配置的值,

expires:JWT过期时间,经过测试,JWT过期时间=expires + ClockSkew。并不是claims中的JwtRegisteredClaimNames.Exp去控制的过期时间

        public static string IssueJWT(TokenModel tokenModel, TimeSpan expiresSliding, TimeSpan expiresAbsoulte)
        {
            var Issuer = "Blog.Core";
            var Audience = "wr";
            var Secret = "sdfsdfsrty45634kkhllghtdgdfss345t678fs";

            var dateTime = DateTime.UtcNow;

            var claims = new Claim[]
                {
                    //下边为Claim的默认配置
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                new Claim(JwtRegisteredClaimNames.Iat, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),
                new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
                //这个就是过期时间,目前是过期100秒,可自定义,注意JWT有自己的缓冲过期时间
                new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddSeconds(180)).ToUnixTimeSeconds()}"),
                new Claim(JwtRegisteredClaimNames.Iss,Issuer),
                new Claim(JwtRegisteredClaimNames.Aud,Audience),
                //这个Role是官方UseAuthentication要要验证的Role,我们就不用手动设置Role这个属性了
                new Claim(ClaimTypes.Role,tokenModel.Role),
                new Claim(ClaimTypes.Name, tokenModel.Uname),
                new Claim(JwtRegisteredClaimNames.Email, tokenModel.EMail),
                new Claim(JwtRegisteredClaimNames.Sub,tokenModel.Sub),
               };

            //秘钥
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Secret));

            var jwt = new JwtSecurityToken(
                issuer: Issuer,
                audience: Audience,
                claims: claims,
                expires: DateTime.Now.AddMinutes(1),
                signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)
                );
            var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

            return encodedJwt;
        }

 

Core3.0中Swagger使用JWT

 appsetting.json

  "Audience": {
    "Secret": "sdfsdfsrty45634kkhllghtdgdfss345t678fs", //不要太短,16位+
    "SecretFile": "C:\\my-file\\blog.core.audience.secret.txt", //安全。内容就是Secret
    "Issuer": "Blog.Core",
    "Audience": "wr"
  }

 

Core3.0中Swagger使用JWT

 Postman测试

Authorization => Bearer Token => Token,这里输入登录时生成的Token值,不需要带Bearer 前缀

Core3.0中Swagger使用JWT

Postman 示例

Core3.0中Swagger使用JWT

 

 Core3.0中Swagger使用JWT

 Swagger示例

Core3.0中Swagger使用JWT

 

 Core3.0中Swagger使用JWT

 

 Core3.0中Swagger使用JWT

 Fiddler监视

Core3.0中Swagger使用JWT

 

 

Core3.0中Swagger使用JWT

Roles配置权限

用户的Role,与访问接口配置的Roles不一致,也就是没有访问权限,访问时会响应为403

Core3.0中Swagger使用JWT

总结

调用接口一直401

JWT配置需要验证的东西,

Core3.0中Swagger使用JWT

 

 一直401,可能是JWT中未包含上面配置的全部参数

相比较之前,又传递了audience和expires参数,这样访问接口验证必传参数才能通过。

Core3.0中Swagger使用JWT

 授权

三种方式

(1)基于角色

(2)基于Claim声明

(3)基于自定义的类

目前,前2个都测试通过的,第三个需要配合创建其他的东西,未实现。

 

            services.AddAuthorization(options =>
            {
                //1.基于角色
                options.AddPolicy("Client", policy => policy.RequireRole("Client").Build());
                options.AddPolicy("Admin", policy => policy.RequireRole("Admin").Build());
                //Client或者Admin
                options.AddPolicy("ClientOrAdmin", policy => policy.RequireRole("Client", "Admin").Build());
                //Client并且Admin
                options.AddPolicy("ClientAndAdmin", policy => policy.RequireRole("Client").RequireRole("Admin").Build());

                //2.基于声明
                options.AddPolicy("AdminClaim2", policy => policy.RequireClaim(ClaimTypes.Name, "Yasuo", "Leesnn").Build());

                //3.基于需要Requirement
                //options.AddPolicy("AdminRequirement", policy => policy.Requirements.Add(new AdminRequirement() { UName = "Kate" }));
            });

 

        /// <summary>
        /// 获取数据,需要授权
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        [Authorize(Policy = "AdminClaim2")]
        [HttpPost("{name}")]
        public string PostUser(string name)
        {
            var sub = User.FindFirst(d => d.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name")?.Value;

            name += "---" + sub ?? "";

            return name + DateTime.Now.ToLongTimeString();
        }

 

 

Core3.0中Swagger使用JWT

 

 Core3.0中Swagger使用JWT

 

相关文章: