目录
1、JWT
现在在各类API的开发中,token已经是必备了。例如:微信公众号开发中,第一个方法就是获取token。JWT具体的定义及组成部分大家可以到网上找找,这儿给一个简单的描述:JWT 令牌是紧凑的 URL 安全令牌,易于在各方之间转移。它们是自包含的,这意味着它们自身内部携带信息,从而减少了对服务器端会话存储的需求。
定义可以从网上找到,但网上入门的例子,要么很简单、要么很复杂,反而不知道如何入门。因此这儿记录一下,在net8的webapi中如何使用JWT的入门教程。
2、具体实现
首先创建
NET8
环境下
WebApi
的项目,通过
nuget
引用包
Microsoft.AspNetCore.Authentication.JwtBearer
在
appsettings.json
中添加配置信息
{"Logging":{"LogLevel":{"Default":"Information","Microsoft.AspNetCore":"Warning"}},"AllowedHosts":"*",/**JWT的配置信息,这几个信息都是测试数据,需要根据实际业务自行调整**/"JwtSettings":{"SecretKey":"bAafd@A7d9#@F4*V!LHZs#ebKQrkE6pad2f3kj34c3dXy@",/**存放加密的秘钥**/"Issuer":"ZhengLinTest",/**存放发布者信息**/"Audience":"AllUseAPI",/**存放受众者信息**/"AccessTokenExpirationMinutes":30,"RefreshTokenExpirationDays":7}}
为了能够将配置文件中
JwtSettings
强转换为一个类,需要提前定义一个Model类。
namespaceJWTWebApplication.Models{/// <summary>/// 这个类主要是用于解析appsettings.json里的配置信息,也可以使用其他方式,获取及保存配置信息/// </summary>publicclassJwtSettings{publicstring SecretKey {get;set;}publicstring Issuer {get;set;}publicstring Audience {get;set;}publicint AccessTokenExpirationMinutes {get;set;}publicint RefreshTokenExpirationDays {get;set;}}}
JWT是一加密的符合JSON格式的字符串,那我们就需要定义,到底要加密哪些信息。在本例中我们会加密:姓名、密码、角色、邮箱等信息。因此我们创建一个
类
,用于自定义需要加密到JWT中的信息。具体的Model如下
namespaceJWTWebApplication.Models{/// <summary>/// 用于存储到token中的数据/// </summary>publicclassUser{publicint Id {get;set;}publicstring Username {get;set;}publicstring Name {get;set;}publicstring Email {get;set;}publicstring Password {get;set;}publicstring[] Roles {get;set;}}}
下面我们会创建一个用于生成
JWT
的
Service
类,并添加一个生成
jwt
的方法
Crete
namespaceJWTWebApplication.Services{publicclassAuthService{//通过依赖注入的方式,将配置参数带入到类中。后面会在program.cs文件中,进行注册。privatereadonlyJwtSettings _jwtSettings;publicAuthService(IOptions<JwtSettings> jwtSettings){
_jwtSettings = jwtSettings.Value;}/// <summary>/// 用于令牌的生成/// </summary>/// <param name="user"></param>/// <returns></returns>publicstringCreate(User user){}}}
在
Create
方法中,先实例化
JwtSecurityTokenHandler
,它负责生成
token
(令牌)
var handler =newJwtSecurityTokenHandler();
下一步是生成令牌的信息并进行签名,因此我们需要刚才配置信息的秘钥,并使用
SigningCredentials
完成签名,
SigningCredentials
需要两个参数:秘钥和算法
var privateKey = Encoding.UTF8.GetBytes(_jwtSettings.SecretKey);var credentials =newSigningCredentials(newSymmetricSecurityKey(privateKey),
SecurityAlgorithms.HmacSha256);
下一步,就是将我们需要加密到
token
中的数据,通过方法实现。该如何添加呢?它的代码是这样的:
newClaim(ClaimTypes.Name, user.Username)//可以理解为键/值结构
为了简化操作,我将创建一个方法来返回我们将保存在令牌中的 ClaimsIdentity(所有令牌声明的列表),该方法会自动添加到令牌的有效负载中。
//准备给Token中的值privatestaticClaimsIdentityGenerateClaims(User user){var ci =newClaimsIdentity();
ci.AddClaim(newClaim("id", user.Id.ToString()));
ci.AddClaim(newClaim(ClaimTypes.Name, user.Username));
ci.AddClaim(newClaim(ClaimTypes.GivenName, user.Name));
ci.AddClaim(newClaim(ClaimTypes.Email, user.Email));foreach(var role in user.Roles)
ci.AddClaim(newClaim(ClaimTypes.Role, role));return ci;}
下一步操作是创建 SecurityTokenDescriptor 的实例,以便在令牌中包含基本信息
var tokenDescriptor =newSecurityTokenDescriptor{
SigningCredentials = credentials,
Expires = DateTime.UtcNow.AddMinutes(_jwtSettings.AccessTokenExpirationMinutes),
Subject =GenerateClaims(user)};
然后我使用
handler.CreateToken()
方法生成令牌,并且使用
handler.WriteToken(token)
方法,将
JwtSecurityToken
序列化为紧凑序列化格式
JWT
并返回。
var token = handler.CreateToken(tokenDescriptor);return handler.WriteToken(token);
最终,生成完成的代码如下:
usingJWTWebApplication.Models;usingMicrosoft.Extensions.Configuration;usingMicrosoft.Extensions.Options;usingMicrosoft.IdentityModel.Tokens;usingSystem.IdentityModel.Tokens.Jwt;usingSystem.Security.Claims;usingSystem.Text;namespaceJWTWebApplication.Services{publicclassAuthService{//通过依赖注入的方式,将配置参数带入到类中privatereadonlyJwtSettings _jwtSettings;publicAuthService(IOptions<JwtSettings> jwtSettings){
_jwtSettings = jwtSettings.Value;}/// <summary>/// 用于令牌的生成/// </summary>/// <param name="user"></param>/// <returns></returns>publicstringCreate(User user){var handler =newJwtSecurityTokenHandler();var privateKey = Encoding.UTF8.GetBytes(_jwtSettings.SecretKey);var credentials =newSigningCredentials(newSymmetricSecurityKey(privateKey),
SecurityAlgorithms.HmacSha256);var tokenDescriptor =newSecurityTokenDescriptor{
SigningCredentials = credentials,
Expires = DateTime.UtcNow.AddMinutes(_jwtSettings.AccessTokenExpirationMinutes),
Subject =GenerateClaims(user)};var token = handler.CreateToken(tokenDescriptor);return handler.WriteToken(token);}//准备给Token中的值privatestaticClaimsIdentityGenerateClaims(User user){var ci =newClaimsIdentity();
ci.AddClaim(newClaim("id", user.Id.ToString()));
ci.AddClaim(newClaim(ClaimTypes.Name, user.Username));
ci.AddClaim(newClaim(ClaimTypes.GivenName, user.Name));
ci.AddClaim(newClaim(ClaimTypes.Email, user.Email));foreach(var role in user.Roles)
ci.AddClaim(newClaim(ClaimTypes.Role, role));return ci;}}}
有了生成token的方法,那我们就需要进行配置,准备使用了。具体来说,就是在
program.cs
中进行配置
首先添加开启授权和认证功能的代码
builder.Services.AddAuthentication();//启用身份验证功能--认证主要是指,用户米、密码是否正确
builder.Services.AddAuthorization();//启用授权功能---授权主要是看有没有权限
app.UseAuthentication();//启用认证功能
app.UseAuthorization();//启用授权功能
其次,要指定使用 JWT 进行身份验证,需要进行配置调整。这涉及设置
DefaultChallengeScheme
以定义如何检查每个传入请求以确定适当的身份验证方法。这可确保应用程序收到的每个请求都被视为 JWT 身份验证
builder.Services.AddAuthentication(x =>{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;});
此外,可以通过
AddJwtBearer()
方法进行验证令牌。在本例中,将使用私钥,并且为了简单起见,排除了对颁发者和受众的验证
//收到的每个请求都被视为 JWT 身份验证
builder.Services.AddAuthentication(x =>{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;}).AddJwtBearer(x =>{
x.TokenValidationParameters =newMicrosoft.IdentityModel.Tokens.TokenValidationParameters{
ValidateIssuer =false,
ValidateAudience =false,
IssuerSigningKey =newSymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecretKey))};});
因为有些类,用到了依赖注入的方式实现,因此在配置文件中加了一下依赖注入的声明
//依赖注入
builder.Services.AddTransient<AuthService>();
builder.Services.AddOptions();
builder.Services.Configure<JwtSettings>(builder.Configuration.GetSection("JwtSettings"));
因此,完成的配置文件如下:
usingJWTWebApplication.Models;usingJWTWebApplication.Services;usingMicrosoft.AspNetCore.Authentication.JwtBearer;usingMicrosoft.Extensions.Configuration;usingMicrosoft.IdentityModel.Tokens;usingMicrosoft.Extensions.Options;usingSystem.Text;var builder = WebApplication.CreateBuilder(args);// Add services to the container.
builder.Services.AddControllers();// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();//依赖注入
builder.Services.AddTransient<AuthService>();
builder.Services.AddOptions();
builder.Services.Configure<JwtSettings>(builder.Configuration.GetSection("JwtSettings"));//启用功能
builder.Services.AddAuthentication();//启用身份验证功能--认证主要是指,用户米、密码是否正确
builder.Services.AddAuthorization();//启用授权功能---授权主要是看有没有权限//读取配置文件的数据//这儿自定义了一个JwtSettings类,类里面的属性要与配置文件中的一致var jwtSettings = builder.Configuration.GetSection("JwtSettings").Get<JwtSettings>();//收到的每个请求都被视为 JWT 身份验证
builder.Services.AddAuthentication(x =>{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;}).AddJwtBearer(x =>{
x.TokenValidationParameters =newMicrosoft.IdentityModel.Tokens.TokenValidationParameters{
ValidateIssuer =false,
ValidateAudience =false,
IssuerSigningKey =newSymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecretKey))};});//声明一个指定名称的认证策略
builder.Services.AddAuthorization(x =>{
x.AddPolicy("rolePolicy", p => p.RequireRole("developer"));});var app = builder.Build();// Configure the HTTP request pipeline.if(app.Environment.IsDevelopment()){
app.UseSwagger();
app.UseSwaggerUI();}
app.UseAuthentication();//启用认证功能
app.UseAuthorization();//启用授权功能
app.MapControllers();
app.Run();
至此,基本的配置已经完成,让我们开始使用吧
首先,先创建一个api的
Controller
,并写下如下的代码
namespaceJWTWebApplication.Controllers{[Route("api/[controller]/[action]")][ApiController]publicclassJWTTestController:ControllerBase{//依赖注入。在program文件中的依赖注入,这儿就用到了privatereadonlyAuthService _authService;publicJWTTestController(AuthService authService){
_authService = authService;}//具体的三个方法实现}}
在类里面,我们将会创建三个方法:
Login
、
test
、
roletest
。这三个方法分别用于:根据传入的用户米/密码,生成
token
。
test
和
roletest
分别用于测试权限认证和测试指定认证名称(就是在
program
中的
x.AddPolicy("rolePolicy", p => p.RequireRole("developer"));
),完整的代码如下:
namespaceJWTWebApplication.Controllers{[Route("api/[controller]/[action]")][ApiController]publicclassJWTTestController:ControllerBase{//依赖注入privatereadonlyAuthService _authService;publicJWTTestController(AuthService authService){
_authService = authService;}[HttpGet]publicstringLogin(string username,string password){//获取前台传过来的用户名、密码的数据var user =newUser();
user.Username = username;
user.Password = password;//从后台进行身份验证,并获取该登录人的其他信息(例如,角色、邮箱等各类信息)
user.Name ="zhenglin";
user.Id =1;
user.Email ="[email protected]";
user.Roles =newstring[]{"developer"};//返回tokenreturn _authService.Create(user);}[Authorize][HttpGet]publicStatusCodeResulttest(){returnStatusCode(200);}[Authorize("rolePolicy")][HttpGet]publicStatusCodeResultroletest(){returnStatusCode(200);}}}
至此,全部代码完成,准备验证
首先测试一下
Login
,看能否返回
token
其次,测试一下携带
token
的
test
方法
最后测试一下,指定名称的认证
3、代码下载
代码下载:下载地址
版权归原作者 zlbcdn 所有, 如有侵权,请联系我们删除。