ASP.NET MVC 4 niestandardowy atrybut autoryzacji z kodami uprawnień (bez ról)


121

Muszę kontrolować dostęp do widoków na podstawie poziomów uprawnień użytkowników (nie ma ról, tylko poziomy uprawnień dla poziomów operacji CRUD przypisanych do użytkowników) w mojej aplikacji MVC 4.

Jako przykład; poniżej AuthorizeUser będzie mój atrybut niestandardowy i muszę go używać w następujący sposób:

[AuthorizeUser(AccessLevels="Read Invoice, Update Invoice")]
public ActionResult UpdateInvoice(int invoiceId)
{
   // some code...
   return View();
}


[AuthorizeUser(AccessLevels="Create Invoice")]
public ActionResult CreateNewInvoice()
{
  // some code...
  return View();
}


[AuthorizeUser(AccessLevels="Delete Invoice")]
public ActionResult DeleteInvoice(int invoiceId)
{
  // some code...
  return View();
}

Czy można to zrobić w ten sposób?

Odpowiedzi:


244

Mogę to zrobić za pomocą atrybutu niestandardowego w następujący sposób.

[AuthorizeUser(AccessLevel = "Create")]
public ActionResult CreateNewInvoice()
{
    //...
    return View();
}

Custom Attribute w następujący sposób.

public class AuthorizeUserAttribute : AuthorizeAttribute
{
    // Custom property
    public string AccessLevel { get; set; }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var isAuthorized = base.AuthorizeCore(httpContext);
        if (!isAuthorized)
        {                
            return false;
        }

        string privilegeLevels = string.Join("", GetUserRights(httpContext.User.Identity.Name.ToString())); // Call another method to get rights of the user from DB

        return privilegeLevels.Contains(this.AccessLevel);           
    }
}

Możesz przekierować nieautoryzowanego użytkownika w swoim niestandardowym AuthorisationAttribute, zastępując HandleUnauthorizedRequestmetodę:

protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
    filterContext.Result = new RedirectToRouteResult(
                new RouteValueDictionary(
                    new
                        { 
                            controller = "Error", 
                            action = "Unauthorised" 
                        })
                );
}

Wypróbowałem Twój przykład HandleUnauthorizedRequest, ale kiedy określam RouteValueDictionary, po prostu przekierowuje do mnie trasę, która nie istnieje. Dodaje trasę, na którą chcę przekierować użytkownika, do trasy, do której użytkownik chciał uzyskać dostęp ... si Otrzymuję coś takiego: localhost: 9999 / admin / Home, kiedy chciałem localhost: 9999 / Home
Marin

1
@Marin Spróbuj dodać area = string.Empty w RouteValueDictionary
Alex

30
Głosowałem za głosem, ale potem zobaczyłem „if (warunek) {return true;} else {return false;}” na końcu ....
GabrielBB

1
@Emil Po prostu zwróciłbym wartość logiczną, którą dała mi metoda String.Contains. Ale to nie ma znaczenia, nie głosowałem przeciw, po prostu nie głosowałem za hehe.
GabrielBB

2
.Name.ToString()jest zbędne, ponieważ Namewłaściwość jest już ciągiem znaków
FindOutIslamNow

13

Oto modyfikacja dla pliku prev. odpowiedź. Główna różnica polega na tym, że gdy użytkownik nie jest uwierzytelniony, używa oryginalnej metody „HandleUnauthorizedRequest” do przekierowania na stronę logowania:

   protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {

        if (filterContext.HttpContext.User.Identity.IsAuthenticated) {

            filterContext.Result = new RedirectToRouteResult(
                        new RouteValueDictionary(
                            new
                            {
                                controller = "Account",
                                action = "Unauthorised"
                            })
                        );
        }
        else
        {
             base.HandleUnauthorizedRequest(filterContext);
        }
    }

3

Może jest to przydatne dla każdego w przyszłości, zaimplementowałem niestandardowy atrybut autoryzacji, taki jak ten:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class ClaimAuthorizeAttribute : AuthorizeAttribute, IAuthorizationFilter
{
    private readonly string _claim;

    public ClaimAuthorizeAttribute(string Claim)
    {
        _claim = Claim;
    }

    public void OnAuthorization(AuthorizationFilterContext context)
    {
        var user = context.HttpContext.User;
        if(user.Identity.IsAuthenticated && user.HasClaim(ClaimTypes.Name, _claim))
        {
            return;
        }

        context.Result = new ForbidResult();
    }
}

0

Jeśli używasz WEB API z Claims, możesz użyć tego:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class AutorizeCompanyAttribute:  AuthorizationFilterAttribute
{
    public string Company { get; set; }

    public override void OnAuthorization(HttpActionContext actionContext)
    {
        var claims = ((ClaimsIdentity)Thread.CurrentPrincipal.Identity);
        var claim = claims.Claims.Where(x => x.Type == "Company").FirstOrDefault();

        string privilegeLevels = string.Join("", claim.Value);        

        if (privilegeLevels.Contains(this.Company)==false)
        {
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, "Usuario de Empresa No Autorizado");
        }
    }
}
[HttpGet]
[AutorizeCompany(Company = "MyCompany")]
[Authorize(Roles ="SuperAdmin")]
public IEnumerable MyAction()
{....
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.