У меня была похожая проблема, когда мой клиент запросил детальные разрешения для каждой роли. Я не смог найти способ изменить атрибут Authorize, но смог реализовать решение с помощью пользовательского атрибута. Но это зависит от одной вещи, т.е. вы можете получить userId вызывающего пользователя? Я использовал аутентификацию cook ie, поэтому я просто включаю userId в свои заявки, когда кто-то входит в систему, поэтому, когда приходит запрос, я всегда могу получить его оттуда. Я думаю, что встроенная логика Session c в asp. net может также выполнить работу, хотя я не могу сказать точно. В любом случае лог c для пользовательской авторизации выглядит так:
- Загрузка пользователей и ролей из базы данных в кеш при запуске. Если вы не настроили кеш в своей программе (и не хотите), вы можете просто создать свой собственный для этой цели, создав класс UserRoleCache с двумя списками stati c. Также есть несколько способов загрузки данных из db при запуске, но я нашел, что это легко сделать прямо в Program.cs, как вы увидите ниже.
- Определите свой пользовательский атрибут, чтобы проверить, имеет ли вызывающий пользователь требуемую роль, перебирая списки в кеше и возвращая 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()
{
}
}