一、前言
在上一篇《.NET Core WebAPI 认证授权之JWT(一):JWT介绍》中讲到了JWT的组成,分为三部分,其中标头(header)和载荷(payload)都只是简单的将json内容进行base64编码,而签名部分就要复杂一点,通常会使用HmacSha256或RsaSha256算法进行签名。关于两种算法在上一篇中也有简单的介绍,本文就不多做介绍,直接进行实操落地。本文先介绍使用HmacSHA256算法签名的JWT。开发环境:
VisualStudio 2019 16.8.3
ASP.NET Core 5.0
二、生成Token
生成签名的算法虽然复杂,但好在.NET有内置的API来生成相应算法的JWT。
1.创建一个用于颁发Token项目,当然也可以将颁发Token步骤合并到API项目中。
2.引入Nuget包Microsoft.AspNetCore.Authentication.JwtBearer(APS.NET Core 5.0 WebAPI项目模板如果勾选Enable OpenAPI会自带这个包),生成Token主要用到了这个包关联的Microsoft.IdentityModel.Tokens和System.IdentityModel.Tokens.Jwt两个t程序集。
3.在AuthenticationController中创建一个登录接口,验证用户的账号密码。
public string Login([FromForm] string userName, [FromForm] string password)
{
//验证账号密码
if (userName == password)
{
//返回JWT
return "";
}
else
{
//返回账号密码错误
return "";
}
}
4.验证账号密码正确后,生成JWT。
if (userName == password) //验证账号密码
{
#region 生成Token
var claims = new[] {
new Claim(ClaimTypes.Name, userName)
};
//密钥 网上随便生成的 建议写配置文件中
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI2a2EJ7m872v0afyoSDJT2o1+SitIeJSWtLJU8/Wz2m7gStexajkeD+Lka6DSTy8gt9UwfgVQo6uKjVLG5Ex7PiGOODVqAEghBuS7JzIYU5RvI543nNDAPfnJsas96mSA7L/mD7RTE2drj6hf3oZjJpMPZUQI/B1Qjb5H3K3PNwIDAQAB"));
//定义签名的密钥、算法
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
//创建Token
var token = new JwtSecurityToken(issuer: "leo96.com", //发布者 随便写 可用于验证 建议写配置文件中
audience: "leo96.com", //受众 随便写 可用于验证 建议写配置文件中
claims: claims, //声明 存储其他信息
expires: DateTime.Now.AddMinutes(5), //过期时间 可写配置文件中
signingCredentials: creds); //凭证
//写入Token
string returnToken = new JwtSecurityTokenHandler().WriteToken(token);
#endregion
return returnToken;
}
这是.NET自带的生成JWT的API,此处使用的是HmacSha256算法,其中需要的Key是从网上找的,貌似随便填什么也可以,但是好像不能小于32个字节?(此处不太清楚)三、Token认证和授权
1.创建API项目,引入Nuget包Microsoft.AspNetCore.Authentication.JwtBearer(APS.NET Core 5.0 WebAPI项目模板如果勾选Enable OpenAPI会自带这个包)。
2.添加JWT认证服务和中间件。
#region 添加JWT认证服务
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true, //是否验证Issuer
ValidateAudience = true, //是否验证Audience
ValidateLifetime = true, //是否验证有效时间
ValidateIssuerSigningKey = true, //是否验证key
ValidIssuer = "leo96.com", //建议配置文件读取
ValidAudience = "leo96.com", //建议配置文件读取
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI2a2EJ7m872v0afyoSDJT2o1+SitIeJSWtLJU8/Wz2m7gStexajkeD+Lka6DSTy8gt9UwfgVQo6uKjVLG5Ex7PiGOODVqAEghBuS7JzIYU5RvI543nNDAPfnJsas96mSA7L/mD7RTE2drj6hf3oZjJpMPZUQI/B1Qjb5H3K3PNwIDAQAB")) //建议配置文件读取
};
});
#endregion
#region 认证中间件
app.UseAuthentication();
#endregion
注意:开启了这些验证后,这里的Issuer、Audience、SecurityKey等需要和之前生成Token时候所使用的相关信息一致。
3.添加授权中间件
#region 授权中间件
app.UseAuthorization();
#endregion
PS:WebAPI项目模板默认自带授权中间件。
4.权限拦截
使用Authorize特性标注在Controllor或Action上后,访问相应接口就需要JWT验证,验证不通过,就会返回401状态码。
四、使用
同时运行两个程序,我们先请求Login接口,拿到Token,然后请求API带保护的资源时,在请求标头中带上Token,即可。(详见上篇《.NET Core WebAPI 认证授权之JWT(一):JWT介绍》)