【学习笔记】Core5 WebApi 加入JWT 验证

【学习笔记】Core5 WebApi 加入JWT 验证,第1张

【学习笔记】Core5 WebApi 加入JWT 验证

        初学WebApi,为了实现登录,最开始的想法是加入Session,不过新建的WebApi项目中没有自动引入Session,然后在搜索资料时发现,WebApi最好使用主流验证模式JWT 来验证登录,这样可以适应多种验证环境 比如APP  移动Web  对外接口。

当然JWT也有缺点,比如它不像Session那样 用户请求后会刷新过期时间,这个需要手动配置代码去刷新ToKen。

关于什么是JWT 这里不再描述,详细可以见下面链接,这里只写代码实现

ASP.NET Core 认证与授权[4]:JwtBearer认证 - 雨夜朦胧 - 博客园

直接进入正题

新建一个 WebApi项目

我这里项目取名为  JWTTest

配置HTTPS 勾不勾感觉无所谓,我这里OpenAPI勾上,是为了自动创建Swagger 测试页的

项目的初始结构。

首先在NuGet 安装下面两个依赖包

1,JwtBearer

2,IdentityServer4.AccessTokenValidation

第一步:配置 appsettings.json

        这步根据你自己的需求来配置,我这里就是把key 存在配置文件里,也可以存在数据库或者其他地方。

  "lConfig_JWTOptions": {
    "Issuer": "http://localhost:44309",
    "Audience": "api",
    "key": "aaaaaaaaaaaaaaaaa"
  }

 红色框就是配置代码

lConfig_JWTOptions  是自定义名字

第二步:配置 Startup.cs

        顺带提一下 Startup.cs 就相当于Web.config ,就以前的xml 变成类的形式来配置。

        1,先从配置文件里读出 自定义key

ConfigureServices 方法:

   public void ConfigureServices(IServiceCollection services)
        {
            //获取配置文件中Config_JWTOptions的key
            var myKey= Configuration.GetSection("Config_JWTOptions").GetChildren().FirstOrDefault(a => a.Key.Equals("key")).Value;
            //开启 JWT 验证
            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(o =>
            {
                o.TokenValidationParameters = new TokenValidationParameters
                {
                    //配置JWT验证
                    NameClaimType = JwtClaimTypes.Name,
                    RoleClaimType = JwtClaimTypes.Role,

               //这里是会跟JwtClaimTypes.Issuer校验,这里值我测试过 填个AAA啥的都可以
               //只要跟JwtClaimTypes.Issuer的值保持一致就行了。
                    ValidIssuer = "http://localhost:44309", 
            
                //这里是跟JwtClaimTypes.Audience 的值校验,也是可以随便填可以,保存一致就行。
                    ValidAudience = "api",

                   IssuerSigningKey = new            
                  SymmetricSecurityKey(Encoding.ASCII.GetBytes(myKey))

                    
                    // RequireSignedTokens = true,
                    // SaveSigninToken = false,
                    // ValidateActor = false,
                    // 将下面两个参数设置为false,可以不验证Issuer和Audience,但是不建议这样做。
                    // ValidateAudience = true,
                    // ValidateIssuer = true, 
                    // ValidateIssuerSigningKey = false,
                    // 是否要求Token的Claims中必须包含Expires
                    // RequireExpirationTime = true,
                    // 允许的服务器时间偏移量
                    // ClockSkew = TimeSpan.FromSeconds(300),
                    // //是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比
                    // ValidateLifetime = true
                };
            });
            services.AddControllers();
        }

             3,JWT使用起来

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
      if (env.IsDevelopment())
      {
           app.UseDeveloperExceptionPage();
           app.UseSwagger();
           app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "JWTTest v1"));
      }

      app.UseRouting();

      //使用JWT验证
      app.UseAuthentication();

      app.UseAuthorization();

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

                注意:app.UseXXXx() 是有先后顺序的,我这里是放在了UseRouting后面,UseAuthorization的前面。

    

  第三步:控制器配置验证,我这里就直接用自动创建的控制器WeatherForecastController

        可以先测试下  上面的JWT配置 有没有生效

