繁体   English   中英

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

[英]How to implement role authorization with custom database?

我有一个需要使用自定义数据库进行角色授权的应用程序。 将数据库设置了一个tblUsers有一个参照表tblRoles表。 用户也已经被分配到他们的角色。

我还想在每个操作上使用[Authorize(Role = "RoleName")]属性来检查是否"RoleName"经过身份验证的用户分配给数据库中的"RoleName" 我在弄清楚需要修改[Authorize]属性的位置时遇到了很多麻烦,因此它的行为方式如此。 我只是想看看一个用户名是否有角色,我不会有一个页面来管理数据库中的角色。

我已经尝试为 ASP.NET Core Identity实现自定义存储提供程序,但开始看起来这不是我需要的,因为我不会在应用程序中管理角色,而且我不知道它如何影响行为[Authorize]属性。

此外,我可能对[Authorize]属性的工作原理有一个错误的假设。 如果你注意到它,如果你能指出它,我将不胜感激。

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

  1. 在启动时从数据库加载用户和角色到缓存。 如果您还没有在您的程序中设置缓存(并且不想),您可以通过创建一个包含 2 个静态列表的 UserRoleCache 类来为此目的创建自己的缓存。 还有几种在启动时从 db 加载数据的方法,但我发现直接在 Program.cs 中这样做很容易,如下所示。
  2. 定义您的自定义属性以通过迭代缓存中的列表来检查调用用户是否具有所需的角色,如果没有则返回 403。

修改您的 Program 类,如:

    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);
        }
    }

最后制作 Role 属性

    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()
        {

        }
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM