Archiv der Kategorie: Attribute

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

MVC Einführung/Tutorial in Custom Editor Templates inklusive der Einbindung von HTML5 Attributen im Model


Wenn ich bisher für meine Viewdaten eine extra CSS Klasse oder ein weiteres HTML5 Attribut benötigt habe, dann sah das z.B. folgendermaßen aus.

 @Html.TextBoxFor(model => model.CurrentDate, 
                new { @class = "input-small " + WebConstants.DatePickerCssClass, 
                           @Value = Model.CurrentDate.ToString(WebConstants.InputDateTimeFormat),
								type="date" })

Da kann man schnell den Überblick verlieren und außerdem gibt es noch ne Menge HTML5 Attribute die man anwenden kann. Es gibt aber noch eine weitere Möglichkeit das “Problem” anzugehen und die heißt “MVC Editor Templates”.

1. Ein paar Grundlagen zu den MVC Editor Templates

Sobald Ihr die Funktion “@HTML.EditorFor(….)” oder “@HTML.DisplayFor(…)” nutzt greift MVC auf Editor Templates zurück, wenn es keine Custom Templates findet, dann nimmt es seine eigenen die von MS vordefiniert wurden. Einen sehr guten Artikel darüber hat Brad Wilson geschrieben. MVC unterscheidet in “EditorTemplates” zum Bearbeiten von Werten und “DisplayTemplates” zum Anzeigen von Werten.

Die Eigenen Templates können entweder unter dem jeweiligen View abgelegt werden (im Ordner “DisplayTemplates” oder “EditorTemplates”) oder unter dem Shared Folder. MVC prüft dann erst den jeweiligen passenden View Folder, wenn Ihr spezielle Templates für einen View erstellt habt und wenn MVC dort keine findet, wird weiter im Shared Folder nach Templates geschaut.

imageimage

Standardmäßig gibt es für Alle Standarddatentypen wie “Datetime”, “Int32/64”, “String” und “Bool” ein Template. In MVC kann man aber bei den Modeldaten noch ein Attribut “DataType” festlegen und für jeden DataType gibt es ebenfalls noch ein Standardtemplate.

Bei der Verwendung des DataType Attributs ist außerdem zu beachten, das der verwendete DataType Vorrang vor dem Datentyp den Properties selbst hat. Im Folgenden Beispiel wird also nicht das Template “DateTime” verwendet, sondern es wird das Template “Time” aufgerufen.

Das DataType Attribut hat noch weitere Auswirkungen auf unsere Templates, denn das DataType Attribut legt z.B. fest wie der Ausgabewert “vorformatiert” wird. Wenn es sich z.B. um ein Datetime Attribut handelt mit dem DataType “Time” dann wird bei der Ausgabe nur noch die Zeit ausgegeben z.B. “13:34”, oder wenn für DataType “Date” steht, dann wir z.B. “23.04.2013” ausgegeben und beim DataType “DateTime” wird z.B. “23.04.2013 13:34” ausgegeben.

/// 
/// Verwendung des DataType Attributes Time, veranlasst MVC
/// nicht das "DateTime" Template zu nutzen
/// sondern, es wird das "Time" Template genommen.
/// 
[DataType(DataType.Time)]
[Display(Name = "Aktuelle Zeit")]
public DateTime CurrentTime { get; set; }

Wenn man also ein Element mit “EditorFor” erstellt, dann prüft MVC welcher Datentyp dargestellt werden soll und sucht ein passendes Template heraus und wenn es keines vom User findet, werden die eigenen von MVC benutzt.

Die Funktion “EditorFor” bietet aber auch die Möglichkeit zu sagen, welches Template verwendet werden soll, wenn man z.B. spezielle Custom Templates angelegt hat.

