最近在研究Asp.net Core基于JWT授权码模式去实现策略授权(根据用户的角色动态判断是否拥有对访问接口的权限).在完成jwt的授权码和模拟用户,角色等数据后,想着去在策略授权的时候直接去访问数据库的数据。发现这并不容易。查找一些资料后
1 //连接字符串 2 services.AddDbContext<JWTContext>(options => 3 options.UseSqlServer(Configuration.GetConnectionString("JWTDBConnection"))); 4 5 services.AddScoped<IAppSettings, AppSettings>(); 6 7 //读取数据库配置策略授权(重点) 8 services.AddOptions<AuthorizationOptions>().Configure<IServiceScopeFactory>((options, sp) => 9 { 10 using (var scope = sp.CreateScope()) 11 { 12 IAppSettings settings = scope.ServiceProvider.GetRequiredService<IAppSettings>(); 13 var Permission = settings.userPermissions(); 14 options.AddPolicy("Permission", policy => policy.Requirements.Add(Permission)); 15 } 16 });
查看上面的代码我们可以发现,在连接数据的下面。我们让容器中注入了一个服务
services.AddScoped<IAppSettings, AppSettings>();
1 public interface IAppSettings 2 { 3 PolicyRequirement userPermissions(); 4 }
1 public class AppSettings:IAppSettings 2 { 3 public JWTContext context; 4 5 public AppSettings(JWTContext context) 6 { 7 this.context = context; 8 } 9 10 public PolicyRequirement userPermissions() 11 { 12 PolicyRequirement policyRequirement = new PolicyRequirement(); 13 14 var _jWTContext = context; 15 var perssions = _jWTContext.permssions; 16 var roles = _jWTContext.roles; 17 policyRequirement.DeniedAction = new PathString("/api/nopermission"); 18 policyRequirement.UserPermissions = (from r in roles 19 join p in perssions 20 on r.Id equals p.RoleId 21 select new UserPermission 22 { 23 UserName = r.Name, 24 Url = "/WeatherForecast" + p.Permssions 25 }).ToList(); 26 27 28 return policyRequirement; 29 }
下面是实现授权服务的一些代码
1 public class PolicyRequirement: IAuthorizationRequirement 2 { 3 4 /// <summary> 5 /// 用户权限集合 6 /// </summary> 7 public List<UserPermission> UserPermissions { get; set; } 8 /// <summary> 9 /// 无权限action 10 /// </summary> 11 public string DeniedAction { get; set; } 12 /// <summary> 13 /// 构造 14 /// </summary> 15 public PolicyRequirement() 16 { 17 18 //没有权限则跳转到这个路由 19 DeniedAction = new PathString("/api/nopermission"); 20 //用户有权限访问的路由配置,当然可以从数据库获取 21 UserPermissions = new List<UserPermission> { 22 new UserPermission { Url="/WeatherForecast/Tourist", UserName="user"}, 23 }; 24 } 25 } 26 27 28 29 /// <summary> 30 /// 用户权限承载实体 31 /// </summary> 32 public class UserPermission 33 { 34 /// <summary> 35 /// 用户名 36 /// </summary> 37 public string UserName { get; set; } 38 /// <summary> 39 /// 请求Url 40 /// </summary> 41 public string Url { get; set; } 42 }
1 public class PolicyHandler : AuthorizationHandler<PolicyRequirement> 2 { 3 4 5 protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PolicyRequirement requirement) 6 { 7 //var httpContext = ((context.Resource) as Microsoft.AspNetCore.Routing.RouteEndpoint); 8 //dynamic httpContext = context.Resource; 9 10 var httpContext = context.Resource as HttpContext; 11 12 var questUrl = httpContext.Request.Path.Value; 13 14 //赋值用户权限 15 var userPermissions = requirement.UserPermissions; 16 //是否经过验证 17 var isAuthenticated = context.User.Identity.IsAuthenticated; 18 19 if (isAuthenticated) 20 { 21 if (userPermissions.GroupBy(g => g.Url).Any(w => w.Key == questUrl)) 22 { 23 //用户名 24 var userName = context.User.Claims.Where(x=>x.Type=="roless").First().Value; 25 if (userPermissions.Any(w => w.UserName == userName && w.Url== questUrl)) 26 { 27 context.Succeed(requirement); 28 } 29 else 30 { 31 //无权限跳转到拒绝页面 32 //context.Fail(); 33 //httpContext.Response.Redirect("https://localhost:5001/api/nopermission"); 34 context.Fail(); 35 var Response = httpContext.Response; 36 var message = Encoding.UTF8.GetBytes("User with Super Admin role cannot be edited"); 37 38 Response.OnStarting(async () => 39 { 40 httpContext.Response.StatusCode = 429; 41 await Response.Body.WriteAsync(message, 0, message.Length); 42 }); 43 } 44 } 45 else 46 { 47 context.Succeed(requirement); 48 } 49 50 } 51 return Task.CompletedTask; 52 } 53 }