ASP.NET Core-自定義Jwt token驗證(ISecurityTokenValidator)


Core為我們提供了自定義token驗證的接口,當我們需要使用自己的方式驗證token時可以使用。
比如Jwt只能數據簽名,不能加密。當需要校驗加密的jwt token。在登錄時將jwt token加密后傳給客戶端,客戶端回傳token。這時需要我們自定義token校驗。

自定義token校驗,實現ISecurityTokenValidator接口

    /// <summary>
    /// 自定義token校驗
    /// </summary>
    public class MyTokenValidator : ISecurityTokenValidator
    {
        public int MaximumTokenSizeInBytes { get; set; }

        public bool CanReadToken(string securityToken)
        {
            return true;
        }
        public bool CanValidateToken
        {
            get
            {
                return true;
            }
        }

        //驗證token
        public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
        {
            string jwtToken = AESCryptoHelper.Decrypt(securityToken);
            ClaimsPrincipal principal = new JwtSecurityTokenHandler().ValidateToken(jwtToken, validationParameters, out validatedToken);
            return principal;
        }
    }

配置文件中添加配置:

  "JwtTokenOptions": {
    "Issuer": "FAN.Issuer",
    "ValidateIssuer": true,
    "Audience": "FAN.Audience",
    "ValidateAudience": true,
    "RawSigningKey": "11111111-1111-1111-1111-111111111111",/*簽名秘鑰*/
    "ValidateIssuerSigningKey": true,
    "ValidateLifetime": false,
    "RequireExpirationTime": false,
    "JwtExpiresInMinutes": 6000,
    "ValidateIntervaltime": true,
    "IntervalExpiresInMinutes": 3000
  }

Startup.cs添加如下內容:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddScoped<TokenBuilder>();
            services.Configure<JwtTokenOptions>(Configuration.GetSection("JwtTokenOptions"));
            JwtTokenOptions tokenOptions = Configuration.GetSection("JwtTokenOptions").Get<JwtTokenOptions>();

            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                  //開啟Bearer服務認證
                  .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
                  {
                      options.SaveToken = true;
                      options.TokenValidationParameters = tokenOptions.ToTokenValidationParams();
                      options.SecurityTokenValidators.Clear();
                      options.SecurityTokenValidators.Add(new MyTokenValidator());
                  });
         }
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseAuthentication();
        }

User:用戶信息

    /// <summary>
    /// 登錄用戶信息
    /// </summary>
    public class User
    {
        public int UserID { get; set; }
        public string Email { get; set; }

        public string Name { get; set; }
        public string Role { get; set; }


        public User(int userID, string name, string email, string role)
        {
            this.UserID = userID;
            this.Name = name;
            this.Email = email;
            this.Role = role;
        }
    }

TokenBuilder:用於創建jwt token

/// <summary>
    /// token創建
    /// </summary>
    public class TokenBuilder
    {
        private JwtTokenOptions _tokenOptions = null;
        public TokenBuilder(IOptions<JwtTokenOptions> tokenOptions)
        {
            this._tokenOptions = tokenOptions.Value;
        }
        /// <summary>
        /// 創建加密JwtToken
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public string CreateJwtToken(User user)
        {
            var claimList = this.CreateClaimList(user);
            JwtSecurityToken jwtSecurityToken = new JwtSecurityToken(
                issuer: this._tokenOptions.Issuer
                , audience: this._tokenOptions.Audience
                , claims: claimList
                //, notBefore: utcNow
                , expires: DateTime.Now.AddDays(3)
                , signingCredentials: new SigningCredentials(this._tokenOptions.SigningKey, SecurityAlgorithms.HmacSha256)
            );
            string jwtToken = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
            //加密jwtToken
            jwtToken = AESCryptoHelper.Encrypt(jwtToken);
            return jwtToken;
        }

        /// <summary>
        /// 創建包含用戶信息的CalimList
        /// </summary>
        /// <param name="authUser"></param>
        /// <returns></returns>
        private List<Claim> CreateClaimList(User authUser)
        {
            //身份單元項項集合
            List<Claim> claimList = new List<Claim>()
                    {
                        new Claim(type: ClaimTypes.Email, value: authUser.Email), //身份單元項
                        new Claim(type: ClaimTypes.Name, value: authUser.Name),
                        new Claim(type: ClaimTypes.NameIdentifier, value: authUser.UserID.ToString()),
                        new Claim(type: ClaimTypes.Role, value: authUser.Role ?? string.Empty)
                    };
            return claimList;
        }
    }

