.NET6之MiniAPI(十):基于策略的身份验证和授权
作者:互联网
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/axzxs2001/p/16503662.html