續上篇 https://dotblogs.com.tw/yc421206/2019/01/07/authentication_via_jwt-dotnet,這裡介紹 MS JWT 的使用方式
開發環境
- VS 2017.15.9.4
- Install-Package System.IdentityModel.Tokens.Jwt
-
專案建置步驟請參考 [Web API] 使用 OWIN 進行測試
產生、驗證 JWT
JwtManager.cs
這有兩個方法,產生 Token、驗證 Token
https://github.com/yaochangyu/sample.dotblog/blob/master/WebAPI/JWT/MsJwt/Server/JwtManager.cs
SecurityTokenDescriptor 用來定義 JWT 的相關設定,Subject 屬性則是放置用戶的 Claim
JwtSecurityTokenHandler 用來產生 JWT、驗證 JWT
public static string GenerateToken(string userName, int expireMinutes = 20) { var symmetricKey = Convert.FromBase64String(Secret); var tokenHandler = new JwtSecurityTokenHandler(); var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, userName) }), NotBefore = Now.Value, Expires = Now.Value.AddMinutes(Convert.ToInt32(expireMinutes)), SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(symmetricKey), SecurityAlgorithms.HmacSha256Signature) }; var securityToken = tokenHandler.CreateToken(tokenDescriptor); var token = tokenHandler.WriteToken(securityToken); return token; }
驗證之前先讀一下 handler.ReadJwtToken(token) 有沒有東西
handler.ValidateToken 驗證 JWT,成功之後就會產生 ClaimsPrincipal
public static bool TryValidateToken(string token, out ClaimsPrincipal principal) { principal = null; if (string.IsNullOrWhiteSpace(token)) { return false; } var handler = new JwtSecurityTokenHandler(); try { var jwt = handler.ReadJwtToken(token); if (jwt == null) { return false; } var secretBytes = Convert.FromBase64String(Secret); var validationParameters = new TokenValidationParameters { RequireExpirationTime = true, ValidateIssuer = false, ValidateAudience = false, IssuerSigningKey = new SymmetricSecurityKey(secretBytes), //LifetimeValidator = LifetimeValidator ClockSkew = TimeSpan.Zero }; SecurityToken securityToken; principal = handler.ValidateToken(token, validationParameters, out securityToken); return true; } catch (Exception) { return false; } }
在 Handler 驗證 JWT
internal class JwtValidationHandler : DelegatingHandler { protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var authorization = request.Headers.Authorization; if (authorization != null && authorization.Scheme == "Bearer") { var token = authorization.Parameter; if (JwtManager.TryValidateToken(token, out var principal)) { Thread.CurrentPrincipal = principal; request.GetRequestContext().Principal = principal; } } return base.SendAsync(request, cancellationToken); } }
別忘了要註冊 Handler
config.MessageHandlers.Add(new JwtValidationHandler());
在 ApiController 產生 JWT
public class TokenController : ApiController { // POST api/token [AllowAnonymous] public IHttpActionResult Post(LoginData loginData) { if (this.CheckUser(loginData.UserName, loginData.Password)) { var token = JwtManager.GenerateToken(loginData.UserName); return new ResponseMessageResult(new HttpResponseMessage { StatusCode = HttpStatusCode.OK, Content = new StringContent(token, Encoding.UTF8) }); } throw new HttpResponseException(HttpStatusCode.Unauthorized); } public bool CheckUser(string username, string password) { // should check in the database return true; } public class LoginData { public string UserName { get; set; } public string Password { get; set; } } }
專案位置
https://github.com/yaochangyu/sample.dotblog/tree/master/WebAPI/JWT/MsJwt
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET