【问题标题】:ASP.Net Identity built in functions with custom tables in ASP.Net CoreASP.Net Identity 内置函数与 ASP.Net Core 中的自定义表
【发布时间】:2019-02-16 19:58:05
【问题描述】:

我在 .Net 2.1 框架上使用 ASP.Net Core Web Api 2 我有自定义 AppUsers 和 AppRoles 表,与桥表 AppUserRoles 链接

我的主要问题是我想使用[Authorize(Roles = "UserRole")] 由于 User.Identity 工作正常并且我从 User.Identity.Name 获取用户 ID,我认为有一些方法可以在控制器请求之前设置角色并检查它们,或者使用 User.IsInRole("UserRole") 来检查控制器内部。

是否可以以某种方式重建或重载.IsInRole("UserRole") 函数或[Authorize(Roles = "UserRole")] 属性背景函数,以便我可以编写自己的逻辑来检查用户权限?或者将我的表设置为要使用的默认表,这样它就可以在自逻辑上工作。 对于我的任务,速度和安全性一样重要。

如果有其他方法,我愿意接受建议,但我的意思是更好地理解这些功能。

【问题讨论】:

    标签: c# jwt asp.net-identity asp.net-core-webapi authorize-attribute


    【解决方案1】:

    您不需要覆盖 Authorize 或 IsInRole。只需将角色作为声明添加到 User.Identity。您可以使用中间件进行声明转换。

    作为一个例子,我建议你看看PolicyServer。它具有相同的方法。 free OSS version 在中间件中添加声明。

    /// Add the policy server claims transformation middleware to the pipeline.
    /// This middleware will turn application roles and permissions into claims
    /// and add them to the current user
    public static IApplicationBuilder UsePolicyServerClaims(this IApplicationBuilder app)
    {
        return app.UseMiddleware<PolicyServerClaimsMiddleware>();
    }
    

    PolicyServerClaimsMiddleware 在哪里:

    public class PolicyServerClaimsMiddleware
    {
        private readonly RequestDelegate _next;
    
        /// <summary>
        /// Initializes a new instance of the <see cref="PolicyServerClaimsMiddleware"/> class.
        /// </summary>
        /// <param name="next">The next.</param>
        public PolicyServerClaimsMiddleware(RequestDelegate next)
        {
            _next = next;
        }
    
        /// <summary>
        /// Invoke
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="client">The client.</param>
        /// <returns></returns>
        public async Task Invoke(HttpContext context, IPolicyServerRuntimeClient client)
        {
            if (context.User.Identity.IsAuthenticated)
            {
                var policy = await client.EvaluateAsync(context.User);
    
                var roleClaims = policy.Roles.Select(x => new Claim("role", x));
                var permissionClaims = policy.Permissions.Select(x => new Claim("permission", x));
    
                var id = new ClaimsIdentity("PolicyServerMiddleware", "name", "role");
                id.AddClaims(roleClaims);
                id.AddClaims(permissionClaims);
    
                context.User.AddIdentity(id);
            }
            await _next(context);
        }
    }
    

    从启动开始:

    public void ConfigureServices(IServiceCollection services)
    {
    
        services.AddMvcCore(options =>
        {
            // workaround: https://github.com/aspnet/Mvc/issues/7809
            options.AllowCombiningAuthorizeFilters = false;
        })
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
        .AddAuthorization();
    
        // This is not relevant for you, but just to show how policyserver is implemented.
        // The bottom line is that you can implement this anyway you like.
    
        // this sets up the PolicyServer client library and policy
        // provider - configuration is loaded from appsettings.json
        services.AddPolicyServerClient(Configuration.GetSection("Policy"))
            .AddAuthorizationPermissionPolicies();
    
    }
    
    public void Configure(IApplicationBuilder app)
    {
        app.UseAuthentication();
    
        // add this middleware to make roles and permissions available as claims
        // this is mainly useful for using the classic [Authorize(Roles="foo")] and IsInRole functionality
        // this is not needed if you use the client library directly or the new policy-based authorization framework in ASP.NET Core
        app.UsePolicyServerClaims();
    
        app.UseMvc();
    }
    

    该示例从文件中读取配置,这也可能是您的一个选项。但是你也可以实现一个 store 并添加一些缓存。

    如果您想添加一些授权逻辑,那么我建议您创建一些策略和授权处理程序。只需确保在正确的位置使用中间件即可。


    另一种方法是使用您自己的过滤器/属性:

    //using Microsoft.AspNetCore.Authorization;
    //using Microsoft.AspNetCore.Mvc;
    //using Microsoft.AspNetCore.Mvc.Filters;
    
    public class CustomPolicyAttribute : AuthorizeAttribute, IAsyncAuthorizationFilter
    {
        private int _number;
    
        public CustomPolicyAttribute(int number)
        {
            _number = number;
        }
    
        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            var service = (IAuthorizationService)context.HttpContext.RequestServices.GetService(typeof(IAuthorizationService));
    
            var requirement = new CustomRequirement
            {
                Number = _number
            };
            var result = await service.AuthorizeAsync(context.HttpContext.User, null, requirement);
            if (!result.Succeeded)
                context.Result = new ForbidResult();
        }
    }
    

    您可以通过多种方式使用它。用作属性(Authorize 等效项):

    [CustomPolicy(1)]
    public async Task<IActionResult> DoSomething()
    {
    
    }
    

    或手动验证(IsInRole 等效项):

    public class MyController : Controller
    {
        private readonly IAuthorizationService _authorizationService;
    
        public MyController(IAuthorizationService authorizationService)
        {
            _authorizationService = authorizationService;
        }
    
        public async Task<IActionResult> DoSomething(int number)
        {
            var requirement = new CustomRequirement
            {
                Number = number
            };
            var result = await _authorizationService.AuthorizeAsync(User, null, requirement);
            if (!result.Succeeded) return Forbid();
    
            return View("success");
        }
    }
    

    您将需要一个 AuthorizationHandler 来评估需求:

    public class CustomRequirementHandler : AuthorizationHandler<CustomRequirement>
    {
        // Use dependency injection to include services you need.
        public CustomRequirementHandler ()
        {
        }
    
        protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomRequirement requirement)
        {
            // Add your advanced check here.
            if (requirement.Number > 0)
            {
                context.Succeed(requirement);
            }
        }
    }
    

    并在启动时注册:

    services.AddTransient<IAuthorizationHandler, CustomRequirementHandler>();
    

    在处理程序中,您可以添加自己的逻辑。在这种情况下,您不必添加策略,也不必添加授权作为声明。

    【讨论】:

    • 我明白了,我现在会尝试实现它,但在我开始之前,除了通过索赔之外,还有其他“纯粹”的方式吗?如果不是,有没有办法在控制器请求加载之前使用声明进行检查,并带有注释Authorize
    • 感谢您的流畅回答。我现在将尝试实现逻辑。如果我对此有任何问题,我会更新帖子。干杯人!
    • 不客气。请注意,还有关于此的官方文档:docs.microsoft.com/nl-nl/aspnet/core/security/authorization/…
    猜你喜欢
    • 2017-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-19
    • 2016-04-25
    • 1970-01-01
    • 2021-02-13
    • 1970-01-01
    相关资源
    最近更新 更多