Wykonanie akcji w kontrolerze przez nie zalogowanego użytkownika można zabezpieczyć dodając atrybut: [Authorize]. A jak pozwolić wykonać akcję tylko użytkownikowi ze specjalnymi uprawnieniami?
Można zadeklarować własny atrybut, który dziedziczy po AuthorizeAttribute i w nim dodać logikę sprawdzenia, czy dany użytkownik może daną akcję wykonać.
Zacznijmy od tego, że użytkownik należy do jakiejś roli. Można tu wykorzystać role wbudowane lub dodać własny mechanizm ról. Ten drugi przypadek jest kuszący, jeśli przewidujemy, że wbudowane role mogą nam w przyszłości nie wystarczyć. Np., gdy będziemy chcieli przypisywać role w ramach czasowych.
Zdefiniowałem enum.:
public enum Role
{
adminOrganization = 1,
accountant = 2
}
Kod mojego atrybutu:
public class AuthorizeCustomAttribute : AuthorizeAttribute
{
private readonly List<Role> _allowedroles;
public AuthorizeCustomAttribute(params Role[] roles)
{
_allowedroles = roles.ToList();
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext.User == null)
return false;
return UserOrganizationRolesHelper.IsUserRole(httpContext.User.Identity.Name, _allowedroles);
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary
{
{ "controller", "Home" },
{ "action", "UnAuthorized" }
});
}
}
Z atrybutu korzystamy:
[AuthorizeCustom(Role.adminOrganization, Role.accountant)]
public class PlacesController : Controller
Logika sprawdzenia, czy użytkownik należy do roli jest związanaz moim rozwiązaniem trzymania przypisanych do użytkownika ról:
public static bool IsUserRole(string userName, IList<Role> roles)
{
var userOrg = GetUserOrganization(userName);
List<UserRole> userRoles = JsonConvert.DeserializeObject<List<UserRole>>(userOrg.Roles);
return userRoles.Exists(x => roles.Contains(x.Role) && x.Active);
}