</pre>
<div class="control-group">@Html.LabelFor(model => model.Datum, new { @class = "control-label" })
<div class="controls">@* Aufruf des Standardtemplates für unser Datum. *@ @Html.EditorFor(model => model.Datum) @Html.ValidationMessageFor(model => model.Datum)</div>
</div>
<div class="control-group">@Html.LabelFor(model => model.Datum, new { @class = "control-label" })
<div class="controls">@* Aufruf des Custom Templates "Custom.Date" für unser Datum. *@ @Html.EditorFor(model => model.Datum, "Custom.Date") @Html.ValidationMessageFor(model => model.Datum)</div>
</div>
<pre>

Oder man kann bereits im Model festlegen welches Custom Template genutzt werden soll mittels des Attributs “UIHint”

[HtmlTag(Autofocus = true)]
[DataType(DataType.Date)]
[Display(Name = "Geburtstag")]
[UIHint("Custom.Date")]
public DateTime Geburtsdatum { get; set; }

Aber wie sieht ein Editor Template eigentlich aus? Dies kann sehr unterschiedlich sein, von sehr einfachen Varianten die nur eine zusätzliche CSS Klasse setzten, bis hin zu Templates die direkt DiplayValue und EditorValue anzeigen und in die passende Tagstruktur einbinden.

@* Text.cshtml *@
@model String

@* Einfaches Template was nur den Wert wieder in einer Textbox darstellt *@
@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = "span4"})

Es ist auch möglich nicht “@Html.TextBox” zu nutzen und das komplette Control selbst zu “erstellen” als “input”, hier kommt es ganz darauf an was man machen will und wie viel Aufwand man aufwenden möchte. Auch das direkte Einbinden von JavaScript Code ist kein Problem.

@* Custom.Int32.cshtml *@
@model Int32

@* Im Template direkt eine bestimmte Formatierung angeben *@</pre>
<div class="control-group"><strong>Custom Int32 Template</strong> @Html.Encode(ViewData.ModelMetadata.DisplayName):
<div class="controls">@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue)</div>
</div>
<pre>

2. Einbinden von HTML5 Attributen mit Hilfe eines Attributes im Model

Ich bin häufig vom “EditorFor” gewechselt zu “TextBoxFor” um eigene HTML Attribute angeben zu können wie den Type oder um die Formatierung des Values bestimmen zu können (wie im Beispiel ganz zu beginn). Hier verliert man aber sehr schnell den Überblick wo man was im View gesetzt hat. Hier kann das Direkte Setzten der passenden HTML5 Attribute oder beliebiger anderer Attribute direkt im Model weiterhelfen.

