.NET6之Mini API【九、基于角色的身份验证和授权】

内容纲要

身份验证是这样一个过程:由用户提供凭据,然后将其与存储在操作系统、数据库、应用或资源中的凭据进行比较。 在授权过程中,如果凭据匹配,则用户身份验证成功,可执行已向其授权的操作。 授权指判断允许用户执行的操作的过程。也可以将身份验证理解为进入空间(例如服务器、数据库、应用或资源)的一种方式,而授权是用户可以对该空间(服务器、数据库或应用)内的哪些对象执行哪些操作。

微软官方文档

asp.net core支持多种授权,本篇重点说明JWT的基于角色授权方式。

基于JWT角色身份验证和授权,思路是在登录时分发加密的Token,在访问资源时带有这个Token,服务端要验证这个Token是不是自己分发的,如果是,再验证访问范围是否正确,本篇的范围就是那些资源是那种角色访问,得到Token的用户当前是那种角色,也就是角色和资源的匹配。

用asp.net core实现步骤:

1、appsettings.json中配置JWT参

2、添加身份认证和授权服务和中间件

3、定义生成Token的方法和验证Toekn参数的方法

4、登录时验证身份并分发Toekn

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
 
 
var builder = WebApplication.CreateBuilder();
//获取JWT参数,并注入到服务容器
var jwtConfig = new JWTConfig();
builder.Configuration.GetSection("JWTConfig").Bind(jwtConfig);
builder.Services.AddSingleton(jwtConfig);
//添加JJWT方式的身份认证和授权,
builder.Services
    .AddAuthorization()
    .AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, opt =>
    {
        opt.RequireHttpsMetadata = false;
        opt.TokenValidationParameters = JwtToken.CreateTokenValidationParameters(jwtConfig);
    });
 
 
var app = builder.Build();
//使用身份认证和授权的中间件
app.UseAuthentication();
app.UseAuthorization();
 
 
app.MapGet("/hellosystem", (ILogger<Program> logger, HttpContext context) =>
{
    var message = $"hello,system,{context.User?.Identity?.Name}";
    logger.LogInformation(message);
 
 
    return message;
}).RequireAuthorization(new RoleData { Roles = "system" });
 
 
app.MapGet("/helloadmin", (ILogger<Program> logger, HttpContext context) =>
{
    var message = $"hello,admin,{context.User?.Identity?.Name}";
    logger.LogInformation(message);
    return message;
}).RequireAuthorization(new RoleData { Roles = "admin" });
 
 
app.MapGet("/helloall", (ILogger<Program> logger, HttpContext context) =>
{
    var message = $"hello,all roles,{context.User?.Identity?.Name}";
    logger.LogInformation(message);
    return message;
}).RequireAuthorization(new RoleData { Roles = "admin,system" });
 
 
 
 
//登录成功,并分发Token
app.MapPost("/login", [AllowAnonymous] (ILogger<Program> logger, LoginModel login, JWTConfig jwtConfig) =>
{
    logger.LogInformation("login");
    if (login.UserName == "gsw" && login.Password == "111111")
    {
        var now = DateTime.UtcNow;
        var claims = new Claim[] {
                new Claim(ClaimTypes.Role, "admin"),
                new Claim(ClaimTypes.Name, "桂素伟"),
                new Claim(ClaimTypes.Sid, login.UserName),
                new Claim(ClaimTypes.Expiration, now.AddSeconds(jwtConfig.Expires).ToString())
                };
        var token = JwtToken.BuildJwtToken(claims, jwtConfig);
        return token;
    }
    else
    {
        return "username or password is error";
    }
});
 
 
app.Run();
//登录实体
public class LoginModel
{
    public string? UserName { get; set; }
    public string? Password { get; set; }
}
//JWT配置
public class JWTConfig
{
    public string? Secret { get; set; }
    public string? Issuer { get; set; }
    public string? Audience { get; set; }
    public int Expires { get; set; }
}
//JWT操作类型
public class JwtToken
{
    //获取Token
    public static dynamic BuildJwtToken(Claim[] claims, JWTConfig jwtConfig)
    {
        var now = DateTime.UtcNow;
        var jwt = new JwtSecurityToken(
            issuer: jwtConfig.Issuer,
            audience: jwtConfig.Audience,
            claims: claims,
            notBefore: now,
            expires: now.AddSeconds(jwtConfig.Expires),
            signingCredentials: GetSigningCredentials(jwtConfig)
        );
        var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
        var response = new
        {
            Status = true,
            AccessToken = encodedJwt,
            ExpiresIn = now.AddSeconds(jwtConfig.Expires),
            TokenType = "Bearer"
        };
        return response;
    }
 
 
    static SigningCredentials GetSigningCredentials(JWTConfig jwtConfig)
    {
        var keyByteArray = Encoding.ASCII.GetBytes(jwtConfig?.Secret!);
        var signingKey = new SymmetricSecurityKey(keyByteArray);
        return new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
    }
    //验证Token的参数
    public static TokenValidationParameters CreateTokenValidationParameters(JWTConfig jwtConfig)
    {
        var keyByteArray = Encoding.ASCII.GetBytes(jwtConfig?.Secret!);
        var signingKey = new SymmetricSecurityKey(keyByteArray);
        return new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = signingKey,
            ValidateIssuer = true,
            ValidIssuer = jwtConfig?.Issuer,
            ValidateAudience = true,
            ValidAudience = jwtConfig?.Audience,
            ClockSkew = TimeSpan.Zero,
            RequireExpirationTime = true,
        };
    }
}
//mini api添加验证授权的参数类型
public class RoleData : IAuthorizeData
{
    public string? Policy { get; set; }
    public string? Roles { get; set; }
    public string? AuthenticationSchemes { get; set; }
}

验证结果:

1、没有登录,返回401

2、登录,取token

3、正确访问

4、没有授权访问,返回403

全部.NET6之MiniAPI-PDF版本下载地址 https://club.51aspx.com/circle/10569.html

给TA打赏
共{{data.count}}人
人已打赏
.NET

.NET6之Mini API【八、日志】

2022-6-29 19:09:10

.NET

.NET6之Mini API【十、基于策略的身份验证和授权】

2022-6-30 18:28:31

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
今日签到
有新私信 私信列表
搜索