Benutzerdefiniertes Autorisierungsattribut für ASP.NET MVC 4 mit Berechtigungscodes (ohne Rollen)

121

Ich muss den Zugriff auf Ansichten basierend auf Benutzerberechtigungsstufen (es gibt keine Rollen, nur Berechtigungsstufen für CRUD-Betriebsebenen, die Benutzern zugewiesen sind) in meiner MVC 4-Anwendung steuern.

Als Beispiel; Unter dem AuthorizeUser befindet sich mein benutzerdefiniertes Attribut, das ich folgendermaßen verwenden muss:

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

Ist es möglich, dies so zu tun?

Chatura
quelle

Antworten:

243

Ich könnte dies mit einem benutzerdefinierten Attribut wie folgt tun.

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

Benutzerdefinierte Attributklasse wie folgt.

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

Sie können einen nicht autorisierten Benutzer in Ihrem Benutzer umleiten, AuthorisationAttributeindem Sie die folgende HandleUnauthorizedRequestMethode überschreiben :

protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
    filterContext.Result = new RedirectToRouteResult(
                new RouteValueDictionary(
                    new
                        { 
                            controller = "Error", 
                            action = "Unauthorised" 
                        })
                );
}
Chatura
quelle
Ich habe Ihr Beispiel für HandleUnauthorizedRequest ausprobiert, aber wenn ich das RouteValueDictionary spezifiziere, wird nur eine Route an mich weitergeleitet, die nicht vorhanden ist. Es hängt die Route an, auf die ich den Benutzer umleiten möchte, auf die Route, auf die der Benutzer zugreifen möchte ... si Ich erhalte Folgendes: localhost: 9999 / admin / Home, wenn ich localhost wollte: 9999 / Home
Marin
1
@Marin Versuchen Sie, area = string.Empty im RouteValueDictionary hinzuzufügen
Alex
30
Ich habe gestimmt, aber dann habe ich am Ende "if (Bedingung) {return true;} else {return false;}" gesehen ....
GabrielBB
1
@Emil Ich würde einfach den Booleschen Wert zurückgeben, den mir die String.Contains-Methode gegeben hat. Aber das ist irrelevant, ich habe nicht abgelehnt, ich habe nur nicht gestimmt, hehe.
GabrielBB
2
.Name.ToString()ist redundant, da die NameEigenschaft bereits Zeichenfolge ist
FindOutIslamNow
13

Hier ist eine Modifikation für die prev. Antworten. Der Hauptunterschied besteht darin, dass der Benutzer, wenn er nicht authentifiziert ist, die ursprüngliche Methode "HandleUnauthorizedRequest" verwendet, um zur Anmeldeseite umzuleiten:

   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);
        }
    }
Leonid Minkov
quelle
3

Vielleicht ist dies für jeden in der Zukunft nützlich. Ich habe ein benutzerdefiniertes Berechtigungsattribut wie das folgende implementiert:

[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();
    }
}
RaphaelH
quelle
0

Wenn Sie die WEB-API mit Ansprüchen verwenden, können Sie Folgendes verwenden:

[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()
{....
}
Maurico Bello
quelle