您的位置:

.NET Core JWT详解

JWT(Json Web Token)是一种跨域的身份验证解决方案,它可以在网络上安全地传输数据,用于在API之间进行身份验证和授权。在.NET Core中,可以使用Microsoft.AspNetCore.Authentication.JwtBearer包来轻松地添加JWT身份验证。本文将对.NET Core中的JWT进行详细介绍,涵盖以下主题:

一、安装和配置JWT

在.NET Core中使用JWT需要安装Microsoft.AspNetCore.Authentication.JwtBearer包。在项目中通过nuget包管理器或命令行中运行以下命令来安装:
Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
安装后,在Startup.cs文件中的ConfigureServices方法中添加以下代码:
services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuer = Configuration["Jwt:Issuer"],
        ValidAudience = Configuration["Jwt:Audience"],
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:SecretKey"]))
    };
});
该配置代码将使.NET Core应用程序支持JWT身份验证。首先,AddAuthentication方法设置JwtBearerDefaults身份验证方案,这意味着授权策略将使用JWTBearerAuthenticationOptions类中的设置,JwtBearerDefaults身份验证方案提供默认的jwt身份验证选项。然后JwtBearer身份验证选项分配了一个新的TokenValidationParameters实例,该实例定义了JWT识别配置的设置。例如,Validators被设置为true以执行身份验证,ValidIssuer和ValidAudience设置为数据流需要进行身份验证和签名才能接受的发行方和受众设置。最后,IssuerSigningKey被设置为应用的加密密钥。

二、生成Token

生成JWT token对身份验证和授权的有效性很重要,因为它使用户可以访问其资源和权限。在.NET Core中,可以使用以下代码生成JWT token:
public string GenerateToken(User user)
{
    var tokenHandler = new JwtSecurityTokenHandler();
    var key = Encoding.ASCII.GetBytes(Configuration["Jwt:SecretKey"]);

    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(new Claim[]
        {
            new Claim(ClaimTypes.Name, user.Username),
            new Claim(ClaimTypes.Email, user.Email)
        }),
        Expires = DateTime.UtcNow.AddDays(7),
        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),
            SecurityAlgorithms.HmacSha256Signature)
    };

    var token = tokenHandler.CreateToken(tokenDescriptor);
    return tokenHandler.WriteToken(token);
}
上面的代码将生成一个包含数据 and claims的JWT token。通过句柄类JwtSecurityTokenHandler将数据进行序列化操作,生成一个包含所有有效数据的JWT token。密钥key的值是加密token内容的密钥,Expires配置JWT tokens的有效截止日期,SymmetricSecurityKey将密钥和SHA-256签名算法用于生成签名。

三、使用JWT

在进行身份验证时,首先需要从传入的请求中提取JWT token,如下所示:
var authHeader = context.HttpContext.Request.Headers["Authorization"].FirstOrDefault();
var token = authHeader?.Split(" ").Last();
一旦获取token后,需要进行身份验证。使用以下代码进行验证:
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(Configuration["Jwt:SecretKey"]);
try
{
    var tokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new SymmetricSecurityKey(key),
        ValidateIssuer = true,
        ValidIssuer = Configuration["Jwt:Issuer"],
        ValidateAudience = true,
        ValidAudience = Configuration["Jwt:Audience"],
        ValidateLifetime = true,
    };
    SecurityToken validatedToken;
    var claimsPrincipal = tokenHandler.ValidateToken(token, tokenValidationParameters, out validatedToken);
    context.HttpContext.User = claimsPrincipal;
}
catch(Exception e)
{
    Console.WriteLine(e.Message);
}
在上面的代码中,我们使用了ValidateToken方法来验证token的有效性。TokenValidationParameters对象定义了一些可能用于配置来自哪些发行者和受众验证令牌的属性,令牌是否过期,签名是否有效等。如果令牌验证成功,将进行授权并返回用户(ClaimsPrincipal对象),失败将提示异常。

四、Token刷新

由于JWT tokens具有有效期的限制,为了避免过期问题,需要定期刷新accessToken。通过使用以下代码来轻松处理JWT tokens的期限:
private async Task
    RefreshToken(string token, string refreshToken)
{
    var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
    var key = Encoding.ASCII.GetBytes(Configuration["Jwt:SecretKey"]);
    
    try
    {
        var tokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(key),
            ValidateIssuer = true,
            ValidIssuer = Configuration["Jwt:Issuer"],
            ValidateAudience = true,
            ValidAudience = Configuration["Jwt:Audience"],
            ValidateLifetime = false
        };
        SecurityToken validatedToken;
        var claimsPrincipal = jwtSecurityTokenHandler.ValidateToken(token, tokenValidationParameters, out validatedToken);
        if (validatedToken is JwtSecurityToken jwtSecurityToken && jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
        {
            var username = claimsPrincipal.Identity.Name;
            var user = await _userManager.FindByNameAsync(username);
            if (user == null)
            {
                return null;
            }

            var isValidated = await _userManager.CheckPasswordAsync(user, refreshToken);
            if (!isValidated)
            {
                return null;
            }

            var newToken = GenerateToken(user);
            return newToken;
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }

    return null;
}
   
在上面的代码中,我们通过传递原始token和refreshToken验证当前token是否过期,如果过期则通过GenerateToken方法生成新的token。与上一小节代码的不同之处在于,这里将ValidateLifetime设置为false,以便控制时间间隔并在过期时生成新token。

五、Token吊销

在某些情况下,我们可能需要吊销某个用户的token。为了实现这个功能,我们必须通过添加一个吊销列表,以记录已被吊销的token。从而验证token时可以在吊销列表中搜索。将吊销列表添加到代码中的步骤如下: 首先,需要添加一个TokenRevocationList和RefreshToken实体类。TokenRevocationList实体类包含一个Id字段和一个Revoked字段,而RefreshToken实体类包含一个Id和一个RefreshToken字段。
public class TokenRevocationList
{
    public int Id { get; set; }
    public string Token { get; set; }       
    public DateTime Revoked { get; set; }
}

public class RefreshToken
{
    public int Id { get; set; }
    public string Token { get; set; }
    public DateTime Expires { get; set; }
}
然后,需要在Startup类中的ConfigureServices方法中配置DbContext,如下所示:
services.AddDbContext<YourDbContext>(options => options.UseSqlServer(Configuration["ConnectionString"]));
在进行身份验证时,通过以下代码添加TokenRevocationList检查:
var tokenRevocationList = _context.TokenRevocationList.ToList();
if (tokenRevocationList.Any(x => x.Token == token))
{
    throw new SecurityTokenException("This token has been revoked");
}
最后,在注销时将token添加到TokenRevocationList以吊销token:
var tokenRevocationList = new TokenRevocationList
{
    Token = token,
    Revoked = DateTime.UtcNow
};

await _context.AddAsync(tokenRevocationList);
await _context.SaveChangesAsync();
结束语 本文介绍了.NET Core中使用JWT进行身份验证的步骤。通过安装并配置JWT包,生成token,使用token进行身份验证,刷新token并吊销token实现了应用程序的安全授权。