场景
客户端根据用户名和密码访问登录接口获取token,服务端登录接口获取账号和密码进行验证,获取用户的角色,若角色是超级管理员则只能授权访问标记为超级管理员的接口,若角色是管理员则只能授权访问标记为管理员的接口。
实现JWT认证
安装JWT包
Microsoft.AspNetCore.Authentication.JwtBearer
配置JWT信息
"JwtSettings": {"Issuer": "YourIssuer","Audience": "YourAudience","SecretKey": "YourSuperSecretKeyThatShouldBeLongAndSecure"
},
创建JWT配置映射实体类
public class JwtSettings
{public string Issuer { get; set; }public string Audience { get; set; }public string SecretKey { get; set; }
}
JWT认证服务配置和添加认证中间件
// 配置 JWT 设置var jwtSettings = builder.Configuration.GetSection("JwtSettings").Get<JwtSettings>();// 添加认证服务builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>{options.TokenValidationParameters = new TokenValidationParameters{ValidateIssuer = true,ValidateAudience = true,ValidateLifetime = true,ValidateIssuerSigningKey = true,ValidIssuer = jwtSettings.Issuer,ValidAudience = jwtSettings.Audience,IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecretKey))};options.Events = new JwtBearerEvents{OnForbidden = async context =>{context.Response.StatusCode = 403;// await context.Response.WriteAsync("服务端拒绝访问:当前身份没有权限访问,请联系管理员开放权限");await context.Response.WriteAsJsonAsync(new { message = "服务端拒绝访问:当前身份没有权限访问,请联系管理员开放权限" });}};});var app = builder.Build();
app.UseAuthentication();
实现自定义策略授权
定义权限策略类
/// <summary>/// 权限策略类/// </summary>public class PermissionRequirement : IAuthorizationRequirement{public string _roleName { get; }public PermissionRequirement(string RoleName){_roleName = RoleName;}}
IAuthorizationRequirement
用于定义授权策略中的具体要求。当你需要实现自定义的授权逻辑时,可以创建实现该接口的类,然后将这些类添加到授权策略中。在用户请求访问受保护资源时,授权系统会检查用户是否满足这些要求。
定义策略处理类
public class PermissionRequirementHandler : AuthorizationHandler<PermissionRequirement>
{protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement){if (context.User.HasClaim(c => c.Type == ClaimTypes.Role && c.Value == requirement._roleName)){context.Succeed(requirement);}else{context.Fail();}await Task.CompletedTask;}
}
AuthorizationHandler
是一个抽象类,位于 Microsoft.AspNetCore.Authorization
命名空间下。它的主要作用是根据特定的授权要求(实现 IAuthorizationRequirement
接口的类)来判断用户是否有权限访问受保护的资源。开发者需要继承 AuthorizationHandler<TRequirement>
泛型类(其中 TRequirement
是具体的授权要求类型),并重写 HandleRequirementAsync
方法来实现自定义的授权逻辑。
配置自定义策略授权和添加授权中间件
// 添加自定义授权策略builder.Services.AddAuthorization(options =>{options.AddPolicy("AdminPolicy", policy => policy.Requirements.Add(new PermissionRequirement("Admin")));options.AddPolicy("SuperAdminPolicy", policy => policy.Requirements.Add(new PermissionRequirement("SuperAdmin")));});var app = builder.Build();
app.UseAuthorization(); //注意,授权中间件放在认证中间件后面
依赖注入
builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped<IAuthorizationHandler, PermissionRequirementHandler>();
实现接口
创建请求实体
public class LoginRequest{public string username { get; set; }public string password { get; set; }}
创建接口
在管理员和超级管理员接口前加上特性进行区分。
[Route("api/[controller]")][ApiController]public class TestController : ControllerBase{private readonly IConfiguration _configuration;public TestController(IConfiguration configuration){_configuration = configuration;}[HttpPost("login")]public IActionResult Login(LoginRequest request){string role = string.Empty;if (request.username == "a" && request.password == "123456"){role = "Admin";}else if (request.username == "b" && request.password == "123456"){role = "SuperAdmin";}var jwtSettings = _configuration.GetSection("JwtSettings").Get<JwtSettings>();var tokenHandler = new JwtSecurityTokenHandler();var key = Encoding.ASCII.GetBytes(jwtSettings.SecretKey);var tokenDescriptor = new SecurityTokenDescriptor{Subject = new ClaimsIdentity(new[]{new Claim(ClaimTypes.Name, request.username),new Claim(ClaimTypes.Role, role)}),Issuer = jwtSettings.Issuer,Audience = jwtSettings.Audience,Expires = DateTime.UtcNow.AddHours(1),SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)};var token = tokenHandler.CreateToken(tokenDescriptor);string tokenString = tokenHandler.WriteToken(token);return Ok(new { token = tokenString, message = "登录成功" });}[HttpGet("GetAdminUserInformation")][Authorize(Policy = "AdminPolicy")]public IActionResult GetAdminUserInformation(){return Ok(new { Name = "管理员", Age = 18, Sex = "男" });}[HttpGet("GetSuperAdminInformation")][Authorize(Policy = "SuperAdminPolicy")]public IActionResult GetSuperAdminInformation(){return Ok(new { Name = "超级管理员", Age = 19, Sex = "男" });}}
请求测试
用管理员账号访问管理员接口ok,访问超级管理员接口返回403
用超级管理员账号访问超级管理员接口ok,访问管理员接口同样返回403