[ASP.NET Web API 2] 實作 System.IdentityModel.Tokens.Jwt 進行身分驗證

續上篇 https://dotblogs.com.tw/yc421206/2019/01/07/authentication_via_jwt-dotnet,這裡介紹 MS JWT 的使用方式

開發環境

 

產生、驗證 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 { getset}
 
        public string Password { getset}
    }
}

 

專案位置

https://github.com/yaochangyu/sample.dotblog/tree/master/WebAPI/JWT/MsJwt

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo