﻿
{"id":27304,"date":"2024-11-04T20:11:26","date_gmt":"2024-11-04T20:11:26","guid":{"rendered":"https:\/\/www.gencayyildiz.com\/blog\/?p=27304"},"modified":"2024-11-04T20:11:26","modified_gmt":"2024-11-04T20:11:26","slug":"asp-net-core-ozellestirilmis-authentication-ve-authorization-yapilanmasi","status":"publish","type":"post","link":"https:\/\/www.gencayyildiz.com\/blog\/asp-net-core-ozellestirilmis-authentication-ve-authorization-yapilanmasi\/","title":{"rendered":"Asp.NET Core &#8211; \u00d6zelle\u015ftirilmi\u015f Authentication ve Authorization Yap\u0131lanmas\u0131"},"content":{"rendered":"<div id=\"fb-root\"><\/div>\n<p>Merhaba,<\/p>\n<p>Her web uygulamas\u0131nda g\u00fcvenlik a\u00e7\u0131s\u0131ndan kullan\u0131c\u0131 ve yetki y\u00f6netimi olduk\u00e7a kritik arz eden konulard\u0131r. Dolay\u0131s\u0131yla bu temel davran\u0131\u015flar, Asp.NET Core uygulamalar\u0131 i\u00e7in de olmazsa olmazd\u0131r diyebiliriz. Bundan dolay\u0131 Asp.NET Core mimarisinde, kimlik do\u011frulama (authentication) ve yetkilendirme (authorization) s\u00fcre\u00e7lerini y\u00f6netebilmek i\u00e7in olduk\u00e7a g\u00fc\u00e7l\u00fc ve esnek bir altyap\u0131 sunulmakta ve bu temel ta\u015flar sayesinde role-based authorization&#8217;dan tutun claims veya policy authorization&#8217;a ve hatta Google, Facebook vs. gibi external authorization yap\u0131lanmalar\u0131na kadar bir\u00e7ok yetkilendirme yakla\u015f\u0131m\u0131 rahatl\u0131kla sergilenebilmektedir. Tabi bu bahsi ge\u00e7en haz\u0131r yap\u0131lanmalar genellikle kabul g\u00f6rm\u00fc\u015f standartlar \u00fczerinden davran\u0131\u015flar\u0131n\u0131 \u015fekillendirmekte olsa da esas\u0131nda bir\u00e7ok durum ve senaryoya kar\u015f\u0131n en k\u0131lcal manevralara kadar yeterlilik g\u00f6stermektedirler.<\/p>\n<p>Bizler bu i\u00e7eri\u011fimizde var olan haz\u0131r mekanizmalardan ziyade, bu mekanizmalar\u0131n standart&#8217;lar\u0131n\u0131n d\u0131\u015f\u0131 durumlarda(senaryolarda) yani haz\u0131r yap\u0131lar\u0131n eri\u015femedi\u011fi senaryotik k\u0131vr\u0131mlarda nas\u0131l \u00e7\u00f6z\u00fcmler getirebilece\u011fimizi ve bu tarz s\u00fcre\u00e7lerde \u00f6zel davran\u0131\u015flar\u0131 geli\u015ftirebilmek i\u00e7in Asp.NET Core mimarisinde ne  gibi nimetlerin bizlere sunuldu\u011funu inceliyor olaca\u011f\u0131z.<\/p>\n<p>Evet, bazen kimi senaryolarda Asp.NET Core&#8217;daki authentication ve authorization i\u00e7in varsay\u0131lan davran\u0131\u015flar standart d\u0131\u015f\u0131 durumlar\u0131n s\u00f6z konusu olmas\u0131ndan dolay\u0131 \u00f6zelle\u015ftirilmi\u015f gereksinimler gerektirebilmektedir. \u00d6rnek vermemiz gerekirse e\u011fer, Asp.NET Core mimarisinde <em>JwtBearer<\/em> yap\u0131lanmas\u0131 JWT&#8217;leri belirli parametreler e\u015fli\u011finde do\u011frulamak \u00fczere tasarlanm\u0131\u015f gayet basit ama efektif bir yap\u0131lanmad\u0131r. Ancak baz\u0131 durumlarda JWT yap\u0131s\u0131 ya da bu JWT&#8217;yi do\u011frulama mant\u0131\u011f\u0131 mevcut ve genel kabul g\u00f6rm\u00fc\u015f standartlar\u0131n d\u0131\u015f\u0131nda olabilmektedir.<\/p>\n<p><em>Ne gibi standart d\u0131\u015f\u0131 durumlar olabilir la hoca?<\/em> diye sorarsan\u0131z e\u011fer a\u015fa\u011f\u0131daki olas\u0131 durumlar\u0131 d\u00fc\u015f\u00fcnebiliriz;<\/p>\n<ul>\n<li>Kullan\u0131lan token, JWT de\u011fil farkl\u0131 bir formatta de\u011fer olabilir.<\/li>\n<li>Token&#8217;\u0131n \u00f6zelle\u015ftirilmi\u015f bir \u015fifreleme algoritmas\u0131yla do\u011frulanmas\u0131 gerekiyor olabilir.<\/li>\n<li>Token&#8217;da ki payload&#8217;lar\u0131n \u00f6zel bir i\u015fleme tabi tutulmas\u0131 gerekiyor olabilir.<\/li>\n<li>vs.<\/li>\n<\/ul>\n<p>\u0130\u015fte bunlar ve bunlara benzer normal \u015fartlar\u0131n d\u0131\u015f\u0131nda \u00f6zelle\u015ftirilmi\u015f davran\u0131\u015flar gerektiren durumlarda bizlerin eldeki token&#8217;\u0131, sistemin sa\u011flad\u0131\u011f\u0131 haz\u0131r yap\u0131larla de\u011fil kendimizce bu davran\u0131\u015flar\u0131 kar\u015f\u0131layacak \u00f6zelle\u015ftirilmi\u015f \u00e7al\u0131\u015fmalarla kullanmam\u0131z ve i\u015fleme tabi tutmam\u0131z gerekecektir. Bu durumlar\u0131n ay\u0131rd\u0131n\u0131 daha net bir \u015fekilde ortaya koyabilmek i\u00e7in \u015f\u00f6yle bir \u00f6rne\u011fi de\u011ferlendirmekte fayda g\u00f6rmekteyim; kimi durumlarda token i\u00e7erisinde yer alan claim&#8217;ler varsay\u0131lan do\u011frulama mant\u0131\u011f\u0131n\u0131n d\u0131\u015f\u0131nda i\u015flenebilmektedirler. Buna en g\u00fczel \u00f6rne\u011fi, keycloak ile do\u011frulama yap\u0131ld\u0131\u011f\u0131 s\u00fcre\u00e7lerde elde edilen token&#8217;daki rollerin manuel de\u011ferlendirilmesi s\u00fcrecinden verebiliriz. Bu durumu tecr\u00fcbe edenler<span style=\"font-size:12px;\">(ki genellikle keycloak kullan\u0131l\u0131rken <code>Keycloak.AuthServices.Authorization<\/code> k\u00fct\u00fcphanesinin <code>AddKeycloakWebApiAuthentication<\/code> servsiyle bu yap\u0131land\u0131rma h\u0131zl\u0131ca uygulanmaktad\u0131r. Ben bu yap\u0131land\u0131rmay\u0131 manuel tecr\u00fcbe edenlerden bahsediyorum)<\/span> bilirler ki, keycloak&#8217;tan gelen token i\u00e7erisindeki rollerin(yani claim&#8217;lerin) do\u011frulanabilmesi normal \u015fartlara nazaran \u00f6zelle\u015ftirilmi\u015f bir de\u011ferlendirme\/ay\u0131rt etme\/i\u015flem gerektirmektedir.<\/p>\n<p>Ya da normal \u015fartlar\u0131n d\u0131\u015f\u0131nda \u00f6zelle\u015ftirilmi\u015f bir authentication ve authorization davran\u0131\u015f\u0131n\u0131 \u015fekillendirmemizi gerektirecek bir ba\u015fka durum ise farkl\u0131 sistemlerden gelen bilgilere g\u00f6re yetkilendirmenin \u015fekillendirilmesi gereken hibrit durumlard\u0131r diyebiliriz. Bu tarz hibrit gereksinimlerde token do\u011frulamas\u0131 farkl\u0131, do\u011frulama neticesinde oturumun hala aktif olup olmad\u0131\u011f\u0131 ise farkl\u0131 veri kaynaklar\u0131ndan kontrol edilebilmektedir. \u0130\u015fte bu tarz davran\u0131\u015fsal yap\u0131lanmalara \u00e7ok nadir ihtiya\u00e7 hissedilse de, s\u00f6z konusu olduklar\u0131 takdirde \u00f6zelle\u015ftirilmi\u015f manuel yap\u0131lar in\u015fa etmemiz ka\u00e7\u0131n\u0131lmaz olmaktad\u0131r.<\/p>\n<p>T\u00fcm bunlar\u0131n d\u0131\u015f\u0131nda, benimsedi\u011finiz g\u00fcvenlik ilkeleriniz JWT do\u011frulama yap\u0131lar\u0131n\u0131 a\u015fabilir, ek \u015fifreleme katmanlar\u0131 kullanmak isteyebilir ya da token \u00fczerinden ekstradan \u00f6zelle\u015ftirilmi\u015f i\u015flemler yapmak isteyebilirsiniz. Veya token i\u00e7erisindeki baz\u0131 bilgilerin i\u015flenmeye gerek olmad\u0131\u011f\u0131n\u0131 d\u00fc\u015f\u00fcnerek de performans iyile\u015ftirmesi gayesiyle do\u011frulama s\u00fcrecini daha hafif hale getirmek istiyor da olabilirsiniz.<\/p>\n<p>\u0130\u015fte burada bahsedilen senaryolarda ya da benzeri durumlarda kimlik do\u011frulama ve yetkilendirme s\u00fcre\u00e7lerinin manuel bir \u015fekilde optimize edilmesi gerekecektir. \u015eimdi gelin Asp.NET Core&#8217;da manuel bir \u015fekilde authentication ve authorization i\u015flemlerinin nas\u0131l yap\u0131ld\u0131\u011f\u0131n\u0131 par\u00e7a par\u00e7a ele almaya ba\u015flayal\u0131m.<\/p>\n<h4>Asp.NET Core&#8217;da Manuel Bir \u015eekilde JWT Do\u011frulama<\/h4>\n<p>Her \u015feyden \u00f6nce Asp.NET Core&#8217;da JWT do\u011frulama i\u015flemini manuel olarak nas\u0131l ger\u00e7ekle\u015ftirebilece\u011fimizi inceleyerek ba\u015flayal\u0131m. Tabi manuel davran\u0131\u015f\u0131 net vurgulayabilmek i\u00e7in \u00f6ncelikle bu g\u00fcne kadar geleneksel olarak nas\u0131l bir do\u011frulama s\u00fcreci ge\u00e7irdi\u011fimizi mukayese ama\u00e7l\u0131 incelemekte fayda g\u00f6rmekteyim.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n.\r\n.\r\n.\r\nbuilder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)\r\n    .AddJwtBearer(options =&gt;\r\n    {\r\n        options.TokenValidationParameters = new()\r\n        {\r\n            ValidateAudience = true,\r\n            ValidateIssuer = true,\r\n            ValidateLifetime = true,\r\n            ValidateIssuerSigningKey = true,\r\n            ValidIssuer = builder.Configuration&#x5B;&quot;JWT:Issuer&quot;],\r\n            ValidAudience = builder.Configuration&#x5B;&quot;JWT:Audience&quot;],\r\n            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration&#x5B;&quot;JWT:SecurityKey&quot;])),\r\n            ClockSkew = TimeSpan.Zero\r\n        };\r\n    });\r\n<\/pre>\n<\/div>\n<p>Yukar\u0131daki kod blo\u011funda, Asp.NET Core mimarisinde bir JWT&#8217;yi do\u011frulamak i\u00e7in haz\u0131r sunulan <code>AddAuthentication<\/code> servisini g\u00f6rmekteyiz. Bu servis, request&#8217;in header&#8217;\u0131nda <em>Authorization<\/em> key&#8217;ine kar\u015f\u0131l\u0131k gelen JWT&#8217;yi standart ko\u015fullara uygun \u015fekilde do\u011frulamaya \u00e7al\u0131\u015fmakta ve do\u011frulama neticesinde uygulaman\u0131n t\u00fcm gereksinimlerine uygun bir <em>ClaimsPrincipal<\/em> nesnesi olu\u015fturarak yetkilendirmeyi ger\u00e7ekle\u015ftirmektedir.<\/p>\n<p>Bu i\u015fleme alternatif olarak a\u015fa\u011f\u0131daki gibi kimlik do\u011frulama s\u00fcrecini manuel bir \u015fekilde ger\u00e7ekle\u015ftirebilir ve sisteme dahil edip, kullanabiliriz;<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nusing Microsoft.AspNetCore.Authentication;\r\nusing Microsoft.Extensions.Options;\r\nusing Microsoft.IdentityModel.Tokens;\r\nusing Microsoft.Net.Http.Headers;\r\nusing System.IdentityModel.Tokens.Jwt;\r\nusing System.Security.Claims;\r\nusing System.Text;\r\nusing System.Text.Encodings.Web;\r\n\r\nnamespace AspNetCoreCustomAuth.AuthenticationHandlers\r\n{\r\n    public class ManualAuthenticationHandler : AuthenticationHandler&lt;AuthenticationSchemeOptions&gt;\r\n    {\r\n        readonly IConfiguration _configuration;\r\n        readonly IHttpContextAccessor _httpContextAccessor;\r\n\r\n        public ManualAuthenticationHandler(\r\n            IOptionsMonitor&lt;AuthenticationSchemeOptions&gt; options,\r\n            ILoggerFactory logger,\r\n            UrlEncoder encoder,\r\n            IConfiguration configuration,\r\n            IHttpContextAccessor httpContextAccessor)\r\n            : base(options, logger, encoder)\r\n        {\r\n            _configuration = configuration;\r\n            _httpContextAccessor = httpContextAccessor;\r\n        }\r\n\r\n        protected override Task&lt;AuthenticateResult&gt; HandleAuthenticateAsync()\r\n        {\r\n            string authenticationScheme = &quot;Manual&quot;;\r\n\r\n            JwtSecurityTokenHandler tokenHandler = new();\r\n            var key = Encoding.ASCII.GetBytes(_configuration&#x5B;&quot;JWT:SecurityKey&quot;]);\r\n\r\n            string token = _httpContextAccessor.HttpContext.Request.Headers&#x5B;HeaderNames.Authorization];\r\n            token = token?.Replace(&quot;Bearer &quot;, &quot;&quot;);\r\n\r\n            ClaimsPrincipal? claimsPrincipal = null;\r\n            try\r\n            {\r\n                claimsPrincipal = tokenHandler.ValidateToken(token, new TokenValidationParameters\r\n                {\r\n                    ValidateAudience = true,\r\n                    ValidateIssuer = true,\r\n                    ValidateLifetime = true,\r\n                    ValidateIssuerSigningKey = true,\r\n                    ValidIssuer = _configuration&#x5B;&quot;JWT:Issuer&quot;],\r\n                    ValidAudience = _configuration&#x5B;&quot;JWT:Audience&quot;],\r\n                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration&#x5B;&quot;JWT:SecurityKey&quot;])),\r\n                    ClockSkew = TimeSpan.Zero\r\n                }, out SecurityToken validatedToken);\r\n\r\n                var ticket = new AuthenticationTicket(claimsPrincipal, authenticationScheme);\r\n                return Task.FromResult(AuthenticateResult.Success(ticket));\r\n            }\r\n            catch\r\n            {\r\n\r\n            }\r\n\r\n            return Task.FromResult(AuthenticateResult.Fail(string.Empty));\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<\/div>\n<p>G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere <code>ManualAuthenticationHandler<\/code> s\u0131n\u0131f\u0131 ile kendimize \u00f6zel bir authentication yap\u0131s\u0131 olu\u015fturmu\u015f bulunuyoruz. Burada token&#8217;\u0131 manuel do\u011frulad\u0131ktan sonra <strong><em>54.<\/em><\/strong> sat\u0131rda, <code>AuthenticationTicket<\/code> nesnesi ile kimli\u011fi do\u011frulanm\u0131\u015f ilgili kullan\u0131c\u0131n\u0131n oturum bilgilerini temsil ediyor ve <strong><em>55.<\/em><\/strong> sat\u0131rda da bu nesne ile kimlik do\u011frulama i\u015fleminin ba\u015far\u0131l\u0131 oldu\u011funu ifade eden <code>AuthenticateResult.Success(ticket)<\/code> sonucu bildiriyoruz. E\u011fer ki, kimlik do\u011frulama s\u00fcrecinde bir ba\u015far\u0131s\u0131zl\u0131k mevzu bahisse o taktirde de <code>AuthenticateResult.Fail(string.Empty)<\/code> sonucunu d\u00f6nd\u00fcrerek token&#8217;\u0131n ge\u00e7ersiz oldu\u011funu ifade ediyoruz.<\/p>\n<p> Bu s\u0131n\u0131f\u0131 sisteme dahil edebilmek i\u00e7in <em>&#8216;Program.cs&#8217;<\/em> dosyas\u0131nda a\u015fa\u011f\u0131daki gibi bir yap\u0131land\u0131rmada bulunmam\u0131z yeterli olacakt\u0131r;<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nbuilder.Services.AddAuthentication(options =&gt;\r\n{\r\n    options.DefaultAuthenticateScheme = &quot;Manual&quot;;\r\n    options.DefaultChallengeScheme = &quot;Manual&quot;;\r\n}).AddScheme&lt;AuthenticationSchemeOptions, ManualAuthenticationHandler&gt;(&quot;Manual&quot;, null);\r\n<\/pre>\n<\/div>\n<p>\u0130\u015fte JWT&#8217;yi haz\u0131r yap\u0131lanmalar\u0131n aksine, \u00f6zelle\u015ftirilmi\u015f davran\u0131\u015flarla manuel olarak nas\u0131l do\u011frulayabilece\u011fimizi mukayese ederek incelemi\u015f olduk. Bu a\u015famadan sonra \u00f6zel gereksinim yap\u0131lanmas\u0131 olan rol tabanl\u0131 yetkilendirmeyi incelemeye ge\u00e7ebiliriz.<\/p>\n<h4>\u00d6zel Gereksinim Yap\u0131lanmas\u0131(Rol Tabanl\u0131 Yetkilendirme)<\/h4>\n<p>Peki, \u015fimdi de \u00f6zelle\u015ftirilmi\u015f yetkilendirme kurallar\u0131 uygulamak istedi\u011fimiz durumlarda kullan\u0131labilecek yap\u0131lar\u0131 inceleyelim. Normal \u015fartlarda, Asp.NET Core yetkilendirme mekanizmalar\u0131 rol tabanl\u0131 yetkilendirme davran\u0131\u015f\u0131n\u0131 rahatl\u0131kla uygulayabilmemizi sa\u011flamaktad\u0131r ancak kimi durumlar vard\u0131r ki \u00f6zel \u015fartlara ba\u011fl\u0131 yetkilendirme ihtiya\u00e7lar\u0131 s\u00f6z konusu olabilmektedir.<\/p>\n<p>Bu gibi durumlarda manuel olarak yetkilendirme kurallar\u0131 belirleyebilmek i\u00e7in <code>IAuthorizationRequirement<\/code> ve <code>AuthorizationHandler<\/code> yap\u0131lanmalar\u0131 kullan\u0131l\u0131r. \u015eimdi bu yap\u0131lanmalar \u00fczerinden farazi bir \u00e7al\u0131\u015fma ile \u00f6zel bir gereksinim olu\u015ftural\u0131m. Misal olarak, token i\u00e7erisinde &#8216;resource_access&#8217; isimli alanda bulunan de\u011ferlere uygun rol tabanl\u0131 bir yetkilendirme \u00e7al\u0131\u015fmas\u0131n\u0131 sisteme entegre etmeyi hedefledi\u011fimizi d\u00fc\u015f\u00fcn\u00fcrsek e\u011fer bunun i\u00e7in \u00f6ncelikle bu gereksinimi temsil edecek olan requirement s\u0131n\u0131f\u0131n\u0131 olu\u015fturarak ba\u015flayabiliriz;<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public sealed record ResourceAccessRequirement(string Role) : IAuthorizationRequirement\r\n    {\r\n\r\n    }\r\n<\/pre>\n<\/div>\n<p>Bu s\u0131n\u0131f, Asp.NET Core&#8217;da yukar\u0131daki sat\u0131rlarda ifade etmeye \u00e7al\u0131\u015ft\u0131\u011f\u0131m \u00fczere \u00f6zel yetkilendirme gereksinimini temsil etmektedir. Yani bir endpoint&#8217;e eri\u015fim g\u00f6sterilmesi i\u00e7in hangi \u015fartlar\u0131n yerine getirilmesi gerekti\u011fi bu s\u0131n\u0131fla belirlenecektir. <em>Ee hoca! bu g\u00fcne kadar bu tarz bir s\u0131n\u0131f olu\u015fturmadan yetkilendirmemizi sa\u011fl\u0131yorduk!<\/em> dedi\u011finizi duyar gibiyim. Evet, bu g\u00fcne kadar token i\u00e7erisindeki claim&#8217;leri direkt de\u011fersel olarak yorumlay\u0131p &#8216;role&#8217; alan\u0131 &#8216;admin&#8217; ise bu endpoint&#8217;e eri\u015fim izni ver gibisinden \u00e7al\u0131\u015fmalar sergiliyorduk. Ancak burada mevzu bahis olan senaryoda kontrolde bulunmak istedi\u011fimiz claim&#8217;de bir de\u011ferden ziyade alt de\u011ferlerin oldu\u011funu varsay\u0131yoruz ve i\u015fte bu durumda nas\u0131l bir davran\u0131\u015f\u0131n sergilenmesi gerekti\u011fini konu\u015fuyoruz. Yani anlayaca\u011f\u0131n\u0131z, token i\u00e7erisindeki claim&#8217;lerde &#8216;resource_access&#8217; alan\u0131 i\u00e7erisindeki &#8216;x&#8217; alan\u0131 &#8216;y&#8217; ise bu endpoint&#8217;e eri\u015fim izni ver \u015feklinde bir \u00f6zel \u00e7al\u0131\u015fma yap\u0131lacaksa e\u011fer bunu \u00f6ncelikle bir requirement ile temsil etmemiz elzemdir ve ancak b\u00f6yle bir davran\u0131\u015fla bu \u00f6zel ihtiya\u00e7 giderilebilmektedir.<\/p>\n<p>Requirement&#8217;\u0131 olu\u015fturduktan sonra art\u0131k bu gereksinim kar\u015f\u0131l\u0131\u011f\u0131nda sergilenecek \u00f6zel davran\u0131\u015f\u0131 ifade edecek olan handler yap\u0131s\u0131n\u0131 a\u015fa\u011f\u0131daki gibi olu\u015fturabiliriz;<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public sealed class ResourceAccessHandler : AuthorizationHandler&lt;ResourceAccessRequirement&gt;\r\n    {\r\n        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ResourceAccessRequirement requirement)\r\n        {\r\n            var resourceAccessClaim = context.User.FindFirst(&quot;resource_access&quot;);\r\n\r\n            if (resourceAccessClaim != null)\r\n            {\r\n                using var jsonDocument = JsonDocument.Parse(resourceAccessClaim.Value);\r\n                var root = jsonDocument.RootElement;\r\n\r\n                if (root.TryGetProperty(&quot;realm-management&quot;, out var realmManagement))\r\n                    if (realmManagement.TryGetProperty(&quot;roles&quot;, out var rolesElement) &amp;&amp; rolesElement.ValueKind == JsonValueKind.Array)\r\n                    {\r\n                        var roles = rolesElement.EnumerateArray().Select(role =&gt; role.GetString());\r\n                        if (roles.Contains(requirement.Role))\r\n                            context.Succeed(requirement);\r\n                    }\r\n            }\r\n\r\n            return Task.CompletedTask;\r\n        }\r\n    }\r\n<\/pre>\n<\/div>\n<p>Burada ise AuthorizationHandler s\u0131n\u0131f\u0131 \u00fczerinden Asp.NET Core&#8217;da belirli bir yetkilendirme gereksinimini kar\u015f\u0131lamak i\u00e7in \u00f6zel bir mant\u0131k\/davran\u0131\u015f tan\u0131mlanmaktad\u0131r. Bu s\u0131n\u0131f ile olu\u015fturulan requirement&#8217;\u0131n \u015fartlar\u0131na\/i\u015f mant\u0131\u011f\u0131na uygunluk durumu kontrol edilmekte, bir ba\u015fka deyi\u015fle yetkilendirme karar\u0131 de\u011ferlendirilmektedir.<\/p>\n<p>Yap\u0131lan \u00e7al\u0131\u015fmaya g\u00f6z at\u0131l\u0131rsa e\u011fer \u00f6nceki sat\u0131rlarda bahsedildi\u011fi gibi token i\u00e7erisindeki &#8216;resource_access&#8217; alan\u0131 i\u00e7erisinde bulunan alt alanlar\u0131n de\u011ferleri okunarak requirement&#8217;ta verilen &#8216;role&#8217; de\u011ferinin kar\u015f\u0131lan\u0131p, kar\u015f\u0131lanmad\u0131\u011f\u0131 de\u011ferlendirilmekte ve duruma g\u00f6re yetkilendirme karar\u0131 verilmektedir. Burada pekte konumuzla alakal\u0131 olmasa da genel k\u00fclt\u00fcr mahiyetinde <code>JsonDocument<\/code>&#8216;tan da bahsetmekte fayda g\u00f6rmekteyim. Bu s\u0131n\u0131f ile metinsel olarak elde edilen JSON veriler olduk\u00e7a verimli bir \u015fekilde okunabilmektedir. Haliyle yapt\u0131\u011f\u0131m\u0131z \u00e7al\u0131\u015fmaya tekrar g\u00f6z atarsak, &#8216;resource_access&#8217; alan\u0131 root eleman olarak elde edilmekte, e\u011fer i\u00e7erisinde &#8216;realm-management&#8217; alan\u0131 varsa o alana girilmekte ve onun i\u00e7erisinde de &#8216;roles&#8217; alan\u0131 kontrol edilmektedir. Nihai olarak &#8216;roles&#8217; alan\u0131 i\u00e7erisinde requirement&#8217;a uygun bir de\u011fer var m\u0131 yok mu kontrol edilmekte ve b\u00f6ylece yetkilendirme verilmektedir. Demek ki bu uygulamada da rol tabanl\u0131 yetkilendirmenin gereksinimi bu \u015fekildeymi\u015f. Ee bu \u00f6zel ve sipesifik olan gereksinime kar\u015f\u0131n da yap\u0131lacak davran\u0131\u015f ancak bu \u015fekilde olmak mecburiyetindedir \ud83d\ude09<\/p>\n<p>\u00d6zetlersek e\u011fer AuthorizationHandler s\u0131n\u0131f\u0131nda; claim&#8217;leri ve di\u011fer ilgili gereksinimleri kullanarak eri\u015fim izninin verilip verilmeyece\u011fine dair kararlar verilmekte ve belirli bir requirement&#8217;\u0131 kar\u015f\u0131layan kullan\u0131c\u0131lar\u0131 do\u011frulamak i\u00e7in \u00f6zel bir mant\u0131k olu\u015fturulabilmektedir.<\/p>\n<p>Ayr\u0131ca olu\u015fturmu\u015f oldu\u011fumuz bu s\u0131n\u0131f i\u00e7erisindeki <code>HandleRequirementAsync<\/code> metodunun <code>AuthorizationHandlerContext context<\/code> parametresinden de bahsetmekte fayda g\u00f6rmekteyim. Bu paremetre; yetkilendirme s\u00fcrecindeki kullan\u0131c\u0131ya dair kimlik bilgilerini(claims), yetkilendirme gereksinimlerini(requirements) ve yetkilendirilecek kaynaklar\u0131n\u0131 i\u00e7ermektedir. Yani t\u00fcm bilgilere bu parametrelerden eri\u015filebilmektedir. Ayr\u0131ca ilgili context&#8217;i kullanarak kullan\u0131c\u0131n\u0131n eri\u015fim iznine sahip olup olmad\u0131\u011f\u0131n\u0131 da belirlemektedir. Bu paramerenin bizleri ilgilendiren \u00f6nemli \u00f6zellikleri \u015funlard\u0131r;<\/p>\n<ul style=\"font-size:12px;\">\n<li><em>context.User<\/em><br \/>\nKullan\u0131c\u0131n\u0131n kimlik bilgilerini ve rollerini(claims) i\u00e7ermektedir.\n<\/li>\n<li><em>context.Resource<\/em><br \/>\nYetkilendirme yap\u0131lacak kayna\u011f\u0131 ifade etmektedir.\n<\/li>\n<li><em>context.Succeed(requirement)<\/em><br \/>\nYetkilendirmenin ba\u015far\u0131yla tamamland\u0131\u011f\u0131n\u0131 ifade etmektedir.\n<\/li>\n<\/ul>\n<p>Evet, yap\u0131lan t\u00fcm bu \u00e7al\u0131\u015fmalar neticesinde requirement ve handler s\u0131n\u0131flar\u0131n\u0131 uygulamaya a\u015fa\u011f\u0131daki gibi ekleyerek sisteme dahil etmemiz gerekmektedir;<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nbuilder.Services.AddAuthorization(options =&gt;\r\n{\r\n    options.AddPolicy(&quot;UserRoleControl&quot;, policy =&gt; policy.Requirements.Add(new ResourceAccessRequirement(&quot;user&quot;)));\r\n});\r\n\r\nbuilder.Services.AddSingleton&lt;IAuthorizationHandler, ResourceAccessHandler&gt;();\r\n<\/pre>\n<\/div>\n<p>G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere burada <a href=\"https:\/\/www.gencayyildiz.com\/blog\/asp-net-core-identity-politika-bazli-kimlik-dogrulama-xvi\/\" rel=\"noopener\" target=\"_blank\">politika tabanl\u0131 bir kimlik do\u011frulama<\/a> yakla\u015f\u0131m\u0131 sergilenmektedir. <em>UserRoleControl<\/em> ad\u0131nda bir politika olu\u015fturulmakta ve gereksinim olarak da olu\u015fturdu\u011fumuz <em>ResourceAccessRequirement<\/em> t\u00fcr\u00fc verilmektedir. Burada dikkat ederseniz parametreye &#8216;user&#8217; de\u011feri verilmi\u015ftir. Bu, yukar\u0131daki sat\u0131rlarda detayland\u0131rd\u0131\u011f\u0131m\u0131z davran\u0131\u015f s\u00fcrecinde &#8216;user&#8217;a kar\u015f\u0131l\u0131k gelen yetkiyi denetleyecek anlam\u0131na gelmektedir. Ayr\u0131ca bu politikan\u0131n kullan\u0131laca\u011f\u0131 endpoint&#8217;lerde davran\u0131\u015f\u0131n devreye girebilmesi i\u00e7in <code>ResourceAccessHandler<\/code>&#8216;\u0131n IoC Container&#8217;a <code>IAuthorizationHandler<\/code> referans\u0131na kar\u015f\u0131n eklenmesi gerekmektedir. Bu ad\u0131mdan sonra art\u0131k hangi endpoint&#8217;te bu politika kullan\u0131lacaksa a\u015fa\u011f\u0131daki gibi <em>RequireAuthorization<\/em>&#8216;dan istifade edilerek politika ad\u0131n\u0131n belirtilmesi yeterlidir.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\napp.MapGet(&quot;\/&quot;, () =&gt; Results.Ok())\r\n    .RequireAuthorization(&quot;UserRoleControl&quot;);\r\n<\/pre>\n<\/div>\n<p>\u0130\u015fte bu kadar. Art\u0131k bu yap\u0131land\u0131rmalar neticesinde uygulama \u00f6zelle\u015ftirilmi\u015f davran\u0131\u015fla korunakl\u0131 hale getirilmi\u015ftir diyebiliriz. <\/p>\n<p>Nihai olarak;<br \/>\nHer ne kadar Asp.NET Core mimarisi, genel ge\u00e7er senaryolara uygun authentication ve authorization yap\u0131lanmalar\u0131n\u0131 standartlar e\u015fli\u011finde haz\u0131r bir \u015fekilde bizlere sunuyor olsa da i\u00e7eri\u011fimiz s\u00fcresince g\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere bazen \u00e7ok spesifik durumlara kar\u015f\u0131n \u00f6zelle\u015ftirilmi\u015f davran\u0131\u015flar sergilememiz gerekebilmektedir ve bu gereksinimlere kar\u015f\u0131n Asp.NET Core mimarisi taraf\u0131ndan geni\u015fletici yap\u0131lar ucu a\u00e7\u0131k bir \u015fekilde hizmetimize sunulmu\u015ftur. Elbette standartlar\u0131n d\u0131\u015f\u0131na \u00e7\u0131k\u0131p \u00f6zel kimlik do\u011frulama ve yetkilendirme davran\u0131\u015flar\u0131n\u0131n geli\u015ftirilmesi gerekti\u011fi olas\u0131 ihtiya\u00e7 durumlar\u0131nda ka\u00e7\u0131n\u0131lmaz olarak bu yap\u0131lanmalara ba\u015fvurarak uygulamalar\u0131m\u0131z\u0131 her senaryoya uygun bir \u015fekilde g\u00f6n\u00fcl rahatl\u0131\u011f\u0131yla geli\u015ftirebiliriz.<\/p>\n<p>\u0130lgilenenlerin faydalanmas\u0131 dile\u011fiyle&#8230;<br \/>\nSonraki yaz\u0131lar\u0131mda g\u00f6r\u00fc\u015fmek \u00fczere&#8230;<br \/>\n\u0130yi \u00e7al\u0131\u015fmalar&#8230;<\/p>\n<p>Not : \u00d6rnek \u00e7al\u0131\u015fmaya a\u015fa\u011f\u0131daki github adresinden eri\u015febilirsiniz.<br \/>\n<a href=\"https:\/\/github.com\/gncyyldz\/AspNetCoreCustomAuth\" rel=\"noopener\" target=\"_blank\">https:\/\/github.com\/gncyyldz\/AspNetCoreCustomAuth<\/a><\/p>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content -->","protected":false},"excerpt":{"rendered":"<p>Merhaba, Her web uygulamas\u0131nda g\u00fcvenlik a\u00e7\u0131s\u0131ndan kullan\u0131c\u0131 ve yetki y\u00f6netimi olduk\u00e7a kritik arz eden konulard\u0131r. Dolay\u0131s\u0131yla bu temel davran\u0131\u015flar, Asp.NET Core uygulamalar\u0131 i\u00e7in de olmazsa olmazd\u0131r diyebiliriz. Bundan dolay\u0131 Asp.NET Core mimarisinde, kimlik do\u011frulama&#46;&#46;&#46;<!-- AddThis Advanced Settings generic via filter on get_the_excerpt --><!-- AddThis Share Buttons generic via filter on get_the_excerpt --><\/p>\n","protected":false},"author":1,"featured_media":3014,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3102],"tags":[2679,5171,5172,5174,5175,2759,2958,3057,5173,5009,3055],"class_list":["post-27304","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-asp-net-core","tag-asp-net-core","tag-asp-net-core-authentication","tag-asp-net-core-authorization","tag-asp-net-core-custom-authentication","tag-asp-net-core-custom-authorization","tag-authentication","tag-authorization","tag-authorizationhandler","tag-custom-authentication","tag-custom-authorization","tag-iauthorizationrequirement"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/27304","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/comments?post=27304"}],"version-history":[{"count":5,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/27304\/revisions"}],"predecessor-version":[{"id":27310,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/27304\/revisions\/27310"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media\/3014"}],"wp:attachment":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media?parent=27304"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/categories?post=27304"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/tags?post=27304"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}