ASP.NET MVC 4 Custom Authorize Attribute


Wie bereits in einem älteren Artikel von mir beschrieben gibt es hier noch einmal eine kleine Auffrischung der Materie inklusive eines Beispiels auf Codeplex.

Wozu ist das Authorize Attribut eigentlich da? Das Authorize Attribut kümmert sich darum, das nur autorisierte (eingeloggte) User den “Internen” Bereich einer Webseite anschauen können, dabei kann es sich z.B. um den Administratorbereich handeln.

Microsoft stellt von Haus aus bereits ein “Authorize” Attribut zur Verfügung was aber standardmäßig nur prüft ob der User auch eingeloggt ist. Wichtig ist hier das beim Login “FormsAuthentication.SetAuthCookie” verwendet wird, wenn der Login erfolgreich war. Denn damit weiß dann auch das Standard “Authorize” Attribut ob der User auf die jeweilige Aktion/Controller zugreifen darf.

Wenn man das “Authorize” Attribut direkt auf den ganzen Controller anwendet, kann man einfach mit einem “AllowAnonymous” Attribut über der jeweiligen Action diese Action wieder “freigeben” und auch ein User der nicht eingeloggt ist kann dann auf diese Action zugreifen.

Im Folgenden Beispiel sieht man ein Beispiel mit dem Standard “Authorize” Attribut, welches auf den gesamten Controller angewendet wird. Damit sich dann ein User auch noch einloggen kann, muss die Login Funktion mit einem “AllowAnonymous” Attribut bestückt werden. Außerdem sieht man bei der Loginmethode die Verwendung von “FormsAuthentication.SetAuthCookie”.

[Authorize]
public class AccountController : Controller
{
    [AllowAnonymous]
    public ActionResult Login(string returnUrl)
    {
        ViewBag.ReturnUrl = returnUrl;
        return View();
    }

    [AllowAnonymous]
    [HttpPost]
    public ActionResult Login(LoginModel model, string returnUrl)
    {
        if (ModelState.IsValid)
        {
            //ACHTUNG HIER müsste vorher nat. ein DB Abgleich mit den Usern aus der DB stattfinden
            //Aktuell setzten wir hier jeden User als Authorisiert, wenn er einen beliebigen Usernamen und PW angibt.
            FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
            
            if (Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }

        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

    public ActionResult LogOff()
    {
        FormsAuthentication.SignOut();

        return RedirectToAction("Index", "Home");
    }

Dann gibt es noch die Möglichkeit ein eigenes Authorize Attribut zu erstellen in dem man von “AuthorizeAttribute” Attribut ableitet (System.Web.Mvc.AuthorizeAttribute).

Ein eigenes Authorize Attribut ist z.B. notwendig wenn man noch zusätzliche Rechte bei einigen Actions oder ganzen Controllern für einzelne User überprüfen muss. Eine Seite die einen eigenen Admin Bereich hat, benötigt eine Extra Prüfung der Rechte für den Admin Bereich, denn hier hat nicht jeder Autorisierte Nutzer auch Zugriff, sondern nur spezielle Nutzer denen das Recht über die eigene Rechteverwaltung zugewiesen wurde. Dafür gibt es dann das eigene Authorize Attribut.

Bei der hier gezeigten Variante setzt Ihr nur das Authorize Attribut auf den jeweiligen Controller oder Action und eine Prüfung welcher User bzw. welche Rolle auf diesen Controller Zugriff hat, wird alles im Authorize Attribut selbst erledigt. Denn dort können wir auch sehen welche Action, Controller, Id oder Custom Route Values gerade aufgerufen wurde und entsprechend eure Rechte prüfen.

Ich finde der Vorteil an dieser Umsetzung liegt vor allem darin das ich eine zentrale Stelle habe an der ich meine Rechte für Alle Controller und Actions verwalten und setzten kann. Ich bin mit dieser Variante bisher sehr gut zurecht gekommen.

using AuthorizeAttribute = System.Web.Mvc.AuthorizeAttribute;

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    #region Member
    private AuthorizationContext CurrentContext { get; set; }
    #endregion

    #region Konstruktor
    /// <summary>
    /// Es muss nichts übergeben werden, da controller und action direkt hier ausgelesen werden können
    /// </summary>
    public CustomAuthorizeAttribute()
    {
    }
    #endregion

    #region Public Functions
    /// <summary>
    /// Funktion die ausgeführt wird, wenn das Attribut "genutzt" wird, das Authorisation Attribut wird immer als erstes Attribut ausgeführt.
    /// </summary>
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);
        //Der Filtercontext wird benötigt um auf die RequestDaten zuzugreifen, 
        //z.b. auf die Id, Action oder den Controller auf den zugegriffen werden soll.
        CurrentContext = filterContext;
      
        //Wenn kein User eingeloggt ist, dann hat er auch keinen Zugriff.
        if (!HttpContext.Current.User.Identity.IsAuthenticated)
        {
            //Wenn der User nicht eingeloggt ist, auf die Loginseite verweisen
            filterContext.Result = new HttpUnauthorizedResult();
        }
        else
        {
            //Prüfen der passenden Rechte für die einzelnen Actions/Methoden 
            if (!CheckRights())
            {
                //Auf die Startseite verweisen, wenn der User keinen Zugriff auf den Kontent hat, den er angefordert hat.
                filterContext.Result = new HttpUnauthorizedResult();
                //Oder auf eine beliebige Andere Webseite verweisen, wenn man nicht unbefingt die Startseite anzeigen möchte.
                //filterContext.Result = new RedirectResult("~/Home/Index");
            }
        }

        //Wenn alles i.o. ist "nichts" unternehmen und einfach beim Aufbau der Seite weitermachen.
    }
    #endregion

