欢迎光临
个人技术文档整理

NET Core认证授权之JWT-WebAPI授权认证(二)

JWT有什么用?

在一次性使用场景下,比如:无状态的API、邮箱验证码等需要一定用户标识,但无法篡改,且只在一定时间内有效的操作。

安装NuGet包

Install-Package Microsoft.IdentityModel.Tokens
Install-Package System.IdentityModel.Tokens.Jwt
Install-Package Microsoft.AspNetCore.Authentication.JwtBearer

对JWT进行配置

  • 在Startup中的ConfigureServices方法中注册服务
            public void ConfigureServices(IServiceCollection services)
            { 
                services.Configure<Configs>(Configuration);//注册配置
      
                #region 注册 JWT身份认证
                services.AddScoped<ITokenService, TokenService>(); //JWT加密 解密
                var conf = Configuration.Get<Configs>();
                var jwtOptions = conf.JwtOptions;
    
                services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(x =>
                {
                    byte[] keyBytes = Encoding.UTF8.GetBytes(jwtOptions.SecurityKey);
                    var secKey = new SymmetricSecurityKey(keyBytes);
                    x.TokenValidationParameters = new()
                    {
                        ValidateIssuer = false,
                        ValidateAudience = false,
                        ValidateLifetime = true,
                        ValidateIssuerSigningKey = true,
                        IssuerSigningKey = secKey
                    };
                });
                #endregion
     
                 
            }
  • 在Startup中的Configure方法中 
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
             //路由中间件
             app.UseRouting();
    
             //需要在UseAuthentication之后再次UseAuthorization  否则,当你使用授权功能比如使用[Authorize]属性的时候系统就会报错
             app.UseAuthentication(); //认证
             app.UseAuthorization(); //授权
            }
  • 登录接口(AuthController)

        /// <summary>
        /// 登录服务
        /// </summary>
        [Route("api/[controller]/[action]")]
        [ApiController]
        public class AuthController : ControllerBase
        {
            private ITokenService _ITokenService = null;
            public AuthController(ITokenService tokenService)
            {
                this._ITokenService = tokenService;
            }
            
            [HttpGet]
            public IActionResult Login(string loginName = "demo", string loginPassword = "123456")
            { 
                if (loginName == "demo" && loginPassword == "123456")
                {
                    var tokenStr = _ITokenService.GetToken(loginName, loginPassword);
                    return new JsonResult(new { code = 200, msg = "登录成功", data = tokenStr });
                }
                else
                {
                    return new JsonResult(new { code = 0, msg = "登录失败" });
                }
            } 
        }

     

  • 校验登录(AdminController)

        [Route("api/[controller]/[action]")]
        [ApiController]
    
        public class AdminController : ControllerBase
        {
            private ITokenService _ITokenService = null;
            public AdminController(ITokenService tokenService)
            {
                this._ITokenService = tokenService;
            }
            [HttpGet]
            [Authorize]//表示只有登录过的用户,拥有token的客户端才可以访问。用这个特性需要引入对应的命名空间
            public IActionResult GetUserInfo()
            {
                var claims = HttpContext.User.Claims;
                var loginName = claims.Where(x => x.Type == "loginName").Select(x => x.Value).FirstOrDefault();
                var loginPassword = claims.Where(x => x.Type == "loginPassword").Select(x => x.Value).FirstOrDefault();
                var _model = new { loginName = loginName, loginPassword = loginPassword };
                return new JsonResult(new { code = 200, msg = "登录成功", data = _model });
    
            } 
             
        }

 

其他源码

  • appsettings.json

    { 
      "JwtOptions": {
        "Issuer": "http://localhost",
        "Audience": "http://localhost",
        "Expires": 3600,
        "SecurityKey": "1234567890123456" //长度有要求 16+
      }
    }
    
  • Configs.cs

     public class Configs
        {  
            public JwtOption JwtOptions { get; set; }
        }
    
     public class JwtOption
        {
            /// <summary>
            /// jwt签发者
            /// </summary>
            public string Issuer { get; set; } = "http://localhost";
            /// <summary>
            /// 接收jwt的一方
            /// </summary>
            public string Audience { get; set; } = "http://localhost";
            /// <summary>
            /// jwt的过期时间
            /// </summary>
            public int Expires { get; set; } = 3600;
            /// <summary>
            /// 秘钥
            /// </summary>
            public string SecurityKey { get; set; } = "123456789012345";
             
        }

     

  • ITokenService.cs和TokenService.cs

        public interface ITokenService
        {
            string GetToken(string loginName, string loginPassword);
            Dictionary<string, string> DecodeToken(string token);
        }
        public class TokenService : ITokenService
        {
            private readonly JwtOption _jwtOptions;
    
            public TokenService(IOptionsMonitor<Configs> configs
            )
            {
                _jwtOptions = configs.CurrentValue.JwtOptions;
            }
    
            /// <summary>
            /// 根据账号密码生成 Token
            /// </summary>
            public string GetToken(string loginName, string loginPassword)
            {
                #region 有效载荷, 可以自己写,爱写多少写多少;尽量避免敏感信息
    
                var cls = new[]
                {
                    new Claim("loginName",loginName),
                    new Claim("loginPassword",loginPassword),
                };
                #endregion
    
                //加密  
                //依赖Nuget:Microsoft.IdentityModel.Tokens
                SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.SecurityKey));
                //签名
                SigningCredentials creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
    
                //依赖Nuget:System.IdentityModel.Tokens.Jwt 
                var jwtSecurityToken = new JwtSecurityToken(
                       issuer: _jwtOptions.Issuer,//jwt签发者
                       audience: _jwtOptions.Audience,//接收jwt的一方 
                                                      //notBefore: DateTime.Now,//定义在什么时间之前,该jwt都是不可用的
                       expires: DateTime.Now.AddSeconds(_jwtOptions.Expires),//jwt的过期时间,这个过期时间必须要大于签发时间
                       claims: cls,
                       signingCredentials: creds
                    );
    
                var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
    
                return token;
            }
    
            /// <summary>
            /// 调用ValidateToken方法对JWT进行解密
            /// </summary>
            /// <param name="jwtToken">jwt令牌</param>
            /// <returns></returns>
            public Dictionary<string, string> DecodeToken(string jwtToken)
            {
                string secKey = _jwtOptions.SecurityKey;//秘钥
                JwtSecurityTokenHandler tokenHandler = new();
                TokenValidationParameters valParam = new();
                var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secKey));
                valParam.IssuerSigningKey = securityKey;
                valParam.ValidateIssuer = false;
                valParam.ValidateAudience = false;
                // 调用ValidateToken方法对JWT进行解密
                ClaimsPrincipal claimsPrincipal = tokenHandler.ValidateToken(jwtToken,
                        valParam, out SecurityToken secToken);
    
                Dictionary<string, string> dic = new Dictionary<string, string>();
                foreach (var claim in claimsPrincipal.Claims)
                {
                    dic.Add(claim.Type, claim.Value);
                }
    
                return dic;
            }
        }

     

 

赞(2)