.Net Core6.0 WebAPI项目框架搭建五:JWT权限验证

 完整框架项目源码地址:https://download.csdn.net/download/yigu4011/87788956?spm=1001.2014.3001.5503

 

JWT是什么?校验逻辑?授权过程?这里就不过多的阐述了,直接上代码

在appsettings.json中配置jwt参数的值 

SecretKey必须大于16个字符

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "AppSettings": {
    //数据库连接字符串
    "ConnectionString": "server=192.168.132.131;uid=sa;pwd=6014359wQ@!;database=MagCoreDB",
    "JwtSetting": {
      "Issuer": "jwtIssuer", //颁发者
      "Audience": "jwtAudience", //可以给哪些客户端使用
      "SecretKey": "yehjsiwkjhuhgyehsnd" //加密Key
    }
  }
}

Nuget安装以下三个包:

.Net Core6.0 WebAPI项目框架搭建五:JWT权限验证_第1张图片

在web.core.model中新建类TokenModel:

/// 
    /// 令牌
    /// 
    public class TokenModel
    {
        /// 
        /// Id
        /// 
        public string Uid { get; set; }
        /// 
        /// 角色
        /// 
        public string Role { get; set; }

    }

新建JwtHelper.cs帮助类 

public class JwtHelper
    {
        /// 
        /// 颁发JWT字符串
        /// 
        /// 
        /// 
        public static string IssueJwt(TokenModel tokenModel)
        {
            //获取Appsetting配置
            string iss = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Issuer" });
            string aud = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Audience" });
            string secret = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "SecretKey" });

            //var claims = new Claim[] //old
            var claims = new List
                {
                 /*
                 * 特别重要:
                   1、这里将用户的部分信息,比如 uid 存到了Claim 中,如果你想知道如何在其他地方将这个 uid从 Token 中取出来,请看下边的SerializeJwt() 方法,或者在整个解决方案,搜索这个方法,看哪里使用了!
                   2、你也可以研究下 HttpContext.User.Claims ,具体的你可以看看 Policys/PermissionHandler.cs 类中是如何使用的。
                 */
                new Claim(JwtRegisteredClaimNames.Jti, tokenModel.Uid.ToString()),
                new Claim(JwtRegisteredClaimNames.Iat, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),
                new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
                //这个就是过期时间,目前是过期1000秒,可自定义,注意JWT有自己的缓冲过期时间
                new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddSeconds(1000)).ToUnixTimeSeconds()}"),
                new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(1000).ToString()),
                new Claim(JwtRegisteredClaimNames.Iss,iss),
                new Claim(JwtRegisteredClaimNames.Aud,aud),

               };

            // 可以将一个用户的多个角色全部赋予;
            claims.AddRange(tokenModel.Role.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));



            //秘钥 (SymmetricSecurityKey 对安全性的要求,密钥的长度太短会报出异常)
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            var jwt = new JwtSecurityToken(
                issuer: iss,
                claims: claims,
                signingCredentials: creds);

            var jwtHandler = new JwtSecurityTokenHandler();
            var encodedJwt = jwtHandler.WriteToken(jwt);

            return encodedJwt;
        }

        /// 
        /// 解析
        /// 
        /// 
        /// 
        public static TokenModel SerializeJwt(string jwtStr)
        {
            var jwtHandler = new JwtSecurityTokenHandler();
            JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);
            object role;
            try
            {
                jwtToken.Payload.TryGetValue(ClaimTypes.Role, out role);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
            var tm = new TokenModel
            {
                Uid = jwtToken.Id.ToString(),
                Role = role != null ? role.ToString() : "",
            };
            return tm;
        }
    }

在HomeController中新建Login接口来获取Token

/// 
        /// 获取Token
        /// 
        /// 
        /// 
        /// 
        [HttpGet]
        [AllowAnonymous]
        public async Task Login(string rolename, string password)
        {
            string jwtStr = string.Empty;
            bool suc = false;

            if (rolename != null && password != null)
            {
                if (rolename != "Admin" && password != "123456")
                {
                    jwtStr = "输入不正确!";
                }
                else
                {
                    // 将用户id和角色名,作为单独的自定义变量封装进 token 字符串中。
                    TokenModel tokenModel = new TokenModel { Uid = "1", Role = rolename };
                    jwtStr = JwtHelper.IssueJwt(tokenModel);//登录,获取到一定规则的 Token 令牌
                    suc = true;
                }
            }
            else
            {
                jwtStr = "输入不能为空!";
            }

            return Ok(new
            {
                success = suc,
                token = jwtStr
            });
        }

运行项目,输入Admin,123456,获取Token:

.Net Core6.0 WebAPI项目框架搭建五:JWT权限验证_第2张图片

JWT权限验证,就需要开启验证,然后输入token令牌,然后在SwaggerSetUp.cs的AddSwaggerSetup方法的AddSwaggerGen服务中,添加代码:

