首先安装jwt所需的Nuget包
Microsoft.AspNetCore.Authentication.JwtBearer
<!-- Swagger授权扩展包 -->
Swashbuckle.AspNetCore.Filters
创建一个类里面写两个方法用来配置Swagger和JWT
/// <summary>
/// Jwt以及Swagger扩展配置
/// </summary>
public static class JwtExtension
{
/// <summary>
/// Jwt配置授权
/// </summary>
/// <param name="services"></param>
/// <param name="builder"></param>
/// <returns></returns>
public static AuthenticationBuilder MyAddAuthentication(this IServiceCollection services, WebApplicationBuilder builder)
{
return services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,// 是否验证Issuer
ValidateAudience = true,// 是否验证Audience
ValidateLifetime = true,// 是否验证失效时间
ClockSkew = TimeSpan.FromSeconds(30),// 有效时间
ValidateIssuerSigningKey = true,// 是否验证SecurityKey
ValidAudience = builder.Configuration.GetSection("JWT:Audience").Value,// Audience
ValidIssuer = builder.Configuration.GetSection("JWT:Issuer").Value,// Issuer,这两项和前面签发jwt的设置一致
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration.GetSection("JWT:SecurityKey").Value))// SecurityKey
};
options.Events = new JwtBearerEvents
{
// 此处为权限验证失败后触发的事件
OnChallenge = context =>
{
// 此处代码为终止.Net Core默认的返回类型和数据结果,这个很重要哦,必须
context.HandleResponse();
// 自定义自己想要返回的数据结果,我这里要返回的是Json对象,通过引用Newtonsoft.Json库进行转换
var payload = JsonConvert.SerializeObject(new Result(DataModel.Enum.HttpCode.Unauthorized, DataModel.Enum.HttpMessage.Unauthorized));
// 自定义返回的数据类型
context.Response.ContentType = "application/json";
// 自定义返回状态码,默认为401 我这里改成 200
context.Response.StatusCode = 200;
// 输出Json数据结果
context.Response.WriteAsync(payload);
return Task.FromResult(0);
},
// 权限不够,例如角色组Role无该权限
OnForbidden = context =>
{
// 自定义自己想要返回的数据结果,我这里要返回的是Json对象,通过引用Newtonsoft.Json库进行转换
var payload = JsonConvert.SerializeObject(new Result(DataModel.Enum.HttpCode.Forbidden, DataModel.Enum.HttpMessage.Forbidden));
// 自定义返回的数据类型
context.Response.ContentType = "application/json";
// 自定义返回状态码,默认为403 我这里改成 200
context.Response.StatusCode = 200;
// 输出Json数据结果
context.Response.WriteAsync(payload);
return Task.FromResult(0);
}
};
});
}
/// <summary>
/// Swagger配置信息
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection MyAddSwaggerGen(this IServiceCollection services)
{
return services.AddSwaggerGen(c =>
{
// Swagger文档版本控制(ApiExplorerSettings中GroupName需要和ApiVersion枚举定义一致)
typeof(DataModel.Enum.ApiVersion).GetEnumNames().ToList().ForEach(name =>
{
c.SwaggerDoc(name, new OpenApiInfo { Title = "DotNET6原生API", Version = name, Description = "<b><a href='https://gitee.com/lovetianci/TianciDotNET6API'>项目地址</a><b>" });
});
// 控制器注释(需在对应项目>属性>输出>文档文件:生成包含API文档的文件√)
c.IncludeXmlComments(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TianciDotNET6API.xml"), true);
// 实体类注释(需在对应项目>属性>输出>文档文件:生成包含API文档的文件√)
c.IncludeXmlComments(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DataModel.xml"), true);
// Summary注释显示授权组名称信息
c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();
// 加这个带锁,false为请求接口未授权将不会显示返回值例如Forbidden
c.OperationFilter<SecurityRequirementsOperationFilter>(false);
var security = new OpenApiSecurityScheme
{
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
// 如果是ApiKey则需要输入Bearer token(中间有空格)
// 因为Scheme填写了Bearer,所以Swagger只需输入token即可(2022年8月29日)
// 如果是http则直接输入token
Description = "直接在下框中输入token<br/><b>授权地址:/api/Login/Login</b>",
Name = "Authorization",
Scheme = "Bearer",
BearerFormat = "JWT"
};
// oauth2唯一不可变
c.AddSecurityDefinition("oauth2", security);
// 添加全局安全要求,所需方案的字典(逻辑与)密钥必须对应于通过 AddSecurityDefinition 定义的方案
// 如果方案是oauth2类型,则值是范围列表,否则必须是空数组
//c.AddSecurityRequirement(new OpenApiSecurityRequirement { { security, new string[] { } } });
// 请求头过滤,上面写了鉴权失败返回值所以这不需要
//c.OperationFilter<AddResponseHeadersFilter>();
});
}
}
配置文件appsetting.json中配置对应的密钥字段(模拟数据)
"JWT": {
"Issuer": "Client",
"Audience": "Server",
"SecurityKey": "EF1DA5B7-C4FA-4240-B997-7D1701BF9BE2"
},
将服务添加到容器
var builder = WebApplication.CreateBuilder(args);
// Swagger配置
builder.Services.MyAddSwaggerGen();
// 注册jwt
builder.Services.MyAddAuthentication(builder);
配置HTTP请求管道
var app = builder.Build();
// 认证
app.UseAuthentication();
// 授权
app.UseAuthorization();
// 开启Swagger
app.UseSwagger();
app.UseSwaggerUI(c =>
{
// Swagger文档版本控制
typeof(DataModel.Enum.ApiVersion).GetEnumNames().ToList().ForEach(name =>
{
c.SwaggerEndpoint($"/Swagger/{name}/Swagger.json", $"{name}");
// 设置首页index为Swagger
c.RoutePrefix = string.Empty;
// 设置网页Title
c.DocumentTitle = "TianciDotNET6API接口文档";
// 设置为none默认可折叠所有方法
c.DocExpansion(DocExpansion.None);
// 设置为-1 可不显示models
c.DefaultModelsExpandDepth(-1);
});
});
登录获取Token的方法可以简单定义一个
_configuration为注入的IConfiguration接口
string userToken = string.Empty;
var claims = new[]
{
new Claim(ClaimTypes.Name, "UserName"),
new Claim(ClaimTypes.Role, "RoleName"),
new Claim(JwtRegisteredClaimNames.Sub,"UserName"),
new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString())
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration.GetSection("JWT:SecurityKey").Value));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken
(
issuer: _configuration.GetSection("JWT:Issuer").Value,// 签发人
audience: _configuration.GetSection("JWT:Audience").Value,// 受众人
claims: claims,
expires: DateTime.Now.AddMinutes(30),//过期时间
signingCredentials: creds
);
userToken = new JwtSecurityTokenHandler().WriteToken(token);
最后控制器添加[Authorize]用来鉴权