什么是JWT:https://www.cnblogs.com/yan7/p/7857833.html
在前后端分离开发中会需要进行用户验证,本篇博客介绍如何在ASP.NET Core WebApi中使用JWT进行用户认证。
本篇博客延续上一篇博客 https://www.cnblogs.com/gygg/p/12849641.html 配置swagger验证功能
开发工具:Visual Studio2019
目标框架:.NET Core 3.1
一、启用swagger验证功能
1.1、AddSwaggerGen()方法中启用swagger验证功能,添加全局安全条件,自定义Heard Token
services.AddSwaggerGen(c =>
{
//启用swagger验证功能
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
{
Description = "在下框中输入请求头中需要添加Jwt授权Token:Bearer Token",
Name = "Authorization",//jwt默认的参数名称
In = ParameterLocation.Header,//jwt默认存放authorization信息的位置(请求头中)
Type = SecuritySchemeType.ApiKey,
BearerFormat = "JWT",
Scheme = "Bearer"
});
//添加全局安全条件
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme{
Reference = new OpenApiReference {
Type = ReferenceType.SecurityScheme,
Id = "Bearer"}
},new string[] { }
}
});
//显示自定义的Heard Token
c.OperationFilter<AuthTokenHeaderParameter>();
});
1.2、添加 AuthTokenHeaderParameter 类,显示自定义的Heard Token
public class AuthTokenHeaderParameter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
operation.Parameters = operation.Parameters ?? new List<OpenApiParameter>();
var isAuthor = operation != null && context != null;
if (isAuthor)
{
//in query header
operation.Parameters.Add(new OpenApiParameter()
{
Name = "Authorization",
Description = "身份验证",
Required = false,
In = ParameterLocation.Header
});
}
if (!context.ApiDescription.HttpMethod.Equals("POST", StringComparison.OrdinalIgnoreCase) &&
!context.ApiDescription.HttpMethod.Equals("PUT", StringComparison.OrdinalIgnoreCase))
{
return;
}
}
}
启动项目,效果图如下

2、注册JWT
2.1、添加 JWTTokenOptions 类
public class JWTTokenOptions
{
/// <summary>
/// 订阅者
/// </summary>
public string Audience { get; set; }
/// <summary>
/// 发起人
/// </summary>
public string Issuer { get; set; }
/// <summary>
/// 过期时间 单位秒
/// </summary>
public long Expire { get; set; }
/// <summary>
/// 秘钥
/// </summary>
public string Secret { get; set; }
}
2.2、在 appsettings.json 中配置JWTToken
"JWTToken": {
"Expire": 3600, //token过期时间 单位s
"Audience": "www.baidu.com", //订阅者
"Issuer": "baidu", //发起人
"Secret": "************************" //秘钥
}
2.3、在 startup 类的 ConfigureServices 方法中注册 jwt
#region 注册jwt
JWTTokenOptions JWTTokenOptions = new JWTTokenOptions();
//获取appsettings的内容
services.Configure<JWTTokenOptions>(this.Configuration.GetSection("JWTToken"));
//将给定的对象实例绑定到指定的配置节
Configuration.Bind("JWTToken", JWTTokenOptions);
//注册到Ioc容器
services.AddSingleton(JWTTokenOptions);
//添加验证服务
services.AddAuthentication(option =>
{
//默认身份验证模式
option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
//默认方案
option.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(option =>
{
//设置元数据地址或权限是否需要HTTP
option.RequireHttpsMetadata = false;
option.SaveToken = true;
//令牌验证参数
option.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
//获取或设置要使用的Microsoft.IdentityModel.Tokens.SecurityKey用于签名验证。
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.
GetBytes(JWTTokenOptions.Secret)),
//获取或设置一个System.String,它表示将使用的有效发行者检查代币的发行者。
ValidIssuer = JWTTokenOptions.Issuer,
//获取或设置一个字符串,该字符串表示将用于检查的有效受众反对令牌的观众。
ValidAudience = JWTTokenOptions.Audience,
//是否验证发起人
ValidateIssuer = false,
//是否验证订阅者
ValidateAudience = false,
////允许的服务器时间偏移量
ClockSkew = TimeSpan.Zero,
////是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比
ValidateLifetime = true
};
//如果jwt过期,在返回的header中加入Token-Expired字段为true,前端在获取返回header时判断
option.Events = new JwtBearerEvents()
{
OnAuthenticationFailed = context =>
{
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
{
context.Response.Headers.Add("Token-Expired", "true");
}
return Task.CompletedTask;
}
};
});
#endregion
2.4、在 startup 类的 Configure 方法中添加认证
app.UseAuthentication(); //添加认证 app.UseAuthorization(); //添加授权(.netCore 3.x中使用)
3、生成JWT
3.1、添加 TokenResult 类
public class TokenResult
{
/// <summary>
/// token字符串
/// </summary>
public string Access_token { get; set; }
/// <summary>
/// 过期时间
/// </summary>
public long Expires_in { get; set; }
}
3.2、添加 JwtTokenHelper 类
public class JwtTokenHelper
{
public JwtTokenHelper()
{
}
public TokenResult AuthorizeToken(int memberId, JWTTokenOptions _tokenOptions)
{
//基于声明的认证
var claims = new[]
{
new Claim(ClaimTypes.Name,memberId.ToString()),
new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString())//jwt的唯一标识
};
//秘钥 转化成UTF8编码的字节数组
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_tokenOptions.Secret));
var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);//资格证书 秘钥加密
var jwtToken = new JwtSecurityToken(_tokenOptions.Issuer, _tokenOptions.Audience, claims,//发起人 订阅者
expires: DateTime.Now.AddSeconds(_tokenOptions.Expire),//过期时间
signingCredentials: credentials);//秘钥
var securityToken = new JwtSecurityTokenHandler().WriteToken(jwtToken);//序列化jwt格式
//生成令牌字符串
return new TokenResult()
{
Access_token = "Bearer " + securityToken,
Expires_in = _tokenOptions.Expire
};
}
}
3.3、添加生成 JWT 方法
[ApiController]
[Route("api/[controller]/[action]")]
public class HomeController : Controller
{
private readonly JWTTokenOptions _tokenOptions;
public HomeController(JWTTokenOptions tokenOptions)
{
_tokenOptions = tokenOptions;
}
/// <summary>
/// 生成jwt
/// </summary>
/// <returns></returns>
[HttpPost]
public TokenResult GenerateJwt()
{
var token = new JwtTokenHelper().AuthorizeToken(123456, _tokenOptions);
return token;
}
}
执行 GenerateJwt 方法,生成 jwt

在需要认证的 Controller 中添加 [Authorize] 特性

若未进行jwt认证,则报错401

若进行了jwt 认证,则正常返回接口
End!
