C#动态注册RBAC
1.PermissionPolicyProvider:每次[Authorize(Policy="xxx")]调用时动态生成Policy
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
namespace Infrastructure.Security
{
public class PermissionPolicyProvider : IAuthorizationPolicyProvider
{
private readonly DefaultAuthorizationPolicyProvider _fallbackPolicyProvider;
public PermissionPolicyProvider(IServiceProvider serviceProvider)
{
var options = serviceProvider.GetRequiredService<Microsoft.Extensions.Options.IOptions<AuthorizationOptions>>();
_fallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options);
}
public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
{
return _fallbackPolicyProvider.GetDefaultPolicyAsync();
}
public Task<AuthorizationPolicy?> GetFallbackPolicyAsync()
{
return _fallbackPolicyProvider.GetFallbackPolicyAsync();
}
public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{
// 每次请求动态生成 Policy
var policy = new AuthorizationPolicyBuilder()
.AddRequirements(new PermissionRequirement(policyName))
.Build();
return Task.FromResult(policy);
}
}
}
2.PermissionHandler:判断JWT Claim "permission"是否包含所需权限
using Microsoft.AspNetCore.Authorization;
namespace Infrastructure.Security
{
public class PermissionHandler : AuthorizationHandler<PermissionRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
{
var permissions = context.User?.Claims
.Where(c => c.Type == "permission")
.Select(c => c.Value)
.ToList();
if (permissions != null && permissions.Contains(requirement.Permission))
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
public class PermissionRequirement : IAuthorizationRequirement
{
public string Permission { get; }
public PermissionRequirement(string permission)
{
Permission = permission;
}
}
[AttributeUsage(AttributeTargets.Method)]
public class PermissionAttribute : AuthorizeAttribute
{
public PermissionAttribute(string permission)
{
Policy = permission;
}
}
}
3.Programe:注册相关服务
using Application.Interfaces;
using Application.Services;
using Infrastructure.Persistence;
using Infrastructure.Security;
using Infrastructure.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System.IdentityModel.Tokens.Jwt;
using System.Text;
namespace WebApi
{
public class Program
{
public static void Main(string[] args)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My WMS API", Version = "v1" });
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer scheme. \r\n\r\n" +
"Enter 'Bearer' [space] and then your token in the text input below.\r\n\r\n" +
"Example: \"Bearer eyJhbGciOiJI...\"",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer"
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Scheme = "oauth2",
Name = "Bearer",
In = ParameterLocation.Header
},
new List<string>()
}
});
});
//DbContext
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseMySql(
builder.Configuration.GetConnectionString("Default"),
ServerVersion.AutoDetect(builder.Configuration.GetConnectionString("Default"))
)
);
//Application
builder.Services.AddScoped<IAuthService, AuthService>();
builder.Services.AddScoped<JwtService>();
//JWT
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
var secretKey = builder.Configuration["Jwt:SecretKey"];
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey))
};
});
//RBAC
builder.Services.AddSingleton<IAuthorizationPolicyProvider, PermissionPolicyProvider>();
builder.Services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
builder.Services.AddAuthorization();
builder.Services.AddControllers();
var app = builder.Build();
// Configure the HTTP request pipeline.
// Swagger
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My WMS API V1");
});
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
}
}
}
4.appsettings:配置
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ConnectionStrings": {
"Default": "server=localhost;database=common;user=root;password=123456;"
},
"Jwt": {
"Issuer": "BackendManagementSystem",
"Audience": "BackendManagementSystem",
"SecretKey": "4f9T8xvU3QeWbN7gRjk2ZLmPqC1yAhS6tYdF0KpVwX9oE5BnC8UzGqR2sTjM1nHb",
"AccessTokenMinutes": "30", // JWT 有效期,单位分钟
"RefreshTokenDays": "7" // RefreshToken 存活天数
},
"AllowedHosts": "*"
}

浙公网安备 33010602011771号