Die Umsetzung, dazu ist letztendlich sehr einfach, denn man muss in seiner Attributklasse nur das Interface “IMetadataAware” einbinden und die dazu gehörende Methode “OnMetadataCreated(ModelMetadata metadata)” einbinden und schon werden von MVC die passenden Werte auch im Template zur Verfügung gestellt.

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class HtmlTagAttribute : Attribute, IMetadataAware
{
    /// 
    /// String der den Key für die "AdditionalValues" Collection enthält in der unsere Attributliste liegt.
    /// 
    public const string HtmlTagAdditionalValuesKey = "HtmlTagAdditionalValues";

    /// 
    /// Wird beim Erstellen der Metadaten für Unser Model aufgerufen und setzt in der passenden Collection
    /// unsere AttributCollection auf die wir dann in den Templates zugreifen können.
    ///  
    /// 
    public void OnMetadataCreated(ModelMetadata metadata)
    {
        //metadata.TemplateHint = "Strings";
        metadata.AdditionalValues[HtmlTagAdditionalValuesKey] = OptionalAttributes();
    }

    /// 
    /// Maximale Länge des Eingabefeldes
    /// 
    public int MaxLength { get; set; }

    /// 
    ///  The min and max attributes works with the following input 
    ///  EHtmlInputTypes: number, range, date, datetime, datetime-local, month, time and week.
    /// 
    public int Min { get; set; }

    /// 
    /// Gibt an ob ein MinValues angegeben wurde
    /// 
    public bool HasMinValues { get; set; }

    /// 
    ///  The min and max attributes works with the following input
    ///  EHtmlInputTypes: number, range, date, datetime, datetime-local, month, time and week.
    /// 
    public int Max { get; set; }

    /// 
    /// The pattern attribute works with the following input types: text, search, url, tel, email, and password.
    /// e.g.: pattern="[A-Za-z]{3}"
    /// 
    public string Pattern { get; set; }

    /// 
    /// The hint is displayed in the input field when it is empty, and disappears when the field gets focus.
    /// 
    public string Placeholder { get; set; }

    /// 
    /// Gibt an ob es sich nur um ein Readonly Feld handelt.
    /// 
    public bool ReadOnly { get; set; }

    /// 
    /// Gibt an ob das Feld Disabled sein soll
    /// 
    public bool Disabled { get; set; }

    /// 
    /// Specifies the shortcut key to activate/focus the element
    /// 
    public string AccessKey { get; set; }

    public int TabIndex { get; set; }
    public string CssClass { get; set; }

    /// 
    /// Gibt an ob auf das Element der Autofokus beim Pageload gesetzt werden soll
    /// Achtung sollte nur einmal Pro "seite" / "Model" verwendet werden.
    /// 
    public bool Autofocus { get; set; }

    /// 
    /// Der Jeweilige Inputtype, hier muss selbst darauf geachtet
    /// werden das dieser nicht mit dem .NET Inputtype "kollidiert"
    ///  und zusammenpasst. - HtmlInputTypes Klasse enthält alle gängigen Input Types
    /// 
    public string InputType { get; set; }

    /// 
    /// Erstellt aus den jeweils gesetzten Attributen eine Liste aus Attributname und Value.
    /// 
    /// 
    public Dictionary OptionalAttributes()
    {
        var options = new Dictionary();

        if (MaxLength != 0)
        {
            options.Add("maxlength", MaxLength);
        }

        if (ReadOnly)
        {
            options.Add("readonly", "readonly");
        }

        if (Disabled)
        {
            options.Add("disabled", "disabled");
        }

        if (Autofocus)
        {
            options.Add("autofocus", null);
        }

        if (!string.IsNullOrWhiteSpace(AccessKey))
        {
            options.Add("accessKey", AccessKey);
        }

        if (TabIndex != 0)
        {
            options.Add("tabindex", TabIndex);
        }

        if (!string.IsNullOrWhiteSpace(CssClass))
        {
            options.Add("class", CssClass);
        }

        if (!string.IsNullOrWhiteSpace(InputType))
        {
            //Der Name des Enums entspricht dem Type direkt.
            options.Add("type", InputType);
        }

        if (HasMinValues)
        {
            options.Add("min", Min);
        }

        if (Max > 0)
        {
            options.Add("max", Max);
        }

        if (!string.IsNullOrEmpty(Pattern))
        {
            options.Add("pattern", Pattern);
        }

        if (!string.IsNullOrEmpty(Placeholder))
        {
            options.Add("placeholder", Placeholder);
        }

        return options;
    }
}

Da wir die Werte die wir als Attribute in unser HTML Element aufnehmen wollen als KeyValuePair<string,object> Collection benötigen, gibt es in unserer Attributklasse die Funktion “OptionalAttributes()” die aus unseren Gesetzten Werten die passende Collection baut.

/// 
/// Die Input Types die wir zur Verfügung stellen.
/// 
public static class HtmlInputTypes
{
    public const string Text = "text";
    public const string Password = "password";
    public const string Datetime = "datetime";
    public const string Date = "date";
    public const string Month = "month";
    public const string Time = "time";
    public const string Week = "week";
    public const string Number = "number";
    public const string Range = "range";
    public const string Email = "email";
    public const string Url = "url";
    public const string Tel = "tel";
};

Verwendet werden kann das ganze dann z.B. folgendermaßen in unserem Model. Es muss nur auf die Verwendung des Properties “InputType” unseres Attributs aufgepasst werden, oder eine entsprechende Logik in den jeweiligen Controls eingebunden werden.

[HtmlTag(Autofocus = true, InputType = HtmlInputTypes.Time)]
[DataType(DataType.Time)]
[Display(Name = "Geburtszeit")]
public DateTime BirthTime { get; set; }