    #region Private Functions
    protected void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        var challengeMessage = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
        throw new HttpResponseException(challengeMessage);
    }

    /// <summary>
    /// Prüfen um welchen Controller es sich handelt und die passende Sicherheitsprüfung vornehmen
    /// </summary>
    /// <returns>TRUE->Darf zugreifen | FALSE->Darf nicht zugreifen</returns>
    private bool CheckRights()
    {
        //Wir können hier recht einfach ermitteln um welchen Controller oder View es sich handelt den wir gerade 
        //überprüfen wollen - wenn wir erst einmal von der Standardroute ausgehen.
        string controllerName = CurrentContext.RouteData.GetRequiredString("controller");
        string actionName = CurrentContext.RouteData.GetRequiredString("action");
        string id = CurrentContext.RouteData.Values.ContainsKey("id") ? CurrentContext.RouteData.Values["id"].ToString() : null;

        //Den aktuell eingeloggten User ermitteln für den die Rechte geprüft werden sollen 
        //Der wert der im Username steht legen wir beim Login fest
        //bei "FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe)" 
        //wird hier der Username oder auch die UserId angezeigt.
        string userName = HttpContext.Current.User.Identity.Name;
        

        //Prüfen welcher Controller das Authorize Attribut aufgerufen hat und dann schauen welche Action aufgerufen wurde.
        switch (controllerName)
        {
            case "Home":
                //Rechteprüfung für den jewiligen Controller und evtl. auch auf die 
                //jeweilige Action bezogen durchführen
                return CheckHomeRights();
                break;

            case "Person":
                break;

        }

        return false;
    }

    /// <summary>
    /// Prüft alle Rechte für den HomeController und den enthaltenen Actions
    /// </summary>
    /// <returns></returns>
    private  bool CheckHomeRights()
    {
        return false;
    }
    #endregion
}

Aufruf des Custom Authorize Attributes z.B. für einen kompletten Controller

 [CustomAuthorize]
 public class HomeController : Controller
 {
     public ActionResult Index()
     {
         ViewBag.Message = "Modify this ...";

         return View();
     }
...

}

Wenn man jedoch einen WebAPI Controller überprüfen möchte ist dafür wieder ein anderes Custom Authorize Attribut zuständig, das findet Ihr dann in meinem nächsten Blogeintrag.

Codeplex:

Dann unter “Source Code” –> “Browse” –> “Testprojekte” –> “Mvc4WebApiKoTb” hier findet Ihr dann die Wichtigsten Dateien im Webprojekt unter “Views/Home”, “Helpers/Authentication” und “Views/Account”. Das Projekt sollte auch so lauffähig sein.

Advertisements

2 Gedanken zu „ASP.NET MVC 4 Custom Authorize Attribute

  1. Pingback: MVC 4 Web API Custom Authorize Attribut | SquadWuschel's Blog

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s