AspNetCore&JWT认证授权

有时想快速搭建一个简单应用,并集成登录功能时,总是会被认证授权绕来绕去,一直想着要搞个授权中心,却把最为简单快捷的方式抛掷脑后。

认证与授权说来说去还是四个核心步骤,登录退出,登录有效后请求资源,请求人是谁与请求人有没有权限请求。

图片

JWT

JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案。其本身只是一种格式或是协议,集成到框架中,然后便按照这种格式或协议来传递信息。

当使用认证授权时,将具有用户信息的令牌以JWT格式的呈现,命名为Id token或是Access token。

项目准备

准备一个Asp.Net Core 6.0的WebApi(前端实现不考虑)。按照如上几个用例挨个实现(退出用例不考虑)

图片


安装Nuget包

<ItemGroup>
  <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
  <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.3" />
  <PackageReference Include="IdentityModel" Version="6.0.0" />
</ItemGroup>

生成JWT格式令牌

增加Account控制器

[ApiController]
[Route("[controller]")]
public class AccountController : ControllerBase
{

}

增加JwtOption

该部分信息用户Jwt格式中所需要的

public class JwtOptions
{
    public const string Name = "Jwt";

    public string Audience { get; set; }
    public string Issuer { get; set; }
    public double ExpiresMinutes { get; set; } = 30d;
    public Encoding Encoding { get; set; } = Encoding.UTF8;
    public string SymmetricSecurityKeyString { get; set; }
    public SymmetricSecurityKey SymmetricSecurityKey => new(Encoding.GetBytes(SymmetricSecurityKeyString));
}

服务注册

builder.Services.Configure<AuthConfigOptions>(builder.Configuration.GetSection(AuthConfigOptions.Name));

配置信息

appsettings.json中增加该块配置

{
  "Jwt": {
    "Audience": "http://localhost:5105",
    "Issuer": "http://localhost:5105",
    "ExpiresMinutes": 30,
    "SymmetricSecurityKeyString": "Symmetric Security Key"
  }
}

注入Option

[ApiController]
[Route("[controller]")]
public class AccountController : ControllerBase
{
    private readonly JwtOptions _jwtOptions;

    public AccountController(IOptionsSnapshot<JwtOptions> jwtOptions)
    {
        _jwtOptions = jwtOptions.Value;
    }
}

增加SignIn方法

此处只模拟存在一个用户,将该用户通过Jwt格式存储信息并颁发token。

[AllowAnonymous]
[HttpPost("Login")]
public IActionResult SignIn([FromBody] SignInDto dto)
{
    //db query...
    //return Unauthorized();

    //user info
    var user = new UserModel()
    {
        Id = Guid.NewGuid(),
        UserName = dto.UserName,
        Email = "test@test.com"
    };

    // 1 定义需要的Cliam信息
    var claims = new[]
    {
        new Claim(JwtClaimTypes.Id, user.Id.ToString("N")),
        new Claim(JwtClaimTypes.Name, user.UserName),
        new Claim(JwtClaimTypes.Email, user.Email)
    };

    // 2 设置SecretKey
    var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.SymmetricSecurityKeyString));

    // 3 设置加密算法
    var algorithm = SecurityAlgorithms.HmacSha256;

    // 4 生成签名凭证信息
    var signingCredentials = new SigningCredentials(secretKey, algorithm);

    // 5 设置token过期时间
    var expires = DateTime.Now.AddMinutes(_jwtOptions.ExpiresMinutes);

    // 6 生成token
    var securityToken = new JwtSecurityToken(
        claims: claims,
        issuer: _jwtOptions.Issuer,
        audience: _jwtOptions.Audience,
        notBefore: DateTime.Now,
        expires: expires,
        signingCredentials: signingCredentials
    );

    var jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
    var token = jwtSecurityTokenHandler.WriteToken(securityToken);

    return Ok(new { token });
}

生成token

图片


请求资源

默认模板生成时自带了一个WeatherForecast控制器,此处将其作为资源,对其添加Authorize特性,控制资源。

[ApiController]
[Route("[controller]")]
[Authorize]
public class WeatherForecastController : ControllerBase
{
  
}

因模板中管道部分默认带上了UseAuthorization,因此再次请求WeatherForecast的方法则会报错,没有为Authorization配置相关服务。
图片

增加服务配置

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.RequireHttpsMetadata = false;
        options.SaveToken = true;
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = false,
            ValidIssuer = jwtOptions.Issuer,
            ValidateAudience = false,
            ValidAudience = jwtOptions.Audience,
            ValidateLifetime = true,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SymmetricSecurityKeyString)),
        };
    });

增加Authentication中间件

app.UseAuthentication();

访问资源

图片

Authorization中间件与Filter区别

在控制器/方法上加Authorize特性,有相应的Filter处理是否有权限,为什么存在了一个Authorization中间件去提前验证?

答:Filter的处理属于MVC的职责范围,而Authorization则是中间件的职责范围,可以认为是总闸与分闸。

图片

2022-04-17,望技术有成后能回来看见自己的脚步

posted @ 2022-04-17 21:30  微笑刺客D  阅读(251)  评论(0编辑  收藏  举报
返回顶部