[HtmlTag(MaxLength = 5, Min=10, Max=50000, CssClass = "input-xxlarge")]
[Display(Name = "Geld in Euro")]
public int Geld { get; set; }

Und umgesetzt wird das ganze dann entsprechend in jedem Template wo die Attribute gesetzt werden sollen. Wir können auch im Template noch bestimmte Werte für das jeweilige Template automatisch setzten lassen oder neue hinzufügen.

@model DateTime
@using Mvc4WebApiKoTb.Helpers.MvcBasic

@{
    var values = new Dictionary();
    if (ViewData.ModelMetadata.AdditionalValues.ContainsKey(HtmlTagAttribute.HtmlTagAdditionalValuesKey))
    {
        values = (Dictionary)ViewData.ModelMetadata.AdditionalValues[HtmlTagAttribute.HtmlTagAdditionalValuesKey];
    }
    
}

@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, values)
@* Custom.Date.cshtml *@
@model DateTime
@using Mvc4WebApiKoTb.Helpers.MvcBasic

@{
    var values = new Dictionary();
    if (ViewData.ModelMetadata.AdditionalValues.ContainsKey(HtmlTagAttribute.HtmlTagAdditionalValuesKey))
    {
        values = (Dictionary)ViewData.ModelMetadata.AdditionalValues[HtmlTagAttribute.HtmlTagAdditionalValuesKey];
    }

    var anzeige = string.Empty;
    if (ViewData.TemplateInfo.FormattedModelValue != null)
    {
        DateTime datum = (DateTime) ViewData.TemplateInfo.FormattedModelValue;
        //Hier wird das übergebene Datum direkt Formatiert ausgegeben
        anzeige = datum.ToString("dd.MM.yyyy");
    }
}

<strong>Custom Date Value</strong> 
@Html.TextBox("", anzeige, values)

Damit haben wir ein eigenes Template für DateTime, welches automatisch die passenden Attribute unserem HTML Element hinzufügt oder sogar das Datum selbst formatiert.

3. Quellen und Code auf Codeplex

http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-4-custom-object-templates.html
http://stackoverflow.com/questions/7313284/how-can-editor-templates-display-templates-recognize-any-attributes-assigned-t
http://www.dotnetcurry.com/ShowArticle.aspx?ID=687

Codeplex:

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

MVC 3 und Remote Validation Attribute


wie bereits in einem anderen Post von mir “versprochen” noch eine Anleitung dazu wie man Remote Validation unter MVC 3 nutzt. Remote Validation bedeutet das vom JavaScript auf der Webseite bei der Eingabe eine Controllermethode aufgerufen wird, welche den Inhalt auf Richtigkeit prüft. Das könnte wie in meinem Falle z.B. sein ob der Nutzer bereits existiert wenn man sich neu auf einer Webseite registrieren möchte.

image

Wir befinden uns im  passenden Model und betrachten hier einfach ein Property, was bereits mehrere Attribute besitzt. Der Erste Parameter im Remote Attribute ist der Methodenname der aufgerufen werden soll und der zweite ist der Controllername in dem sich die Methode befindet, dies sind die beiden wichtigsten Parameter, mit den restlichen Parametern kann wie immer die Fehlermeldung angepasst werden.

Es ist auch noch möglich das die Remote Validation von einem weiteren Feld abhängig ist dies kann mit der Eigenschaft “AdditionalFields” im Remote Attribute mit angegeben werden und unsere Methode wird dann mit zwei Strings statt einem aufgerufen.

Die zugehörige Methode wird dann im passenden Controller definiert und erhält als Übergabeparameter unseren Eingabewert und als Rückgabewert wird Json verwendet, hier ist der zweite Parameter “JsonRequestBehavior.AllowGet” wichtig, ohne diesen Parameter wird unsere Methode nicht aufgerufen.

image

Das war alles was für Remote Validation benötigt wird.

Damit Remote Validation auch funktioniert muss in der web.config auch JavaScript aktiviert sein.

image

