Vue3+.net6实战之完成JWT的配置

ASP.NET Core中使用封装的JWT

.NET封装了对于JWT的操作,让我们在程序中使用JWT进行鉴权和授权更简单。

第1步,我们先在配置系统appsettings.json中配置一个名字为JWT的节点,并在节点下创建SigningKey、ExpireSeconds两个配置项,分别代表JWT的密钥和过期时间(单位为秒)。
我们再创建一个对应JWT节点的配置类JWTOptions,类中包含SigningKey、ExpireSeconds这两个属性。

"JWT": {
  "SigningKey": "fasdfad&9045dafz222#fadpio@0232",
  "ExpireSeconds": "86400"
}
public class JWTOptions
{
    public string SigningKey { get; set; }
    public int ExpireSeconds { get; set; }
}

第2步,通过NuGet为项目安装Microsoft.AspNetCore.Authentication.JwtBearer包,这个包封装了简化ASP.NET Core中使用JWT的操作。

第3步,编写代码对JWT进行配置,把代码内容添加到Program.cs的builder.Build之前。

services.Configure<JWTOptions>(builder.Configuration.GetSection("JWT"));
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(x =>
    {
        var jwtOpt = builder.Configuration.GetSection("JWT").Get<JWTOptions>();
        byte[] keyBytes = Encoding.UTF8.GetBytes(jwtOpt.SigningKey);
        var secKey = new SymmetricSecurityKey(keyBytes);
        x.TokenValidationParameters = new TokenValidationParameters()
        {
            ValidateIssuer = false,
            ValidateAudience = false,
            ValidateLifetime = false,
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = secKey
        };
    });

第4步,在Program.cs的app.UseAuthorization之前添加app.UseAuthentication

第5步,在TestController类中增加登录并且创建JWT的操作方法Login。

[HttpPost]
public async Task<IActionResult> Login(LoginRequest loginRequest, 
    [FromServices] IOptions<JWTOptions> jwtOptions)
{
    string userName = loginRequest.UserName;
    string password = loginRequest.Password;
    var user = await _userManager.FindByNameAsync(userName);
    var success = await _userManager.CheckPasswordAsync(user, password);
    if (!success)
    {
        return BadRequest("失败");
    }
    var claims = new List<Claim>();
    claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString())) ;
    claims.Add(new Claim(ClaimTypes.Name, user.UserName));
    var roles = await _userManager.GetRolesAsync(user);
    foreach (var role in roles)
    {
        claims.Add(new Claim(ClaimTypes.Role, role));
    }
    string jwtToken = BuildToken(claims,jwtOptions.Value);
    return Ok(jwtToken);
}
private static string BuildToken(IEnumerable<Claim> claims, JWTOptions options)
{
    DateTime expires = DateTime.Now.AddSeconds(options.ExpireSeconds);
    byte[] keyBytes = Encoding.UTF8.GetBytes(options.SigningKey);
    var secKey = new SymmetricSecurityKey(keyBytes);
    var credentials = new SigningCredentials(secKey,
        SecurityAlgorithms.HmacSha256Signature);
    var tokenDescriptor = new JwtSecurityToken(expires: expires,
        signingCredentials: credentials, claims: claims);
    return new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);
}

第6步,在需要登录才能访问的控制器类上添加[Authorize]这个ASP.NET Core内置的Attribute。

[Route("[controller]/[action]")]
[ApiController]
[Authorize]
public class TempController : ControllerBase
{
    [HttpGet]
    public IActionResult Hello()
    {
        string id = this.User.FindFirst(ClaimTypes.NameIdentifier)!.Value;
        string userName = this.User.FindFirst(ClaimTypes.Name)!.Value;
        IEnumerable<Claim> roleClaims = this.User.FindAll(ClaimTypes.Role);
        string roleNames = string.Join(',', roleClaims.Select(c => c.Value));
        return Ok($"id={id},userName={userName},roleNames ={roleNames}");
    }
}

