如何使用自定义数据库实现角色授权?

问题描述 投票:0回答:1

我有一个需要使用自定义数据库进行角色授权的应用程序。数据库使用tblUsers表建立,该表引用了tblRoles表。用户也已经分配了他们的角色。

我还想在每个操作上使用[Authorize(Role = "RoleName")]属性,以检查是否将经过身份验证的用户分配给数据库中的"RoleName"。我在弄清楚需要在何处对[Authorize]属性进行修改以使其具有这种行为时遇到了很多麻烦。我只想看看用户名是否具有角色,就没有一个页面来管理数据库中的角色。

我已经尝试实现custom storage providers for ASP.NET Core Identity,但是它开始看起来并不是我所需要的,因为我不打算管理应用程序中的角色,而且我无法确定它如何影响[Authorize]的行为属性。

[此外,我对[Authorize]属性的工作原理可能有一个错误的假设。如果您注意到了,请指出。

asp.net-mvc asp.net-core authorize-attribute asp.net-authorization
1个回答
0
投票

当我的客户要求为每个角色提供精细权限时,我遇到了类似的问题。我找不到修改Authorize属性的方法,但是能够使用自定义属性实现解决方案。但这取决于一件事,即您可以获取主叫用户的userId吗?我使用Cookie身份验证,因此当有人登录时,我只在声明中包含userId,因此当请求到来时,我总是可以从那里获取它。我认为asp.net中的内置Session逻辑也可以完成任务,但是我不能肯定地说。无论如何,自定义授权的逻辑是这样的:

  1. 在启动时将用户和角色从数据库加载到缓存。如果您尚未在程序中设置缓存(并且不想这样做),则可以为此创建一个带有2个静态列表的UserRoleCache类,从而为此目的自行创建缓存。另外,有几种在启动时从db加载数据的方法,但是我发现在Program.cs中直接进行操作很容易,如下所示。
  2. 通过遍历缓存中的列表来定义您的自定义属性以检查主叫用户是否具有所需角色,如果没有,则返回403。>
  3. 像这样修改您的程序类:

    public class Program
    {
        public static async Task Main(string[] args)
        {
            IWebHost webHost = CreateWebHostBuilder(args).Build();

            using (var scope = webHost.Services.CreateScope())
            {
                //Get the DbContext instance. Replace MyDbContext with the 
                //actual name of the context in your program
                var context = scope.ServiceProvider.GetRequiredService<MyDbContext>();

                List<User> users = await context.User.ToListAsync();
                List<Role> roles = await context.Role.ToListAsync();

                //You may make getters and setters, this is just to give you an idea
                UserRoleCache.users = users;
                UserRoleCache.roles = roles;

            }

            webHost.Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();

    }

然后是检查用户是否具有角色的逻辑。注意,我使用了一系列角色,因为有时您希望允许访问多个角色。

    public class RoleRequirementFilter : IAuthorizationFilter
    {
        private readonly string[] _roles;

        public PermissionRequirementFilter(string[] roles)
        {
            _roles = roles;
        }

        public void OnAuthorization(AuthorizationFilterContext context)
        {
            bool hasRole = false;

            //Assuming there's a way you can get the userId
            var userId = GetUserId();

            User user = UserRoleCache.users.FirstOrDefault(x => x.Id == userId);
            //Where roleType is the name of the role like Admin, Manager etc
            List<Role> roles = UserRoleCache.roles.FindAll(x => _roles.Contains(x.RoleType))

            foreach(var role in roles)
            {
                if(user.RoleId == role.Id)
                {
                    hasRole = true;
                    break;
                }
            }

            if (!hasRole)
                context.Result = new StatusCodeResult(403);
        }
    }

最后创建角色属性

    public class RoleAttribute : TypeFilterAttribute
    {
        public RoleAttribute(params string[] roles) : base(typeof(RoleRequirementFilter))
        {
            Arguments = new object[] { roles };
        }
    }

现在您可以在控制器中使用Role属性:

public class SampleController : ControllerBase
    {

        [HttpGet]
        [Role("Admin", "Manager")]
        public async Task<ActionResult> Get()
        {

        }

        [HttpPost]
        [Role("Admin")]
        public async Task<ActionResult> Post()
        {

        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.