ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

.NET6之MiniAPI(十):基于策略的身份验证和授权

2022-07-21 21:33:41  阅读:189  来源: 互联网

标签:MiniAPI get 身份验证 context new var NET6 jwtConfig public


  JWT不管是基于角色,还是自定义策略,实现的步骤都是大同小异的,基于自定义策略的步骤如下:

  1、appsettings.json中配置JWT参

  2、添加身份认证和授权服务和中间件,并设置为策略模式和策略名称

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

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

  5、继承AuthorizationHandler<IAuthorizationRequirement>,实现鉴权的规则

  接下来看看具体实现。

 

JWT配置

"JWTConfig": {
    "Secret": "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
    "Issuer": "gsw",
    "Audience": "everone",
    "Expires": 10000
  }

实现自定义策略

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);
//这里是注入权限数据,也可以放在缓存中,以便鉴权时用
builder.Services.AddSingleton(new List<Permission> { new Permission { RoleName = "admin", Url = "/helloadmin", Method = "get" } });
//注入自定义策略处理类型
builder.Services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
//注入身分验证和授权,并且是Policy的名称为Permission
builder.Services
    .AddAuthorization(options =>
    {
        var permissionRequirement = new PermissionRequirement();
        options.AddPolicy("Permission", policy => policy.AddRequirements(permissionRequirement));
    })
    .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();
//map三个get请求,都是.RequireAuthorization("Permission"),基于Permission策略来验证的
app.MapGet("/hellosystem", (ILogger<Program> logger, HttpContext context) =>
{
    var message = $"hello,system,{context.User?.Identity?.Name}";
    logger.LogInformation(message);

    return message;
}).RequireAuthorization("Permission");

app.MapGet("/helloadmin", (ILogger<Program> logger, HttpContext context) =>
{
    var message = $"hello,admin,{context.User?.Identity?.Name}";
    logger.LogInformation(message);
    return message;
}).RequireAuthorization("Permission");

app.MapGet("/helloall", (ILogger<Program> logger, HttpContext context) =>
{
    var message = $"hello,all roles,{context.User?.Identity?.Name}";
    logger.LogInformation(message);
    return message;
}).RequireAuthorization("Permission");

//登录,并分发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; }
}
//Token功能类
public class JwtToken
{
    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);
    }
    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,
        };
    }
}
//权限实本类
public class Permission
{
    public string? RoleName { get; set; }
    public string? Url { get; set; }
    public string? Method { get; set; }
}
//自定义策略授权时的参数类型,这时没参数,所以是个空类型
public class PermissionRequirement : IAuthorizationRequirement
{
}
//自定义策略授权的处理类型
public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
{
    private readonly List<Permission> _userPermissions;
    public PermissionHandler(List<Permission> permissions)
    {
        _userPermissions = permissions;
    }
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
    {
        if (context.Resource is DefaultHttpContext)
        {
            var httpContext = context.Resource as DefaultHttpContext;
            var questPath = httpContext?.Request?.Path;
            var method = httpContext?.Request?.Method;
            var isAuthenticated = context?.User?.Identity?.IsAuthenticated;
            if (isAuthenticated.HasValue && isAuthenticated.Value)
            {
                var role = context?.User?.Claims?.SingleOrDefault(s => s.Type == ClaimTypes.Role)?.Value;
                if (_userPermissions.Where(w => w.RoleName == role && w.Method?.ToUpper() == method?.ToUpper() && w.Url?.ToLower() == questPath).Count() > 0)
                {
                    context?.Succeed(requirement);
                }
                else
                {
                    context?.Fail();
                }
            }
        }
        return Task.CompletedTask;
    }
}

运行结果如下:

1、没有登录,返回401

2、登录,取token

 

 3、正确访问

 

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

 

  想要更快更方便的了解相关知识,可以关注微信公众号 

 

 

标签:MiniAPI,get,身份验证,context,new,var,NET6,jwtConfig,public
来源: https://www.cnblogs.com/ljknlb/p/16503664.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有