Как реализовать авторизацию ролей с пользовательской базой данных? - PullRequest
0 голосов
/ 19 февраля 2020

У меня есть приложение, которое требует авторизации роли с использованием пользовательской базы данных. База данных настроена с помощью таблицы tblUsers, которая имеет ссылку на таблицу tblRoles. Пользователям также уже назначены их роли.

Я также хочу использовать атрибут [Authorize(Role = "RoleName")] в каждом действии, чтобы проверить, назначен ли аутентифицированный пользователь для "RoleName" в базе данных. У меня много проблем с выяснением, где мне нужно внести изменения в атрибут [Authorize], чтобы он так себя вел. Я просто хочу посмотреть, есть ли у имени пользователя роль, у меня не будет страницы для управления ролями в базе данных.

Я пытался реализовать пользовательских провайдеров хранения для ASP. NET Базовая идентичность , но начинает казаться, что это не то, что мне нужно, потому что я не собираюсь управлять ролями в приложении, и я не могу сказать, как это влияет на поведение атрибута [Authorize].

Кроме того, вполне вероятно, что в моем понимании ложное предположение о том, как работает атрибут [Authorize]. Если вы заметите это, я буду признателен, если вы укажете на это.

1 Ответ

0 голосов
/ 19 февраля 2020

У меня была похожая проблема, когда мой клиент запросил детальные разрешения для каждой роли. Я не смог найти способ изменить атрибут Authorize, но смог реализовать решение с помощью пользовательского атрибута. Но это зависит от одной вещи, т.е. вы можете получить userId вызывающего пользователя? Я использовал аутентификацию cook ie, поэтому я просто включаю userId в свои заявки, когда кто-то входит в систему, поэтому, когда приходит запрос, я всегда могу получить его оттуда. Я думаю, что встроенная логика Session c в asp. net может также выполнить работу, хотя я не могу сказать точно. В любом случае лог c для пользовательской авторизации выглядит так:

  1. Загрузка пользователей и ролей из базы данных в кеш при запуске. Если вы не настроили кеш в своей программе (и не хотите), вы можете просто создать свой собственный для этой цели, создав класс UserRoleCache с двумя списками stati c. Также есть несколько способов загрузки данных из 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>();

    }

Затем приходит лог c для проверки, есть ли у пользователя роль. Обратите внимание, что я использовал массив ролей, потому что иногда вам может понадобиться разрешить доступ к нескольким ролям.

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

Теперь вы можете использовать Атрибут роли в ваших контроллерах:

public class SampleController : ControllerBase
    {

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

        }

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

        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...