Visual Studio: ASP.NET Core project (empty oder WebAPI)
empty:
Startup.cs:
ConfigureServices: services.AddMvc()
Configure: app.UseMvc()
“Controllers” Ordner erzeugen
New item: API Controller Class, Base class auf ControllerBase
ändern (weniger Intellisync)
ROUTING
Class Routing: [Route("bli/bla")]
als Controllerklassenattribut wird allen Actions vorgestellt. [Controller]
in der Route wird durch Klassenname (muss mit “Controller” enden) ohne “Controller” ersetzt.
Atrribute Routing: [HttpGet/Post/Put/Delete("route")]
vor Methode.
{bli} = Parameter “bli” in Methode wird aus Route geholt
{bla:int} = Parameter “bla” in Methode wird als int aus Route geholt (nur dann wenns auch ein int ist)
{bla:string:minlength(7)} = Parameter “blu” in Methode wird als string aus Route geholt, String muss mind. 7 Zeichen lang sein
{foo?} = optionaler Parameter
{bar=4711} = Defaultwert (sonst 0 bei int und “” bei string)
{wtf:regex(^abc…xyz$)} = Route greift nur wenn regular Expression matched
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing
MODEL BINDING
Parameter in Action vorangestellt [FromRoute]
(default), [FromBody]
, [FromQuery]
, [FromForm]
, [FromHeader]
zwingt ASP.NET Core gleichnamigen Parameter aus dieser Quelle zu beziehen.
Immer ModelState.IsValid
prüfen um sicherzustellen dass alle Bindings und Contraints erfolgreich ausgewertet wurden.
DataAnnoations bei Properties von komplexen Typen (z.B. [MinLength(7)] public string Bli { get; set; }
in einer Klasse) werden für ModelState ausgewertet (public und get/set sind notwendig!).
https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation
ACTION RESULTS
Actions liefern IActionResult
anstatt Basistypen, ermöglicht clientseitig besseres Ergebnismanagement (v.a. im Fehlerfall – Exception würde sonst immer 500 liefern anstatt sinnvoller Informationen).
return NotFound() = 404
return BadRequest() oder BadRequest(ModelState) = 400, alternativ mit Zusatzinformation (Validation-Fehler z.B.)
return Ok() oder Ok(“whatever”) oder Ok(new { bli=”bla”, blu=”blu”}) = 200 mit Wert im Body (Object wird zu JSON)
https://docs.microsoft.com/en-us/aspnet/core/web-api/action-return-types
SECURITY – TRANSPORT
Für MVC kann man verschiedenste Filter einfügen, zwei der wichtigsten (Antiforgery Token (eigentlich nicht Transport aber he…) und Require HTTPS gehen so) – in ConfigureServices()
:
services.AddMvc(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
options.Filters.Add(new RequireHttpsAttribute());
});
In der Configure
Methode der Startup-Klasse (Startup.cs) gibts vielfache Möglichkeiten die Transportsicherheit zu erhöhen:
app.UseHttpsRedirection() = offensichtlich
app.UseHsts() = offensichtlich
Das ist aber eher dürftig, viele zusätzliche Securityheader bekommt man über diverse Nugets:
Nwebsec.AspnetCore.Middleware (https://docs.nwebsec.com/en/latest/nwebsec/NWebsec.AspNetCore.Middleware.html)
app.UseHsts(options => options.MaxAge(days: 365).IncludeSubdomains()) = offensichtlich aber mit Parameter
app.UseXXssProtections(options => options.EnableWithBlockMode()) = Cross Side Scripting Header, mit Parameter
app.UseXcontentTypeOptions() = X-Content-Type-Options Header
app.UseXfo(options => options.Deny()) = X-Frame-Options Header
app.UseReferrerPolicy(opts => opts.NoReferrer()) = Referrer Policy
app.UseCsp(…crazy zeug…) = Content Security Policy, siehe Doku, vielfältigste Möglichkeiten sich selbst die Knie wegzuschießen
NetEscapades.AspnetCore.SecurityHeaders (https://andrewlock.net/adding-default-security-headers-in-asp-net-core/)
app.UseSecurityHeaders(new HeaderPolicyCollection().AddDefaultSecurityHeaders()) = für die die etwas schreibfauler sind 😀
SECURITY – AUTHENTICATION UND AUTHORIZATION
Am Beispiel ADFS – in ConfigureServices()
Authentication enablen:
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
}).AddWsFederation(options =>
{
options.MetadataAddress = "https://myadfs.mydomain.com/FederationMetadata/2007-06/FederationMetadata.xml";
options.Wtrealm = "https://myrelyingpartytrust/";
}).AddCookie(options =>
{
options.AccessDeniedPath = new PathString("/api/mycontroller/myaccessdeniedaction");
});
Wobei der Relying Party Trust im ADFS natürlich entsprechend eingetragen werden muss (WS-Federation) und die entsprechenden Claims issued werden müssen. Wtrealm ist der Relying Party Trust Identifier.
Authorization kann schon am ADFS passieren (Issuance Authorization Rules) oder auf WebAPI Seite mit dem [Authorize]
oder [AllowAnonymous]
Attribut gesetzt auf Klasse (Controller) oder Methode (Action). Gemeinsame Regeln kann man in Policies in ConfigureService()
mit Name erzeugen
services.AddAuthorization(options =>
{
options.AddPolicy("MyPolicy", policy => policy.RequireClaim("http://schemas.xmlsoap.org/claims/Group", "MyAdminGroup"));
});
und dann im Klassen/Methodenattribute verwenden ([Authorize(Policy="MyPolicy")]
)