.NET 实现JWT登录认证
在ASP.NET Core应用程序中,使用JWT进行身份验证和授权已成为一种流行的方式。JWT是一种安全的方式,用于在客户端和服务器之间传输用户信息。
添加NuGet包
首先,我们需要添加一些NuGet包来支持JWT身份验证。在您的ASP.NET Core项目中,打开Startup.cs
文件,并在ConfigureServices
方法中添加以下代码:
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
注册
// ...
public void ConfigureServices(IServiceCollection services)
{
// 添加JWT身份验证服务
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
var config = Configuration.GetSection("JwtConfig").Get<JwtConfig>(); // 从appsettings.json读取JwtConfig配置
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = config.Issuer,
ValidAudience = config.Audience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config.SecretKey))
};
options.Events = new JwtBearerEvents
{
OnMessageReceived = async context =>
{
var token = context.Request.Cookies["access_token"]; // 从Cookie中获取token值
if (!string.IsNullOrEmpty(token))
{
context.Token = token; // 将token值设置到JwtBearer上下文中的Token属性
}
}
};
});
// ...
}
这里我们使用AddAuthentication
方法添加了JWT身份验证服务,并设置了默认的认证方案为JwtBearerDefaults.AuthenticationScheme
,这是JWT身份验证的默认方案。
在AddJwtBearer
方法中,我们通过GetSection
方法从appsettings.json文件中读取了一个名为JwtConfig
的配置,其中包含了JWT的一些信息,例如签发者(Issuer)、接收者(Audience)、秘钥(SecretKey)等。这些信息将用于验证和生成JWT令牌。
在Configure
方法中添加JWT认证中间件:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// 其他中间件配置...
app.UseAuthentication();
app.UseAuthorization();
//...
}
配置appsettings.json
接下来,我们需要在appsettings.json文件中配置JWT的相关信息。在您的ASP.NET Core项目中,找到appsettings.json文件,并添加以下配置:
{
// ...
"JwtConfig": {
"Issuer": "YourIssuer",
"Audience": "YourAudience",
"SecretKey": "YourSecretKey",
"AccessTokenExpirationMinutes": 60,
"RefreshTokenExpirationMinutes": 1440
}
}
您可以根据自己的需求修改配置项的值。这里的AccessTokenExpirationMinutes
和RefreshTokenExpirationMinutes
分别表示访问令牌和刷新令牌的过期时间,单位为分钟。
创建 JWT 设置类
接下来,我们需要创建一个 C# 类来表示 JWT 的配置项,并使用 IOptions
接口将其注入到需要的地方。以下是一个示例的 JwtSettings 类:
csharpCopy codepublic class JwtSettings
{
public string Issuer { get; set; }
public string Audience { get; set; }
public string SecretKey { get; set; }
public int AccessTokenExpirationMinutes { get; set; }
public int RefreshTokenExpirationMinutes { get; set; }
}
这个类定义了与 appsettings.json 文件中的配置项相对应的属性。
用户模型
// Models/User.cs
public class UserModel
{
public string Id { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public string RefreshToken {get; set; }
}
实现JWT登录认证
现在,我们可以开始实现JWT登录认证的逻辑。我们将创建一个JwtService
类,用于生成和验证JWT令牌。在您的ASP.NET Core项目中,创建一个名为JwtService.cs
的类文件,然后添加以下代码:
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
public interface IJwtService
{
string GenerateAccessToken(UserModel user);
string GenerateRefreshToken();
bool ValidateAccessToken(string token);
}
public class JwtService : IJwtService
{
private readonly JwtConfig _jwtConfig;
public JwtService(IConfiguration configuration)
{
_jwtConfig = configuration.GetSection("JwtConfig").Get<JwtSettings>();
}
public string GenerateAccessToken(UserModel user)
{
// 设置Token的Claims
List<Claim> claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, user.Id),
new Claim(ClaimTypes.Name, user.Username)
};
// 生成Token的密钥
SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(appSettings.SecretKey));
// 生成Token的签名证书
SigningCredentials creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256Signature);
// 设置Token的过期时间
DateTime expires = DateTime.Now.AddMinutes(appSettings.AccessTokenExpirationMinutes);
// 创建Token
JwtSecurityToken token = new JwtSecurityToken(
appSettings.Issuer,
appSettings.Audience,
claims,
expires: expires,
signingCredentials: creds
);
// 生成Token字符串
string tokenString = new JwtSecurityTokenHandler().WriteToken(token);
return tokenString;
}
public string GenerateRefreshToken()
{
var randomNumber = new byte[32];
using (var rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(randomNumber);
return Convert.ToBase64String(randomNumber);
}
}
public bool ValidateAccessToken(string token)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.UTF8.GetBytes(_jwtConfig.SecretKey);
try
{
tokenHandler.ValidateToken(token, new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = _jwtConfig.Issuer,
ValidAudience = _jwtConfig.Audience,
IssuerSigningKey = new SymmetricSecurityKey(key)
}, out var validatedToken);
}
catch (Exception)
{
return false;
}
return true;
}
}
这里我们创建了一个JwtService
类,实现了IJwtService
接口。该服务类通过依赖注入方式注入了IConfiguration
,从而可以在构造函数中读取JwtConfig
配置。
-
JwtService
类中包含了生成访问令牌和刷新令牌的方法,以及验证访问令牌和从访问令牌中获取用户主体的方法。其中,-
GenerateAccessToken
方法使用JwtSecurityTokenHandler
来生成访问令牌,并设置了过期时间、签名等参数。 -
GenerateRefreshToken
方法生成一个随机的32位Base64编码的字符串作为刷新令牌。 -
ValidateAccessToken
方法验证访问令牌和从访问令牌中获取用户主体。它们使用JwtSecurityTokenHandler
来验证令牌的签名、过期时间等信息,并返回验证结果或用户主体。
-
用户信息加密
在JWT中,用户信息是以Claims的形式进行传递的,但默认情况下,这些信息是以明文的形式存储在令牌中的。为了保护用户信息的安全性,我们可以选择对用户信息进行加密。下面是一个简单的示例,演示如何在生成访问令牌时对用户信息进行加密。
public string GenerateAccessToken(UserModel user)
{
// 设置Token的Claims
List<Claim> claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, user.Id),
new Claim(ClaimTypes.Name, user.Username)
};
// 生成Token的密钥
SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(appSettings.SecretKey));
// 生成Token的签名证书
SigningCredentials creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256Signature);
// 设置Token的过期时间
DateTime expires = DateTime.Now.AddMinutes(appSettings.AccessTokenExpirationMinutes);
// 创建Token
JwtSecurityToken token = new JwtSecurityToken(
appSettings.Issuer,
appSettings.Audience,
claims,
expires: expires,
signingCredentials: creds
);
// 生成Token字符串
string tokenString = new JwtSecurityTokenHandler().WriteToken(token);
return tokenString;
}
在上面的示例中,我们使用了SigningCredentials
类来设置加密的参数,包括加密密钥、加密算法等。这样生成的访问令牌在传递用户信息时会进行加密,增加了用户信息的安全性。
用户登录验证
在用户登录时,我们需要对用户提供的用户名和密码进行验证,并生成访问令牌和刷新令牌。下面是一个简单的示例,演示如何在ASP.NET Core中实现用户登录验证,并生成JWT令牌。
[HttpPost("login")]
public IActionResult Login(UserModel model)
{
// 验证用户名和密码
var isValidUser = ValidateUser(model.Username, model.Password);
if (!isValidUser)
{
return BadRequest(new { message = "Invalid username or password" });
}
// 生成访问令牌
var accessToken = _jwtService.GenerateAccessToken(model);
// 生成刷新令牌
var refreshToken = _jwtService.GenerateRefreshToken();
// 返回访问令牌和刷新令牌给客户端
return Ok(new
{
access_token = accessToken,
refresh_token = refreshToken
});
}
在上面的示例中,我们通过调用_jwtService.GenerateAccessToken
和_jwtService.GenerateRefreshToken
方法来生成访问令牌和刷新令牌,并将刷新令牌保存到数据库或其他持久化存储中,以便后续使用。
刷新令牌
在用户登录后,访问令牌会在一定时间后过期,此时用户需要使用刷新令牌来获取新的访问令牌,而无需重新登录。下面是一个简单的示例,演示如何在ASP.NET Core中实现刷新令牌功能。
[HttpPost("refresh")]
public IActionResult RefreshToken(UserModel model)
{
// 验证刷新令牌是否有效
var isValidRefreshToken = ValidateAccessToken(model.RefreshToken);
if (!isValidRefreshToken)
{
return BadRequest(new { message = "Invalid refresh token" });
}
// 生成新的访问令牌
var accessToken = _jwtService.GenerateAccessToken(model);
// 返回新的访问令牌给客户端
return Ok(new
{
access_token = accessToken
});
}
在上面的示例中,我们通过调用_jwtService.GenerateAccessToken
方法来生成新的访问令牌,并将其返回给客户端。在生成新的访问令牌时,我们可以使用之前保存的用户信息,例如用户名等。
用户登录简单验证
在每次请求时,我们需要对访问令牌进行验证,以确保用户的身份和权限。下面是一个简单的示例,演示如何在ASP.NET Core中实现对访问令牌的简单验证。
[HttpGet("profile")]
[Authorize]
public IActionResult GetUserProfile()
{
// 获取当前用户的用户名
var username = ....;
// 根据用户名从数据库或其他持久化存储中获取用户信息
var userModel = ......;
if (userModel == null)
{
return NotFound(new { message = "userModel not found" });
}
// 返回用户信息给客户端
return Ok(new
{
username = userModel.Username,
email = userModel.Email
});
}
在上面的示例中,我们通过添加[Authorize]
属性来标记需要验证访问令牌的API端点。当客户端发送请求时,ASP.NET Core会自动验证访问令牌的有效性,并将用户信息存储在UserModel
对象中,以便我们在方法内部访问。
总结
本篇博文通过一个简单的案例,介绍了如何使用 C# .NET 实现 JWT 登录验证,并处理用户信息的加密、刷新 Token、各种验证规则等功能。
原文链接:https://www.cnblogs.com/ke210/archive/2023/04/15/17320965.html
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:.NET 实现 JWT 登录验证 - Python技术站