Hinweis: Wenn entweder in der web.config oder beim Nutzer im Browser JavaScript ausgeschalten ist, dann funktioniert auch unser Remote Validation Attribute nicht mehr. Bei diesem Attribut gibt es auch keine Serverseitige Validierung die dann automatisch einspringt, d.h. man muss immer noch im Controller selbst eine Serverseitige Validierung mit einbauen!

MVC 3 und Benutzerdefinierte Überprüfung der Eingaben mit dem “ValidationAttribute”


Unter ASP.NET MVC 3 ist es sehr einfach sich ein eigenes Validation Attribut zu erstellen, welches dann im Model verwendet werden kann. Ich wollte zum Beispiel prüfen ob ein User Bereits existiert beim Anlegen eines neuen Users.

image

Mit Hilfe meines eigenen Attributes “CheckUserExistsAttribute”, dazu einfach eine neue Klasse anlegen und diese von “ValidationAttribute” ableiten und die Funktion “IsValid” überschreiben.

image

 

Damit ist man schon fertig, wenn man jetzt z.B. auf einer Webseite schon ein Required Attribut verwendet bei einem anderen Property, dann wundert man sich warum das eigene Benutzerdefinierte Attribut nicht “geprüft” wird, in meinem Falle existierte “jr@gmx.de” bereits, wurde aber nicht angezeigt über mein Attribut.

image

Das hat den Hintergrund, das für die bereits implementierten Attribute automatisch die die Validierung per JavaScript eingestellt ist (bei MVC 3) in der web.config und mein Benutzerdefiniertes Attribut keine solche Implementierung beinhaltet und erst auf dem Server ausgewertet wird bei einem kompletten Postback.

image

Die Einbindung von Remote Validation bzw. der zusätzlichen Validierung unter der Hilfe von Javascript kann man auch hier finden:

http://highoncoding.com/Articles/767_Remote_Validation_in_ASP_NET_MVC_3.aspx

http://haacked.com/archive/2009/11/19/aspnetmvc2-custom-validation.aspx

http://bradwilson.typepad.com/blog/2010/10/mvc3-unobtrusive-validation.html

bzw. in dem folgenden Blogpost

ASP.NET MVC 3 Nutzer Authentication mit Attributen


Bei einer Webseite mit einer Nutzerverwaltung, ist mit das wichtigste das man nicht einfach die Daten anderer User betrachten darf oder sich Zugriff zum Adminbereich verschafft, nur weil man etwas mit der URL “umherspielt”.

Dafür gibt es zum einen das Attribut “Authorize” was direkt mitgeliefert wird und prinzipiell prüft, ob überhaupt ein User eingeloggt ist und wenn nicht wird auf die Loginseite verwiesen.

Dann besteht aber noch die Möglichkeit ein Custom Attribut zu erstellen, in dem man alle wichtigen Daten für den aktuellen Controller und den Aufgerufenen View überprüfen kann.

Zum einen haben mir hier die folgenden Links sehr weitergeholfen:

http://msdn.microsoft.com/en-us/library/gg416513%28VS.98%29.aspx

http://msdn.microsoft.com/en-us/library/dd381609%28v=VS.98%29.aspx

http://geekswithblogs.net/brians/archive/2010/07/08/implementing-a-custom-asp.net-mvc-authorization-filter.aspx

Dann noch ein kleines Beispiel wie so eine Umsetzung aussehen könnte. Als erstes benötigen wird eine neue Klasse die vom AuthorizeAttribute ableitet und wir können hier eigene Werte im Konstruktor übergeben, die wir evtl. später benötigen. Dann muss man noch OnAuthorization überschreiben und kann hier seine gewünschte Funktionalität einbinden.

image

Mit der Hilfe von filterContext.Result und mit HttpUnauthorizedResult() wird auf die Loginseite verwiesen, kann auch in einem der oberen Links nachgelesen werden.

image

oder mit new RedirectResult(“BeliebigeURL”) kann auch direkt auf eine URL verwiesen werden.image

Das Attribut kann dann in jedem beliebigen Controller eingesetzt werden und wird vor allen anderen Attributen ausgeführt.

image