• Core3.0中Swagger使用JWT


    前言

    学习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();

    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

     启用权限授权认证服务

                //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,
                        };
                    });

    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?}");
                });
            }

     授权方法

    这里的区别,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;
            }

     appsetting.json

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

     Postman测试

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

    Postman 示例

     

     Swagger示例

     

     

     Fiddler监视

    Roles配置权限

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

    总结

    调用接口一直401

    JWT配置需要验证的东西,

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

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

     授权

    三种方式

    (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();
            }

     

  • 相关阅读:
    Uva11235
    Uva11300/BZOJ1045/BZOJ1465/BZOJ3292
    树形背包模板
    Miller-Rabin素性测试
    BZOJ1500 : [NOI2005]维修数列-fhq_Treap
    COGS2421 [HZOI 2016]简单的Treap
    用 fhq_Treap 实现可持久化平衡树
    hdu 1010(DFS) 骨头的诱惑
    hdu 1026(BFS+输出路径) 我要和怪兽决斗
    hdu 1072(BFS) 有炸弹
  • 原文地址:https://www.cnblogs.com/masonblog/p/13055540.html
Copyright © 2020-2023  润新知