添加的[Authorize]表示这个控制器类下所有的操作方法都需要登录后才能访问。
ControllerBase中定义的ClaimsPrincipal类型的User属性代表当前登录用户的身份信息,我们可以通过ClaimsPrincipal的Claims属性获得当前登录用户的所有Claim信息,不过我们一般通过FindFirst方法根据Claim的类型来查找需要的Claim,如果用户身份信息中含有多个同类型的Claim,我们则可以通过FindAll方法来找到所有Claim。

完成代码后,运行项目,然后访问/Test/Login,并且在请求报文中填上正确的用户名和密码,请求成功并获得返回的JWT。
接下来我们访问/Temp/Hello路径。运行显示状态码401,没有授权,所以访问被拒绝。

ASP.NET Core要求(这也是HTTP的规范)JWT放到名字为Authorization的HTTP请求报文头中,报文头的值为“Bearer JWT”。默认情况下,我们无法在Swagger中添加请求报文头,因此我们需要借助第三方工具来发送带自定义报文头的HTTP请求。
以Postman为例,我们在请求的【Headers】中手工添加名字为Authorization的报文头,在Postman中发送的请求和服务器的响应如图所示。
在这里插入图片描述

Authorization的值中的“Bearer”和JWT之间一定要通过空格分隔。从服务器的响应可以看出,服务器返回的HTTP状态码为200,请求成功。

对于客户端获得的JWT,在前端项目中,我们可以把令牌保存到Cookie、LocalStorLocalStorage等位置,从而在后续请求中重复使用,而对于移动App、PC客户端,我们可以把令牌保存到配置文件中或者本地文件数据库中。当执行【退出登录】操作的时候,我们只要在客户端本地把JWT删除即可。

  • [Authorize]的注意事项

ASP.NET Core中身份验证和授权验证的功能由Authentication、Authorization中间件提供,我们在Program.cs中编写的app.UseAuthenticationapp.UseAuthorization就用于添加相应中间件到管道中。

**[Authorize]这个Attribute既可以被添加到控制器类上,也可以被添加到操作方法上。**我们可以在控制器类上标注[Authorize],那么这个控制器类中的所有操作方法都会被进行身份验证和授权验证;对于标注了[Authorize]的控制器类,如果其中某个操作方法不想被验证,我们可以在这个操作方法上添加[AllowAnonymous]。如果其中某个操作方法需要被验证,我们也可以不在类上添加,而在操作方法上添加[Authorize]。

在发送请求的时候,我们只要按照HTTP的要求,把JWT按照“Bearer JWT”格式放到名字为Authorization的请求报文头中即可。ASP.NET Core会按照HTTP的规范,从Authorization中取出令牌,并且进行校验、解析,然后把解析结果填充到User属性中,这一切都是ASP.NET Core完成的,不需要开发人员自己编写代码。

Asp.Net Core鉴权授权:在Swaggerr中的Token验证

Swagger中默认没有提供设置自定义HTTP请求报文头的方式,因此对于需要传递Authorization报文头的接口,调试起来很麻烦。我们可以通过对OpenAPI进行配置,从而让Swagger中可以发送Authorization报文头。

我们需要修改Program.cs的AddSwaggerGen方法调用。

builder.Services.AddSwaggerGen(c =>
{
var scheme = new OpenApiSecurityScheme()
{
Description = “Authorization header. \r\nExample: ‘Bearer 12345abcdef’”,
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = “Authorization”
},
Scheme = “oauth2”,
Name = “Authorization”,
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
};
c.AddSecurityDefinition(“Authorization”, scheme);
var requirement = new OpenApiSecurityRequirement();
requirement[scheme] = new List();
c.AddSecurityRequirement(requirement);
});
添加完以上代码后,重启并运行项目,会发现在Swagger界面的右上角增加了一个【Authorize】按钮。点击按钮后,弹出对话框的文本框,我们输入“Bearer JWT”,然后单击【Authorize】按钮,这样在这个界面之后的请求中,浏览器都会自动在请求报文头中加入Authorization报文头。当然,如果界面关闭或重启了,我们就必须重新输入Authorization报文头的值。
image

设置完授权对话框后,再在Swagger界面中发起对需要授权接口的请求,就可以看到服务器端的身份验证成功了。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

栀梦星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值