JWT(JSON Web Token)
簡單的介紹下JWT,更多的話,能夠這邊文章看看。咱們着重講下實現。app
ASP.NET Core 的Middleware實現
-
建立JWT
首先咱們要先建立token,畢竟這個是最重要的。Core自帶JWT幫助類,因此咱們按照幫助類的意思來寫個方法建立token。
- public string CreateJsonWebToken(Dictionary<string, string> payLoad)
- {
- if (string.IsNullOrWhiteSpace(setting.SecurityKey))
- {
- throw new ArgumentNullException("JsonWebTokenSetting.securityKey",
- "securityKey爲NULL或空字符串。請在\"appsettings.json\"配置\"JsonWebToken\"節點及其子節點\"securityKey\"");
- }
- var now = DateTime.UtcNow;
-
-
-
- var claims = new List<Claim>();
- foreach (var key in payLoad.Keys)
- {
- var tempClaim = new Claim(key, payLoad[key]?.ToString());
- claims.Add(tempClaim);
- }
-
-
- var jwt = new JwtSecurityToken(
- issuer: null,
- audience: null,
- claims: claims,
- notBefore: now,
- expires: now.Add(TimeSpan.FromMinutes(setting.ExpiresMinute)),
- signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes(setting.SecurityKey)), SecurityAlgorithms.HmacSha256));
- var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
- return encodedJwt;
- }
從方法咱們看到,咱們傳入的是負載這個片斷,而失效時間與祕鑰咱們是放在了appsettings.json
來進行配置的。使用DI來獲取配置文件中的節點值。
-
編寫中間件
咱們都知道,中間件是Core的管道模型組成部分,因此咱們在中間件作驗證,來判斷每次請求用戶是有有權限是有該WebApi或者其餘API。
- 中間件
- public JwtCustomerAuthorizeMiddleware(RequestDelegate next, IOptions<JsonWebTokenSetting> options, IJsonWebTokenValidate jsonWebTokenValidate, Func<Dictionary<string, string>, JsonWebTokenSetting, bool> validatePayLoad, List<string> anonymousPathList)
- {
- this._next = next;
- this._setting = options.Value;
- this._jsonWebTokenValidate = jsonWebTokenValidate;
- this._validatePayLoad = validatePayLoad;
- this._anonymousPathList = anonymousPathList;
- }
-
- public async Task Invoke(HttpContext context)
- {
-
-
- if (_anonymousPathList.Contains(context.Request.Path.Value))
- {
-
- await _next(context);
- return;
- }
- var result = context.Request.Headers.TryGetValue("Authorization", out StringValues authStr);
- if (!result || string.IsNullOrEmpty(authStr.ToString()))
- {
- throw new UnauthorizedAccessException("未受權,請傳遞Header頭的Authorization參數。");
- }
-
-
- result = _jsonWebTokenValidate.Validate(authStr.ToString().Substring("Bearer ".Length).Trim()
- , _setting, _validatePayLoad);
- if (!result)
- {
- throw new UnauthorizedAccessException("驗證失敗,請查看傳遞的參數是否正確或是否有權限訪問該地址。");
- }
-
- await _next(context);
- }
從代碼來看,anonymousPathList
是URL路徑,如果在這個List
內的URL,即可直接跳過驗證,
接着將authStr
token代入驗證函數,validatePayLoad
倒是咱們自代入的委託函數,用於服務器自定義驗證。
- 驗證
驗證方法,我只是作了簽名驗證與時間驗證。並無定得死死的,讓用戶自由度的去進行驗證。
- public bool Validate(string encodeJwt, JsonWebTokenSetting setting, Func<Dictionary<string, string>, JsonWebTokenSetting, bool> validatePayLoad)
- {
- if (string.IsNullOrWhiteSpace(setting.SecurityKey))
- {
- throw new ArgumentNullException("JsonWebTokenSetting.securityKey",
- "securityKey爲NULL或空字符串。請在\"appsettings.json\"配置\"JsonWebToken\"節點及其子節點\"securityKey\"");
- }
-
- var success = true;
- var jwtArr = encodeJwt.Split('.');
- var header = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[0]));
- var payLoad = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[1]));
-
- var hs256 = new HMACSHA256(Encoding.ASCII.GetBytes(setting.SecurityKey));
-
- success = success && string.Equals(jwtArr[2], Base64UrlEncoder.Encode(hs256.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(jwtArr[0], ".", jwtArr[1])))));
- if (!success)
- {
- return success;
- }
-
- var now = ToUnixEpochDate(DateTime.UtcNow);
- success = success && (now >= long.Parse(payLoad["nbf"].ToString()) && now < long.Parse(payLoad["exp"].ToString()));
-
-
- success = success && validatePayLoad(payLoad, setting);
-
- return success;
- }
-
加載中間件
- 使用擴展方法,來封裝中間件
- public static IApplicationBuilder UseJwtCustomerAuthorize(this IApplicationBuilder app, Action<IJwtCustomerAuthorezeOption> action)
- {
- var _JwtCustomerAuthorezeOption = app.ApplicationServices.GetService<IJwtCustomerAuthorezeOption>() as JwtCustomerAuthorezeOption;
- action(_JwtCustomerAuthorezeOption);
- return app.UseMiddleware<JwtCustomerAuthorizeMiddleware>(_JwtCustomerAuthorezeOption.validatePayLoad, _JwtCustomerAuthorezeOption.anonymousPath);
- }
- 在
Startup.cs
使用
- 註冊服務
- public void ConfigureServices(IServiceCollection services) {
- services.AddJwt(Configuration);}
- 使用中間件
- public void Configure(IApplicationBuilder app, IHostingEnvironment env)
- {
- app.UseJwtCustomerAuthorize(option =>
- {
-
- option.SetAnonymousPaths(new System.Collections.Generic.List<string>()
- {
-
- "/Home/Privacy",
- "/Home/CreateJsonToken"
- });
-
- option.SetValidateFunc((playLoad, sertting) =>
- {
- return true;
- });
- });
- }
總結下,經過上面,就完成了JWT在ASP.NET Core使用中間件的方式的實現。簡單來講就是用自帶方法建立token,驗證則使用中間件的形式,每次請求都須要進行驗證固然你能夠設置特殊URL。在下篇文章咱們來說講使用策略模式的JWT實現。