目录
2.1 注册JwtBearer认证——AddJwtBearer方法
2.2 Jwt验证选项参数汇总——JwtBearerOptions
继上次“C#开发日记:手把手教你生成JWT” 后:http://t.csdnimg.cn/78CkH
我们这次使用生成的Token为其他接口设置验证,上次使用的命名空间是:Microsoft.IdentityModel.Tokens;
这次需要再安装:Microsoft.AspNetCore.Authentication.JwtBearer
一、注册身份验证服务
在 Microsoft.Extensions.DependencyInjection.IServiceCollection 中注册注册身份验证服务的方法为AddAuthentication,是IServiceCollection的扩展方法。
public static AuthenticationBuilder AddAuthentication(this IServiceCollection services);
public static AuthenticationBuilder AddAuthentication(this IServiceCollection services, string defaultScheme);
public static AuthenticationBuilder AddAuthentication(this IServiceCollection services, Action<AuthenticationOptions> configureOptions);
选择第三个带有action<T>委托的身份验证选项
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(options = >{
//身份验证选项 AuthenticationOptions
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
//options.DefaultAuthenticateScheme=...;
//options.DefaultSignInScheme=...;
//options.DefaultSignOutScheme=...;
//options.DefaultChallengeScheme=...;
//options.DefaultForbidScheme=...,
//options.RequireAuthenticatedSignIn=...;
})
二、配置JwtBearer身份验证
2.1 注册JwtBearer认证——AddJwtBearer方法
如果使用默认方案Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme
来启用 JwtBearer认证通过调用 重载2 AddJwtBearer("Bearer", delegate{});来指定默认。
AddJwtBearer的部分定义如下:
public static class JwtBearerExtensions
{
// 默认方案
public static AuthenticationBuilder AddJwtBearer(this AuthenticationBuilder builder)
{
//使用如下方法重载
return builder.AddJwtBearer("Bearer", delegate
{
});
}
... 省略其他
//重载1
public static AuthenticationBuilder AddJwtBearer(this AuthenticationBuilder builder, string authenticationScheme, Action<JwtBearerOptions> configureOptions)
{
return builder.AddJwtBearer(authenticationScheme, null, configureOptions);
}
// 重载2
public static AuthenticationBuilder AddJwtBearer(this AuthenticationBuilder builder, string authenticationScheme, string? displayName, Action<JwtBearerOptions> configureOptions)
{
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<JwtBearerOptions>, JwtBearerConfigureOptions>());
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IPostConfigureOptions<JwtBearerOptions>, JwtBearerPostConfigureOptions>());
return builder.AddScheme<JwtBearerOptions, JwtBearerHandler>(authenticationScheme, displayName, configureOptions);
}
}
可以看出默认AddJwtBearer会调用其重载1方法,输入字符串参数和又一个JwtBearerOptions类型的Action<T>委托,然后返回一个重载2:
AddJwtBearer(authenticationScheme, null, configureOptions);
参数分别是:
- 身份验证方案名称(string): authenticationScheme
- 身份验证处理程序的显示名称(可选): null
- 允许配置 Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerOptions 的委托: configureOptions
返回验证构造器的引用—— AddScheme,它是第一章节中"注册身份验证服务"用到的AuthenticationBuilder类自身的 AddScheme方法,它用于添加一项特定类型的身份验证机制。
builder.AddScheme<JwtBearerOptions, JwtBearerHandler>(authenticationScheme, null, configureOptions);
已知就只剩JwtBearerOptions
类型的action<T>委托configureOptions还未设置值,利用AddJwtBearer返回的引用(AddScheme),在第一章 注册身份验证服务的基础上来配置JwtBearerOptions
选项类。
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(options => { options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; })
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "dlht",
ValidateAudience = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey =
new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration.GetSection("JWT_SECRET_KEY").Value!)),
ValidateLifetime = true,
RequireExpirationTime = true,
ClockSkew = TimeSpan.FromSeconds(30)
};
options.SaveToken = true;
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
if (!string.IsNullOrEmpty(accessToken))
{
context.Token = accessToken;
}
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
var e = context.Exception;
return Task.CompletedTask;
}
};
});
2.2 Jwt
验证选项参数汇总——JwtBearerOptions
为了记忆理解上述行为配置的含义,我总结了JwtBearerOptions
选项类的属性和其行为:
属性名 | 类型 | 默认值 | 摘要/行为描述 |
---|---|---|---|
RequireHttpsMetadata | bool | true | 是否需要HTTPS进行元数据地址或权限的访问,默认为true。 |
MetadataAddress | string | 无默认值 | 获取元数据的发现端点。 |
Authority | string? | null | 进行OpenIdConnect调用时使用的权限。 |
Audience | string? | null | 接收到的OpenIdConnect令牌的单个有效受众值。 |
Challenge | string | "Bearer" | 放在"WWW-Authenticate"头中的挑战。 |
Events | JwtBearerEvents | 无默认值 | 由应用程序提供的处理由承载认证处理器引发的事件的对象。 |
BackchannelHttpHandler | HttpMessageHandler? | null | 用于检索元数据的HttpMessageHandler。 |
Backchannel | HttpClient | 无默认值 | 用于检索元数据的后端通道。 |
BackchannelTimeout | TimeSpan | 1分钟 | 使用后端通道进行HTTP调用时的超时时间。 |
Configuration | OpenIdConnectConfiguration? | null | 直接由开发者提供的配置。如果提供,则不会使用MetadataAddress和后端通道属性。 |
ConfigurationManager | IConfigurationManager<OpenIdConnectConfiguration>? | null | 负责从元数据中检索、缓存和刷新配置。如果没有提供,则会使用MetadataAddress和后端通道属性创建一个。 |
RefreshOnIssuerKeyNotFound | bool | true | 在SecurityTokenSignatureKeyNotFoundException之后是否尝试刷新元数据。 |
SecurityTokenValidators | IList<ISecurityTokenValidator> | 一个包含_defaultHandler的列表 | 用于验证访问令牌的ISecurityTokenValidator列表。已过时,建议使用TokenHandlers。 |
TokenHandlers | IList<TokenHandler> | 一个包含_defaultTokenHandler的列表 | 用于验证访问令牌的TokenHandler列表。 |
TokenValidationParameters | TokenValidationParameters | 新实例 | 用于验证身份令牌的参数。 |
SaveToken | bool | true | 定义在成功授权后,是否应该在AuthenticationProperties中存储承载令牌。 |
IncludeErrorDetails | bool | true | 定义是否应该将令牌验证错误返回给调用者。默认启用。 |
MapInboundClaims | bool | true | 定义是否应该将提取的JSON声明的名称映射为声明类型。 |
AutomaticRefreshInterval | TimeSpan | 默认自动刷新间隔 | 自动刷新元数据的频率。 |
RefreshInterval | TimeSpan | 默认刷新间隔 | 在检索失败或显式请求刷新的情况下,两次检索之间的最小时间。 |
UseSecurityTokenValidators | bool | false | 定义是使用TokenHandlers还是SecurityTokenValidators来验证传入的令牌。 |
okenValidationParameters
类在 ASP.NET Core 身份验证框架中用于定义验证 JWT(JSON Web Tokens)时所需的参数。
属性名 | 类型 | 默认行为/摘要描述 |
---|---|---|
AlgorithmValidator | Func<string, bool> | 验证签名算法的委托,用于确定是否接受令牌使用的特定签名算法。 |
ActorValidationParameters | TokenValidationParameters | 用于验证令牌中的 Actor 声明的参数。 |
AudienceValidator | Func<IEnumerable<string>, bool> | 验证受众(Audience)声明的委托。 |
ClockSkew | TimeSpan | 允许的时钟偏差,用于调整令牌的过期时间,以处理时钟不同步的情况。 |
ConfigurationManager | IConfigurationManager<OpenIdConnectConfiguration> | 用于配置管理的接口,例如用于OpenID Connect配置。 |
CryptoProviderFactory | ICryptoProviderFactory | 用于创建加密提供者的工厂。 |
IssuerSigningKey | SecurityKey | 用于验证令牌签名的密钥。 |
IssuerSigningKeys | IEnumerable<SecurityKey> | 用于验证签名的密钥集合。 |
IssuerSigningKeyResolver | Func<TokenValidationContext, IEnumerable<SecurityKey>, IEnumerable<SecurityKey>> | 用于解析发行者签名密钥的委托。 |
IssuerValidator | Func<string, bool> | 验证令牌中的发行者(Issuer)声明的委托。 |
LifetimeValidator | Func<DateTime?, DateTime?, bool> | 验证令牌生命周期的委托。 |
NameClaimType | string | 用于识别名称声明的类型。 |
PropertyBag | IDictionary<string, object> | 一个属性包,用于存储额外的配置信息。 |
RequireAudience | bool | 是否要求令牌中包含受众声明。 |
RequireExpirationTime | bool | 是否要求令牌中包含过期时间声明。 |
RequireSignedTokens | bool | 是否要求令牌必须被签名。 |
RoleClaimType | string | 用于识别角色声明的类型。 |
SaveSigninToken | bool | 在身份验证成功后是否保存签名令牌。 |
TokenReader | ITokenReader | 用于读取令牌的接口。 |
TokenReplayCache | ITokenReplayCache | 用于防止令牌重放的缓存。 |
TokenReplayValidator | Func<TokenReplayValidationResult> | 用于验证令牌是否被重放的委托。 |
TryAllIssuerSigningKeys | bool | 是否尝试使用所有发行者签名密钥来验证签名。 |
TypeValidator | Func<string, bool> | 验证令牌类型(如 JWT)的委托。 |
ValidateActor | bool | 是否验证 Actor 声明。 |
ValidateAudience | bool | 是否验证受众声明。 |
ValidateIssuer | bool | 是否验证发行者声明。 |
ValidateIssuerSigningKey | bool | 是否验证发行者签名密钥。 |
ValidateLifetime | bool | 是否验证令牌的生命周期。 |
ValidateSignatureLast | bool | 是否在验证其他所有声明之后验证签名。 |
ValidateTokenReplay | bool | 是否验证令牌是否被重放。 |
ValidateWithLKG | bool | 是否使用最后已知良好的(Last Known Good)配置来验证令牌。 |
ValidAlgorithms | IEnumerable<string> | 接受的签名算法列表。 |
ValidAudience | string | 单个有效的受众声明。 |
ValidAudiences | IEnumerable<string> | 有效的受众声明列表。 |
ValidIssuer | string | 单个有效的发行者声明。 |
ValidIssuers | IEnumerable<string> | 有效的发行者声明列表。 |
ValidTypes | IEnumerable<string> | 接受的令牌类型列表。 |
2.3 添加授权到指定控制器
builder.Services.AddAuthorization(configure =>
{
configure.AddPolicy("Api", policy => policy.RequireClaim("AuthType", "Api"));
configure.AddPolicy("User", policy => policy.RequireClaim("AuthType", "User"));
});
三、测试
3.1配置授权
[Route("api/[controller]")]
[ApiController]
public class UserController(IUserService _userService) : ControllerBase
{
[Authorize(Policy = "User")] /*一定要添加授权码,不添加接口无法被保护*/
[HttpPost("[action]")]
public async Task<IActionResult> Updata(USER_Test users)
{
var result=await _userService.Updata(users);
return Ok(result);
}
}
我使用了更新用户名与密码的接口,然后正确的得到了未授权的401错误,说明我们的token已经配置成功啦!
3.2 使用token访问授权接口
登录获取token
使用接口测试工具填入token
访问授权更新接口
成功!!!