.Net Web Api中使用JWT认证

.Net Web Api中使用JWT认证

首发于个人博客 CoderMiner技术博客 http://coderminer.com

JWT(Java Web Token)

JWT由三部分组成,头部(header).数据(payload).签名(sign),基本的格式是

如果算法是 HS256

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  your-256-bit-secret
)

如 :

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiI1YmVkMTU1MTA5MTY0MzNhZDRhZWVmYTkiLCJuYmYiOjE1NDIyNjQxNDYsImV4cCI6MTU0MjI2NDE0NiwiaWF0IjoxNTQyMjY0MTQ2fQ.JmPlYiPBvS-OF4uA2M4erklwwasj8Isg3BeYXZwqJ04

可以在 JWT官网 进行验证token相关的信息

在.net web api中使用

创建 Web Api的工程

安装三方包,需要通过 nuget 安装

Microsoft.IdentityModel.JsonWebTokens

生成Token

需要引入的包

using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;

生成 Token的Secret key

var hmac = new HMACSHA256();
var key = Convert.ToBase64String(hmac.Key);
private static string Secret = "szQkFW37ihYnEfgw1huvUMtp53zAA8w4jpQ/m6uaVDpkZdGu+FL8XbWZ+Oxs0w0g/KdjFVAYk9D9MJoXT7MfzQ=="

生成Token,创建一个 TokenManager 类,并添加方法 GenerateToken

public static string GenerateToken(string username)
{

    var symmetricKey = Convert.FromBase64String(Secret);
    var tokenHandler = new JwtSecurityTokenHandler();
    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(new[] {
            new Claim(ClaimTypes.Name,username),
        }),
        Expires = DateTime.Now.AddMinutes(30),

        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(symmetricKey),SecurityAlgorithms.HmacSha256Signature)
    };
    var securityToken = tokenHandler.CreateToken(tokenDescriptor);
    return  tokenHandler.WriteToken(securityToken);
}

把token返回给客户端

可以在登录接口中生成token,并返回给客户端

public class UserController : ApiController
{
    public string Login([FromBody]LoginReq req)
    {
      var token = TokenManager.GenerateToken(req.username);
    }
}

验证Token

客户端在调用了登录接口之后,之后其他的接口都需要验证token信息,为此可以创建一个过滤器,可以对整个Controller生效

  • 过滤器(Filter)

token放在接口的Headers

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,AllowMultiple = false,Inherited = true)]
public class TokenFilterAttribute : AuthorizationFilterAttribute
{
  public override void OnAuthorization(HttpActionContext actionContext)
  {
    var attr = actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().OfType<AllowAnonymousAttribute>();
    bool isAnonymous = attr.Any(a => a is AllowAnonymousAttribute);
    if (!isAnonymous)
    {
        var authorization = actionContext.Request.Headers.Authorization;
        var result = TokenManager.ValidateToken(authorization.Scheme);
        if (!result)
        {
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
        }
    }
  }
}
  • 在整个Controller生效
[TokenFilter]
public class UserController : ApiController
  • 验证Token是否有效,是否过期等
private static ClaimsPrincipal GetPrincipal(string token)
{
    try
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var jwtToken = tokenHandler.ReadToken(token) as JwtSecurityToken;
        if(jwtToken == null)
        {
            return null;
        }
        var symmetricKey = Convert.FromBase64String(Secret);
        var validationParams = new TokenValidationParameters()
        {
            RequireExpirationTime = true,
            ValidateIssuer =false,
            ValidateAudience = false,
            IssuerSigningKey = new SymmetricSecurityKey(symmetricKey),
        };
        SecurityToken securityToken;
        var pincipal = tokenHandler.ValidateToken(token, validationParams, out securityToken);
        return pincipal;
    }
    catch (Exception ex)
    {
        return null;
    }
}
public static bool ValidateToken(string token)
{
    var principal = GetPrincipal(token);
    var identity = principal?.Identity as ClaimsIdentity;
    if(identity == null)
    {
        return false;
    }
    if (!identity.IsAuthenticated)
    {
        return false;
    }
    var nameClaim = identity.FindFirst(ClaimTypes.NameIdentifier);
    var username = nameClaim?.Value;
    if (string.IsNullOrEmpty(username))
    {
        return false;
    }

    return true;
}

更多精彩内容 http://coderminer.com