先运行启动,请求一下WeatherForecast,请求成功是返回状态码200的。

这里之所以是成功,因为还没有给这个请求加上验证

1,给Get方法 加上[Authorize] 就会开启验证

然后再来请求一次测试下, 请求返回的状态码就是401了,没有权限。

2,开始配置生成Token,  新写一个方法 Login_GetToken,模拟登录一下

  [HttpPost]
 public IActionResult Login_GetToken(String userName, String password)
 {
            //假设账号和密码都是demo  否则验证失败
            if (!userName.Equals("demo") || !password.Equals("demo"))
            {
                return Unauthorized();//登录失败 返回状态码 401
            }

            //登录成功,生成ToKen
            var tokenHandler = new JwtSecurityTokenHandler();
            var authTime = DateTime.UtcNow;
            var expiresAt = authTime.AddDays(7);
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[]
                {
                    new Claim(JwtClaimTypes.Audience, "api"),
                    new Claim(JwtClaimTypes.Issuer, "http://localhost:44309"),
                    new Claim(JwtClaimTypes.Id, "1001"),
                    new Claim(JwtClaimTypes.Name, userName),
                   // new Claim(JwtClaimTypes.Email, "[email protected]"),//根据需求填
                    //new Claim(JwtClaimTypes.PhoneNumber,"13600000000")
                }),
                Expires = expiresAt,
                SigningCredentials = new SigningCredentials(new         
                 SymmetricSecurityKey(Encoding.ASCII.GetBytes("aaaaaaaaaaaaaaaaa")), 
                SecurityAlgorithms.HmacSha256Signature)

            };
            var token = tokenHandler.CreateToken(tokenDescriptor);
            var tokenString = tokenHandler.WriteToken(token);
            return Ok(new
            {
                access_token = tokenString,
                token_type = "Bearer",
                profile = new
                {
                    sid = "1001",
                    name = userName,
                    auth_time = new DateTimeOffset(authTime).ToUnixTimeSeconds(),
                    expires_at = new DateTimeOffset(expiresAt).ToUnixTimeSeconds()
                }
            });

}

最后再测试一下登录:登录成功后会返回token

下次请求带上这个Token 就可以正常访问了。

最后:

        如果要带上token去测试前面配置的Get()方法,需要先配置Swagger页的Authorize支持

在 Startup 中 ConfigureServices 方法:

   services.AddSwaggerGen(c =>
   {
                    c.SwaggerDoc("v1", new OpenApiInfo { Title = "JWTTest", Version = 
                    "v1" });
                    //swagger启动JWT验证
                    var sec = new OpenApiSecurityScheme
                    {
                        Description = "JWT Authorization header using the Bearer scheme. Example: "Authorization: Bearer {token}"",
                        Name = "Authorization",
                        In = ParameterLocation.Header,
                        Type = SecuritySchemeType.Http,
                        Scheme = "Bearer",
                        BearerFormat = "JWT"
                    };
         //把所有方法配置为增加bearer头部信息
         var securityRequirement = new OpenApiSecurityRequirement
         {
             {
                  new OpenApiSecurityScheme
                  {
                       Reference = new OpenApiReference
                       {
                            Type = ReferenceType.SecurityScheme,
                            Id = "bearerAuth"
                       }
                 },
                 new string[] {}
             }
         };

        //注册到swagger中
       c.AddSecurityDefinition("bearerAuth", sec);
       c.AddSecurityRequirement(securityRequirement);
 });

再次启动时,每个接口后面 就会有一把锁,就说明配置成功了。

点击锁,就可以带上token 去请求接口

 

这个Demo比较乱,不过初步的实现了JWT 验证,后期可以把生成Token封装一个类里。配合注入依赖和 appsettings.json  就可以把代码变的很整洁也容易维护了。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5661042.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存