services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("V1", new OpenApiInfo
                {
                    // {ApiName} 定义成全局变量,方便修改
                    Version = "V1",
                    Title = $"{ApiName} 接口文档——.NetCore 6.0",
                    Description = $"{ApiName} HTTP API V1",
                    //Contact = new OpenApiContact { Name = ApiName, Email = "[email protected]", Url = new Uri("https://www.jianshu.com/u/94102b59cc2a") },
                    //License = new OpenApiLicense { Name = ApiName, Url = new Uri("https://www.jianshu.com/u/94102b59cc2a") }
                });
                c.OrderActionsBy(o => o.RelativePath);

                var xmlPath = Path.Combine(AppContext.BaseDirectory, "Mag.Core.API.xml");//这个就是刚刚配置的xml文件名
                c.IncludeXmlComments(xmlPath, true);//默认的第二个参数是false,这个是controller的注释,记得修改
                var xmlModelPath = Path.Combine(AppContext.BaseDirectory, "Mag.Core.Model.xml");//这个就是Model层的xml文件名
                c.IncludeXmlComments(xmlModelPath);

                // 在header中添加token,传递到后台
                c.OperationFilter();

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

运行项目,就可以看见JWT验证入口:

.Net Core6.0 WebAPI项目框架搭建五:JWT权限验证_第3张图片

.Net Core6.0 WebAPI项目框架搭建五:JWT权限验证_第4张图片

在SetUp文件夹里面新建注册方法AuthorizationSetup.cs

public static class AuthorizationSetup
    {
        public static void AddAuthorizationSetup(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));

            // 1【授权】、这个和上边的异曲同工,好处就是不用在controller中,写多个 roles 。
            // 然后这么写 [Authorize(Policy = "Admin")]
            services.AddAuthorization(options =>
            {
                options.AddPolicy("User", policy => policy.RequireRole("User").Build());
                options.AddPolicy("System", policy => policy.RequireRole("System").Build());
                options.AddPolicy("SystemOrAdmin", policy => policy.RequireRole("Admin", "System"));

            });

            //读取配置文件
            var symmetricKeyAsBase64 = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "SecretKey" });
            var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
            var signingKey = new SymmetricSecurityKey(keyByteArray);
            var Issuer = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Issuer" });
            var Audience = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Audience" });



            // 令牌验证参数
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = signingKey,
                ValidateIssuer = true,
                ValidIssuer = Issuer,//发行人
                ValidateAudience = true,
                ValidAudience = Audience,//订阅人
                ValidateLifetime = true,
                ClockSkew = TimeSpan.FromSeconds(30),
                RequireExpirationTime = true,
            };

            //2.1【认证】、core自带官方JWT认证
            // 开启Bearer认证
            services.AddAuthentication("Bearer")
             // 添加JwtBearer服务
             .AddJwtBearer(o =>
             {
                 o.TokenValidationParameters = tokenValidationParameters;
                 o.Events = new JwtBearerEvents
                 {
                     OnAuthenticationFailed = context =>
                     {
                         // 如果过期,则把<是否过期>添加到,返回头信息中
                         if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                         {
                             context.Response.Headers.Add("Token-Expired", "true");
                         }
                         return Task.CompletedTask;
                     }
                 };
             });



        }
    }

 在program.cs里面注册服务,开启服务

//jwt授权验证
builder.Services.AddAuthorizationSetup();
app.UseAuthentication();

在BaseApiController里面设置全局权限验证:

.Net Core6.0 WebAPI项目框架搭建五:JWT权限验证_第5张图片

 没有验证权限会提示401:

.Net Core6.0 WebAPI项目框架搭建五:JWT权限验证_第6张图片

设置获取token的时候 [AllowAnonymous],无需验证:

.Net Core6.0 WebAPI项目框架搭建五:JWT权限验证_第7张图片 获取一个Admin权限的token,并放到swagger 的权限验证里面:

 .Net Core6.0 WebAPI项目框架搭建五:JWT权限验证_第8张图片

 可以访问:.Net Core6.0 WebAPI项目框架搭建五:JWT权限验证_第9张图片

设置测试方法:需要System的权限才能访问:

.Net Core6.0 WebAPI项目框架搭建五:JWT权限验证_第10张图片

 上面我们是用的Admin的权限,所以会提示403错误

.Net Core6.0 WebAPI项目框架搭建五:JWT权限验证_第11张图片

 新增解析Token的方法:

/// 
        /// 解析Token
        /// 
        /// 
        [HttpGet]
        [Authorize]
        public IActionResult ParseToken()
        {
            //需要截取Bearer 
            var tokenHeader = HttpContext.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
            var user = JwtHelper.SerializeJwt(tokenHeader);
            return Ok(user);

        }

解析出来的role是Admin。 

.Net Core6.0 WebAPI项目框架搭建五:JWT权限验证_第12张图片

你可能感兴趣的:(.netcore,.netcore)