最近在研究 Asp.net Core 基于 JWT 授权码模式去实现策略授权 (根据用户的角色动态判断是否拥有对访问接口的权限). 在完成 jwt 的授权码和模拟用户,角色等数据后,想着去在策略授权的时候直接去访问数据库的数据。发现这并不容易。查找一些资料后

# 核心代码

// 连接字符串
 services.AddDbContext<JWTContext>(options =>
 options.UseSqlServer (Configuration.GetConnectionString ("JWTDBConnection")));
 services.AddScoped<IAppSettings, AppSettings>();
 // 读取数据库配置策略授权 (重点)
 services.AddOptions<AuthorizationOptions>().Configure<IServiceScopeFactory>((options, sp) =>
 {
    using (var scope = sp.CreateScope ())
    {
        IAppSettings settings = scope.ServiceProvider.GetRequiredService<IAppSettings>();
        var Permission = settings.userPermissions ();
        options.AddPolicy ("Permission", policy => policy.Requirements.Add (Permission));
    }
});

查看上面的代码我们可以发现,在连接数据的下面。我们让容器中注入了一个服务:
services.AddScoped<IAppSettings, AppSettings>()

# 定义接口

public interface IAppSettings  
 {  
      PolicyRequirement userPermissions();  
 }

# 实现接口

public class AppSettings:IAppSettings
    {
        public JWTContext context;
        public AppSettings(JWTContext context)
        {
            this.context = context;
        }
        public PolicyRequirement userPermissions()
        {
            PolicyRequirement policyRequirement = new PolicyRequirement();
            var _jWTContext = context;
            var perssions = _jWTContext.permssions;
            var roles = _jWTContext.roles;
            policyRequirement.DeniedAction = new PathString("/api/nopermission");
            policyRequirement.UserPermissions = (from r in roles
                               join p in perssions
                               on r.Id equals p.RoleId
                               select new UserPermission
                               {
                                   UserName = r.Name,
                                   Url = "/WeatherForecast" + p.Permssions
                               }).ToList();
            return policyRequirement;
        }

# 策略授权的核心代码

public class PolicyRequirement: IAuthorizationRequirement
    {
        /// <summary>
        /// 用户权限集合
        /// </summary>
        public List<UserPermission> UserPermissions { get;  set; }
        /// <summary>
        /// 无权限 action
        /// </summary>
        public string DeniedAction { get; set; }
        /// <summary>
        /// 构造
        /// </summary>
        public PolicyRequirement ()
        {
            // 没有权限则跳转到这个路由
            DeniedAction = new PathString ("/api/nopermission");
            // 用户有权限访问的路由配置,当然可以从数据库获取
            UserPermissions = new List<UserPermission> {
                              new UserPermission {  Url="/WeatherForecast/Tourist", UserName="user"},
                          };
        }
    }
    /// <summary>
    /// 用户权限承载实体
    /// </summary>
    public class UserPermission
    {
        /// <summary>
        /// 用户名
        /// </summary>
        public string UserName { get; set; }
        /// <summary>
        /// 请求 Url
        /// </summary>
        public string Url { get; set; }
    }
public class PolicyHandler : AuthorizationHandler<PolicyRequirement>
    {
        protected override Task HandleRequirementAsync (AuthorizationHandlerContext context, PolicyRequirement requirement)
        {
            //var httpContext = ((context.Resource) as Microsoft.AspNetCore.Routing.RouteEndpoint);
            //dynamic httpContext = context.Resource;
            var httpContext = context.Resource as HttpContext;
            var questUrl = httpContext.Request.Path.Value;
            // 赋值用户权限
            var userPermissions = requirement.UserPermissions;
            // 是否经过验证
            var isAuthenticated = context.User.Identity.IsAuthenticated;
            if (isAuthenticated)
            {
                if (userPermissions.GroupBy (g => g.Url).Any (w => w.Key == questUrl))
                {
                    // 用户名
                    var userName = context.User.Claims.Where (x=>x.Type=="roless").First ().Value;
                    if (userPermissions.Any (w => w.UserName == userName && w.Url== questUrl))
                    {
                        context.Succeed (requirement);
                    }
                    else
                    {
                        // 无权限跳转到拒绝页面
                        //context.Fail ();
                        //httpContext.Response.Redirect ("https://localhost:5001/api/nopermission");
                        context.Fail ();
                        var Response = httpContext.Response;
                        var message = Encoding.UTF8.GetBytes ("User with Super Admin role cannot be edited");
                        Response.OnStarting (async () =>
                        {
                            httpContext.Response.StatusCode = 429;
                            await Response.Body.WriteAsync (message, 0, message.Length);
                        });
                    }
                }
                else
                {
                    context.Succeed (requirement);
                }
            }
            return Task.CompletedTask;
        }
    }
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

teapus 微信支付

微信支付

teapus 支付宝

支付宝