AESCryptoHelper:使用AES對jwttoken的加密解密

    /// <summary>
    /// AES加密解密
    /// </summary>
    public class AESCryptoHelper
    {
        /// <summary>
        /// AES加密解密Key,Key必須十六位
        /// </summary>
        private static readonly string AESKey = "1111111111111111";
        /// <summary>
        ///  AES 加密
        /// </summary>
        /// <param name="plainText"></param>
        /// <returns></returns>
        public static string Encrypt(string plainText)
        {
            return Encrypt(plainText, AESKey);
        }
        /// <summary>
        ///  AES 加密
        /// </summary>
        /// <param name="plainText"></param>
        /// <param name="key">密碼必須是16位,否則會報錯哈</param>
        /// <returns></returns>
        public static string Encrypt(string plainText, string key)
        {
            string result = null;
            if (string.IsNullOrEmpty(plainText))
            {
                return result;
            }
            byte[] plainTextArray = Encoding.UTF8.GetBytes(plainText);
            using (MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider())
            {
                using (RijndaelManaged rijndaelManaged = new RijndaelManaged
                {
                    Key = provider.ComputeHash(Encoding.UTF8.GetBytes(key)),
                    //Key = Encoding.UTF8.GetBytes(key),
                    Mode = CipherMode.ECB,
                    Padding = PaddingMode.PKCS7
                })
                {
                    using (ICryptoTransform cryptoTransform = rijndaelManaged.CreateEncryptor())
                    {
                        byte[] resultArray = cryptoTransform.TransformFinalBlock(plainTextArray, 0, plainTextArray.Length);
                        result = Convert.ToBase64String(resultArray, 0, resultArray.Length);
                        Array.Clear(resultArray, 0, resultArray.Length);
                        resultArray = null;
                    }
                }
            }
            Array.Clear(plainTextArray, 0, plainTextArray.Length);
            plainTextArray = null;
            return result;
        }
        /// <summary>
        ///  AES 解密
        /// </summary>
        /// <param name="encryptText"></param>
        /// <returns></returns>
        public static string Decrypt(string encryptText)
        {
            return Decrypt(encryptText, AESKey);
        }
        /// <summary>
        ///  AES 解密
        /// </summary>
        /// <param name="encryptText"></param>
        /// <param name="key">密碼必須是16位,否則會報錯哈</param>
        /// <returns></returns>
        public static string Decrypt(string encryptText, string key)
        {
            string result = null;
            if (string.IsNullOrEmpty(encryptText))
            {
                return result;
            }
            byte[] encryptTextArray = Convert.FromBase64String(encryptText);
            using (MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider())
            {
                using (RijndaelManaged rijndaelManaged = new RijndaelManaged
                {
                    Key = provider.ComputeHash(Encoding.UTF8.GetBytes(key)),
                    //Key = Encoding.UTF8.GetBytes(key),
                    Mode = CipherMode.ECB,
                    Padding = PaddingMode.PKCS7
                })
                {
                    using (ICryptoTransform cryptoTransform = rijndaelManaged.CreateDecryptor())
                    {
                        byte[] resultArray = cryptoTransform.TransformFinalBlock(encryptTextArray, 0, encryptTextArray.Length);
                        result = Encoding.UTF8.GetString(resultArray);
                        Array.Clear(resultArray, 0, resultArray.Length);
                        resultArray = null;
                    }
                }
            }
            Array.Clear(encryptTextArray, 0, encryptTextArray.Length);
            encryptTextArray = null;
            return result;
        }
    }

控制器:

    [Route("api/[controller]/[action]")]
    [ApiController]
    public class ValuesController : ControllerBase
    {
        private TokenBuilder _tokenBuilder = null;
        public ValuesController(TokenBuilder tokenBuilder)
        {
            this._tokenBuilder = tokenBuilder;
        }
        /// <summary>
        /// 登錄,生成加密token
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public ActionResult<string> Login()
        {
            //省略登錄邏輯。。。。
            var user = new User(1, "fan", "410577910@qq.com", "admin");
            string signToken = this._tokenBuilder.CreateJwtToken(user);
            return signToken;
        }
        /// <summary>
        /// 創建訂單,需要校驗token
        /// </summary>
        /// <returns></returns>
        [Authorize]
        [HttpPost]
        public ActionResult<string> CreateOrder()
        {
            if (base.User.Identity.IsAuthenticated)
            {
                string userName = base.User.Identity.Name;
            }
            //省略創建訂單邏輯。。。
            return "生成訂單成功";
        }
    }

測試

登錄:(獲取token)

http://localhost:5000/api/values/CreateOrder

創建訂單:(帶上token,才能授權通過)

http://localhost:5000/api/values/CreateOrder POST
Headers添加:
Key: Authorization
Value: Bearer 2FrDOaIT8r9n7axl4ARhe2dp7S7bWS5+eCcErbkeIIzVbutYr+LmMI1HBEWCLwgwS80adJlwDGW9iNtL2Kp4y+twxHmEpPJfhmg8X1uzgYReh6Nd7XcJmQh9zXvma9gfySU8DcEOijD79wellmRqPNh8ZYX7C0DqKx55L8DVgkJ4emOHIyni/V7qs3xqgU6RstCCxOAI4tHS7v67jmtQJks2x88iBntAJWsPwr7jRChvdWXHpsMeOzyZDjEwiT/XZIFHwB6wyUOfGqqkpdj3s36XwaKEvEBJzwSL2LCUEpMJUr7SQ0r4ZJNnPEBsFoiA/s35nbhgt9OU5w4Z+9MUJ2hBW/eTRlhwtcUR48nitE+PyJS9Ipan+wngvKkkX64BU0l4aLQ9b+REmjf9NZ1RD1UGCL2bmP5XDeoHtYM8uEGYCXu4vvZ1C16oy7AJv/PEEUtL1WNEwJ0Pf9A3DV0o0UxR1q1T5x5nFHftmUu/wrgL2R6GJkUKvWOFWJgAILRk1jHd6HueuqTdTZWdPIDmUH6XwaKEvEBJzwSL2LCUEpMATTE2c3Sw+06USRWWJ3+pIYWS7pM632cOahyPj5iyAihGleXc3bFgjTH/9zlUnJAz3FTrFdRLjj4Vy/UTQDwUKLZEcPWXcYFTPtfuMuR1rwrzIXJOa8ywA/qdbn0XTHtCbTPTHADBaqPEzK8NxMQdCrtgfuCjJ4kPrmVxOaf784RiHgDmcvJ+2Xtazf09hYo+gKtSy8xLTktDZHxfniAtfZP8QU18rpGNsOcKl/E7rA==


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM