﻿
{"id":19642,"date":"2020-12-04T13:54:53","date_gmt":"2020-12-04T13:54:53","guid":{"rendered":"https:\/\/www.gencayyildiz.com\/blog\/?p=19642"},"modified":"2020-12-04T13:57:36","modified_gmt":"2020-12-04T13:57:36","slug":"identityserver4-yazi-serisi-22-resource-owner-credential-grant-uygulamasi","status":"publish","type":"post","link":"https:\/\/www.gencayyildiz.com\/blog\/identityserver4-yazi-serisi-22-resource-owner-credential-grant-uygulamasi\/","title":{"rendered":"IdentityServer4 Yaz\u0131 Serisi #22 \u2013 Resource Owner Credential Grant Uygulamas\u0131"},"content":{"rendered":"<div id=\"fb-root\"><\/div>\n<p>Merhaba,<\/p>\n<p><a href=\"https:\/\/www.gencayyildiz.com\/blog\/identityserver4-yazi-serisi\/\" rel=\"noopener noreferrer\" target=\"_blank\">IdentityServer4 Yaz\u0131 Serisi<\/a>nin yirmiikinci makalesinde <a href=\"https:\/\/www.gencayyildiz.com\/blog\/identityserver4-yazi-serisi-10-resource-owner-credentials-grantflow\/\" rel=\"noopener noreferrer\" target=\"_blank\">Resource Owner Credential Grant<\/a> ak\u0131\u015f tipini kullanan uygulama geli\u015ftirece\u011fiz.<\/p>\n<p><strong style=\"color:orange;\">Ba\u015flarken<\/strong><br \/>\n\u0130lk olarak bu ak\u0131\u015f t\u00fcr\u00fcn\u00fcn \u00f6zelli\u011fini hat\u0131rlayarak ba\u015flayal\u0131m. <em>Resource Owner Credential Grant<\/em>, kullan\u0131c\u0131y\u0131 y\u00f6nlendirme yapmaks\u0131z\u0131n direkt olarak Auth Server \u00fczerinden yetkilendiren bir ak\u0131\u015f t\u00fcr\u00fcd\u00fcr. Bu ak\u0131\u015f t\u00fcr\u00fcn\u00fc daha detayl\u0131 inceleyebilmek i\u00e7in yukar\u0131da adresi verilen makaleyi okuman\u0131z\u0131 tavsiye ederim.<\/p>\n<p><strong style=\"color:orange;\">Auth Server Uygulamas\u0131<\/strong><br \/>\n\u00d6rneklendirmeyi MVC client uygulamas\u0131 tasarlayarak ger\u00e7ekle\u015ftirece\u011fiz. Tabi her\u015feyden \u00f6nce bu uygulamaya kar\u015f\u0131l\u0131k Auth Server&#8217;da client tasarlayarak ba\u015flayal\u0131m;<br \/>\n<span style=\"font-size:11px;\">(Not: Config.cs dosyas\u0131 ve IdentityServer4 konfig\u00fcrasyonlar\u0131 yaz\u0131 serisi boyunca de\u011ferlendirildi\u011fi i\u00e7in bu i\u00e7erikte ele al\u0131nmayacak, yap\u0131ld\u0131klar\u0131 varsay\u0131lacakt\u0131r.)<\/span><\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n                .\r\n                .\r\n                .\r\n                new Client{\r\n                    ClientId = &quot;ResourceOwnerClient&quot;,\r\n                    ClientName = &quot;Resource Owner Client&quot;,\r\n                    ClientSecrets = { new Secret(&quot;resourceownerclient&quot;.Sha256()) },\r\n                    AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,\r\n                    AllowedScopes =\r\n                    {\r\n                        &quot;Garanti.Write&quot;, &quot;Garanti.Read&quot;,\r\n                        IdentityServerConstants.StandardScopes.Profile,\r\n                        IdentityServerConstants.StandardScopes.OpenId,\r\n                        IdentityServerConstants.StandardScopes.Email,\r\n                        &quot;Roles&quot; \/\/Identity Resource\r\n                    },\r\n                    AccessTokenLifetime = 3 * 60,\r\n                    AllowOfflineAccess = true,\r\n                    RefreshTokenUsage = TokenUsage.OneTimeOnly,\r\n                    RefreshTokenExpiration = TokenExpiration.Absolute,\r\n                    AbsoluteRefreshTokenLifetime = (3 * 60) + 30,\r\n                    RequirePkce = false\r\n                }\r\n                .\r\n                .\r\n                .\r\n<\/pre>\n<p>Yukar\u0131daki client tan\u0131mlamas\u0131nda g\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere <em><strong>8.<\/strong><\/em> sat\u0131rda oldu\u011fu gibi &#8216;AllowedGrantTypes&#8217; \u00f6zelli\u011fine &#8216;GrantTypes.ResourceOwnerPassword&#8217; de\u011feri verilerek ilgili ak\u0131\u015f t\u00fcr\u00fcyle \u00e7al\u0131\u015f\u0131laca\u011f\u0131 bildirilmektedir. Geri kalan t\u00fcm \u00f6zellikler ise \u00f6nceden inceledi\u011fimiz konfig\u00fcrasyonlara kar\u015f\u0131l\u0131k gelmektedir.<\/p>\n<p>Akabinde ilgili uygulama \u00fczerinden giri\u015f yapabilecek bir user&#8217;a ihtiyac\u0131m\u0131z olacakt\u0131r. Bunun i\u00e7in a\u015fa\u011f\u0131daki gibi bir test user tan\u0131mlamas\u0131 yapmam\u0131z yeterlidir;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n                new TestUser\r\n                {\r\n                     SubjectId = &quot;test-user1&quot;,\r\n                     Username = &quot;test-user1&quot;,\r\n                     Password = &quot;12345&quot;,\r\n                     Claims = new List&lt;Claim&gt;\r\n                     {\r\n                         new Claim(&quot;email&quot;, &quot;test-user@identity.com&quot;),\r\n                         new Claim(&quot;role&quot;, &quot;admin&quot;),\r\n                         new Claim(&quot;role&quot;, &quot;moderator&quot;),\r\n                         new Claim(&quot;name&quot;, &quot;hilmi&quot;)\r\n                     }\r\n                }\r\n<\/pre>\n<p>Evet, MVC uygulamam\u0131z\u0131n Resource Owner Credential ak\u0131\u015f\u0131 ile \u00e7al\u0131\u015fmas\u0131 i\u00e7in Auth Server neredeyse haz\u0131r. \u015eimdi MVC client&#8217;\u0131 \u00fczerinden bu ak\u0131\u015f ile bir istek yap\u0131ld\u0131\u011f\u0131 zaman o iste\u011fi kar\u015f\u0131layacak ve gerekli username ve password bilgileri e\u015fli\u011finde kimlik do\u011frulamay\u0131 ger\u00e7ekle\u015ftirecek olan <em>IResourceOwnerPasswordValidator<\/em> katman\u0131n\u0131 tasarlamam\u0131z gerekmektedir.<\/p>\n<p><strong style=\"color:orange;\">IResourceOwnerPasswordValidator Interface&#8217;i \u0130le Kimlik Bilgilerini Do\u011frulama<\/strong><br \/>\nYukar\u0131da da bahsedildi\u011fi gibi Resource Owner Credential ak\u0131\u015f\u0131 ile kimlik do\u011frulamay\u0131 ger\u00e7ekle\u015ftirebilmek i\u00e7in Auth Server&#8217;da <em>IResourceOwnerPasswordValidator<\/em> interface&#8217;inden t\u00fcreyen bir s\u0131n\u0131f tasarlamam\u0131z gerekmektedir.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator\r\n    {\r\n        public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)\r\n        {\r\n            if (context.UserName == &quot;test-user1&quot; &amp;&amp; context.Password == &quot;12345&quot;)\r\n                context.Result = new GrantValidationResult(&quot;test-user1&quot;, OidcConstants.AuthenticationMethods.Password);\r\n        }\r\n    }\r\n<\/pre>\n<p>Yukar\u0131daki s\u0131n\u0131f\u0131 incelerseniz ilgili interface taraf\u0131ndan implemente edilen &#8216;ValidateAsync&#8217; metodu i\u00e7erisinde kimlik do\u011frulama i\u015flemi ger\u00e7ekle\u015ftirilmektedir. Tabi burada test user kulland\u0131\u011f\u0131m\u0131zdan dolay\u0131 manuel bir kar\u015f\u0131la\u015ft\u0131rma olsa da esas\u0131nda kullan\u0131c\u0131 bilgileri veritaban\u0131nda tutulaca\u011f\u0131 i\u00e7in gerekli \u00e7al\u0131\u015fman\u0131n yap\u0131lmas\u0131 ve veritaban\u0131 \u00fczerinden sorgulanmas\u0131 gerekmektedir. Velhas\u0131l bir \u015fekilde kullan\u0131c\u0131 bilgileri do\u011fruland\u0131ktan sonra ilgili metodun &#8216;ResourceOwnerPasswordValidationContext&#8217; t\u00fcr\u00fcnden olan context isimli parametresinin &#8216;Result&#8217; property&#8217;sine &#8216;GrantValidationResult&#8217; t\u00fcr\u00fcnden bir nesne set ediyor ve ilk parametresine kullan\u0131c\u0131n\u0131n subject id de\u011ferini, ikincisine ise kullan\u0131lan authentication metot t\u00fcr\u00fcn\u00fc yani resource owner grant(nam-\u0131 di\u011fer password) de\u011ferini veriyoruz.<\/p>\n<p>Ard\u0131ndan ilgili s\u0131n\u0131f\u0131 Auth Server&#8217;\u0131n &#8216;Startup.cs&#8217; dosyas\u0131nda &#8216;AddResourceOwnerValidator&#8217; metodu e\u015fli\u011finde IdentityServer servisine dahil ediyoruz.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n            services.AddIdentityServer()\r\n                    .\r\n                    .\r\n                    .\r\n                    .AddResourceOwnerValidator&lt;ResourceOwnerPasswordValidator&gt;()\r\n                    .AddDeveloperSigningCredential();\r\n<\/pre>\n<p><strong style=\"color:orange;\">MVC Uygulamas\u0131<\/strong><br \/>\nS\u0131ra client uygulamas\u0131n\u0131 geli\u015ftirmeye gelmi\u015ftir. \u0130lk olarak MVC client&#8217;\u0131n\u0131 geli\u015ftirece\u011fimizden dolay\u0131 bir adet Asp.NET Core MVC uygulamas\u0131 olu\u015ftural\u0131m ve i\u00e7erisine &#8216;HomeController&#8217;\u0131 ekleyelim. Ard\u0131ndan ilgili controller i\u00e7erisine &#8216;Login&#8217; action metodunu olu\u015ftural\u0131m ve .cshtml dosyas\u0131n\u0131 a\u015fa\u011f\u0131daki gibi tasarlayal\u0131m.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n@model UserLogin\r\n\r\n&lt;form method=&quot;post&quot;&gt;\r\n    &lt;div class=&quot;form-group&quot;&gt;\r\n        &lt;label&gt;Username&lt;\/label&gt;\r\n        &lt;input asp-for=&quot;Username&quot; type=&quot;text&quot; class=&quot;form-control&quot;&gt;\r\n    &lt;\/div&gt;\r\n    &lt;div class=&quot;form-group&quot;&gt;\r\n        &lt;label&gt;Password&lt;\/label&gt;\r\n        &lt;input type=&quot;password&quot; asp-for=&quot;Password&quot; class=&quot;form-control&quot;&gt;\r\n    &lt;\/div&gt;\r\n    &lt;button type=&quot;submit&quot; class=&quot;btn btn-primary&quot;&gt;Giri\u015f Yap&lt;\/button&gt;\r\n&lt;\/form&gt;\r\n<\/pre>\n<p>Bu, kullan\u0131c\u0131 giri\u015finin yap\u0131laca\u011f\u0131 sayfad\u0131r. Username ve password bilgilerini ta\u015f\u0131yan &#8216;UserLogin&#8217; modeli ise a\u015fa\u011f\u0131daki gibidir.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class UserLogin\r\n    {\r\n        public string Username { get; set; }\r\n        public string Password { get; set; }\r\n    }\r\n<\/pre>\n<p>Post neticesinde verileri kar\u015f\u0131layacak olan metoduda tasarlarsak e\u011fer;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n        public async Task Login(UserLogin userLogin)\r\n        {\r\n            HttpClient client = new HttpClient();\r\n            DiscoveryDocumentResponse disco = await client.GetDiscoveryDocumentAsync(&quot;https:\/\/localhost:1000&quot;);\r\n            PasswordTokenRequest password = new PasswordTokenRequest()\r\n            {\r\n                UserName = userLogin.Username,\r\n                Password = userLogin.Password,\r\n                ClientId = &quot;ResourceOwnerClient&quot;,\r\n                ClientSecret = &quot;resourceownerclient&quot;,\r\n                Address = disco.TokenEndpoint\r\n            };\r\n            TokenResponse token = await client.RequestPasswordTokenAsync(password);\r\n            UserInfoRequest userInfoRequest = new UserInfoRequest\r\n            {\r\n                Token = token.AccessToken,\r\n                Address = disco.UserInfoEndpoint\r\n            };\r\n            UserInfoResponse userInfo = await client.GetUserInfoAsync(userInfoRequest);\r\n            ClaimsIdentity claimsIdentity = new ClaimsIdentity(userInfo.Claims, CookieAuthenticationDefaults.AuthenticationScheme, &quot;name&quot;, &quot;role&quot;);\r\n            ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(claimsIdentity);\r\n            AuthenticationProperties properties = new AuthenticationProperties();\r\n            properties.StoreTokens(new List&lt;AuthenticationToken&gt;\r\n            {\r\n              new AuthenticationToken\r\n                                     {\r\n                                         Name = OpenIdConnectParameterNames.IdToken,\r\n                                         Value = token.IdentityToken\r\n                                     },\r\n              new AuthenticationToken\r\n                                     {\r\n                                         Name = OpenIdConnectParameterNames.AccessToken,\r\n                                         Value = token.AccessToken\r\n                                     },\r\n              new AuthenticationToken\r\n                                     {\r\n                                         Name = OpenIdConnectParameterNames.RefreshToken,\r\n                                         Value = token.RefreshToken\r\n                                     },\r\n              new AuthenticationToken\r\n                                     {\r\n                                         Name = OpenIdConnectParameterNames.ExpiresIn,\r\n                                         Value = DateTime.UtcNow.AddSeconds(token.ExpiresIn).ToString(&quot;O&quot;)\r\n                                     },\r\n            });\r\n            await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal, properties);\r\n        }\r\n<\/pre>\n<p>\u015feklinde olacakt\u0131r. Yukar\u0131daki kod blo\u011funu izah edersek e\u011fer;<\/p>\n<ul>\n<li><strong><em>3 &#8211; 12. sat\u0131r aral\u0131\u011f\u0131<\/em><\/strong><br \/>\nKlasik <a href=\"https:\/\/www.gencayyildiz.com\/blog\/identityserver4-yazi-serisi-5-discovery-endpoint\/\" rel=\"noopener noreferrer\" target=\"_blank\">discovery endpoint<\/a>&#8216;e istek g\u00f6nderilmekte ve token talebi i\u00e7in gerekli request nesnesi(PasswordTokenRequest) \u00fcretilmektedir.\n<\/li>\n<li><strong><em>13. sat\u0131r<\/em><\/strong><br \/>\nAuth Server&#8217;a &#8216;RequestPasswordTokenAsync&#8217; fonksiyonu ile resource owner credential t\u00fcr\u00fcnde istek yap\u0131lmakta ve token talep edilmektedir.\n<\/li>\n<li><strong><em>14 &#8211; 19. sat\u0131r aral\u0131\u011f\u0131<\/em><\/strong><br \/>\nElde edilen token&#8217;da ki access token de\u011feri ile kullan\u0131c\u0131 bilgileri talep edilmektedir.\n<\/li>\n<li><strong><em>20 &#8211; 21. sat\u0131r aral\u0131\u011f\u0131<\/em><\/strong><br \/>\nKullan\u0131c\u0131 bilgileri tutacak olan &#8216;ClaimsPrincipal&#8217; nesnesi olu\u015fturulmaktad\u0131r. Burada dikkat edilmesi gereken husus 20. sat\u0131rda \u00fcretilen <code>new ClaimsIdentity(userInfo.Claims, CookieAuthenticationDefaults.AuthenticationScheme, \"name\", \"role\");<\/code> nesnesinin ilk parametresi d\u0131\u015f\u0131nda 2. , 3. ve 4. parametreleridir. 2. parametre, ilgili uygulaman\u0131n kulland\u0131\u011f\u0131 cookie ad\u0131n\u0131 gerektirirken<span style=\"font-size:10px;\">(a\u015fa\u011f\u0131daki sat\u0131rlarda g\u00f6rece\u011fiz)<\/span>, 3. parametre <code style=\"color:red;\">User.Identity.Name<\/code> koduna kar\u015f\u0131l\u0131k kullan\u0131c\u0131dan gelen hangi claim ile e\u015fle\u015ftirilmesi gerekti\u011fini bildirmekte ve 4. parametre ise benzer \u015fekilde kullan\u0131c\u0131n\u0131n authorize\/rol yetkisinin yine kullan\u0131c\u0131dan gelen claim&#8217;lerden hangisiyle e\u015fle\u015fmesi gerekti\u011fini belirlemektedir.<\/p>\n<p>Burada ilgili claim de\u011ferlerinin elde edilebilmesi i\u00e7in Auth Server&#8217;da a\u015fa\u011f\u0131daki Identity Resource&#8217;lerin eklenmesi gerekti\u011fini unutmay\u0131n\u0131z&#8230;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n                .\r\n                .\r\n                .\r\n                new IdentityResources.OpenId(),\r\n                new IdentityResources.Profile(),\r\n                new IdentityResources.Email(),\r\n                new IdentityResource\r\n                {\r\n                    Name = &quot;Roles&quot;,\r\n                    Description = &quot;Roles&quot;,\r\n                    DisplayName = &quot;Roles&quot;,\r\n                    UserClaims =\r\n                    {\r\n                        &quot;role&quot;\r\n                    }\r\n                }\r\n                .\r\n                .\r\n                .\r\n<\/pre>\n<\/li>\n<li><strong><em>22 &#8211; 44 sat\u0131r aral\u0131\u011f\u0131<\/em><\/strong><br \/>\nBurada giri\u015f yapan kullan\u0131c\u0131n\u0131n elde etti\u011fi authentication properties bilgilerini client uygulamas\u0131 \u00fczerinde g\u00fcncellemekteyiz. Hatta hat\u0131rlarsan\u0131z IdentityServer4 mimarisi i\u00e7in <a href=\"https:\/\/www.gencayyildiz.com\/blog\/identityserver4-yazi-serisi-14-merkezi-uyelik-sistemi-refresh-token-ile-yeni-access-token-alma\/\" rel=\"noopener noreferrer\" target=\"_blank\">refresh token<\/a> konusunu ele al\u0131rken de birebir ayn\u0131 i\u015flemi ger\u00e7ekle\u015ftirmi\u015ftik. Lakin ilgili makalede authentication property&#8217;leri<br \/>\n<code>(await HttpContext.AuthenticateAsync()).Properties;<\/code> kodu ile elde ediyor, \u00fczerine de\u011fi\u015fikliklerimizi ger\u00e7ekle\u015ftiriyorduk. Halbuki burada direkt olarak &#8216;AuthenticationProperties&#8217; t\u00fcr\u00fcnden nesneyi elimizle manuel olu\u015fturuyoruz.\n<\/li>\n<li><strong><em>46. sat\u0131r<\/em><\/strong><br \/>\nGiri\u015f i\u015flemini yukar\u0131da \u00fcretilen de\u011ferler e\u015fli\u011finde ger\u00e7ekle\u015ftiriyoruz.\n<\/li>\n<\/ul>\n<p>Bu geli\u015ftirmelerden sonra client uygulamas\u0131n\u0131n &#8216;Startup.cs&#8217; dosyas\u0131nda a\u015fa\u011f\u0131daki geli\u015ftirmenin yap\u0131lmas\u0131 gerekmektedir;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)\r\n                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, _ =&gt;\r\n                {\r\n                    _.LoginPath = new PathString(&quot;\/home\/login&quot;);\r\n                });\r\n<\/pre>\n<p>Eklene cookie servisine \u015fema ad\u0131 olarak &#8216;Cookies&#8217; de\u011ferini ta\u015f\u0131yan <code>CookieAuthenticationDefaults.AuthenticationScheme<\/code> sabit verilmektedir. Dikkat ederseniz ayn\u0131 sabit yukar\u0131da login i\u015flemi esnas\u0131nda da ilgili alanlarda kullan\u0131lmaktad\u0131r.<\/p>\n<p>Ve bir nazar\u0131n\u0131za de\u011fer noktay\u0131 daha i\u015faret ederim ki o da &#8216;AddOpenIdConnect&#8217; servisinin kullan\u0131lmamas\u0131d\u0131r. &#8216;AddOpenIdConnect&#8217; servisi kimlik do\u011frulamay\u0131 ger\u00e7ekle\u015ftiren bir protokold\u00fc. Haliyle bizler bu protokol\u00fcn yapaca\u011f\u0131 i\u015flemi yukar\u0131da manuel yapm\u0131\u015f bulunmaktay\u0131z. O y\u00fczden bu servisi eklemeye gerek kalmam\u0131\u015ft\u0131r.<\/p>\n<p>Ve son olarak client uygulamas\u0131nda kimlik do\u011frulama ve yetkilendirme i\u015flemlerinin sa\u011fl\u0131kl\u0131 bir \u015fekilde i\u015fleyebilmesi i\u00e7in &#8216;UseAuthentication&#8217; ve &#8216;UseAuthorization&#8217; middleware&#8217;lerini \u00e7a\u011f\u0131rmay\u0131 unutmuyoruz.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n            app.UseAuthentication();\r\n            app.UseAuthorization();\r\n<\/pre>\n<p>\u00c7\u0131k\u0131\u015f i\u015flemi i\u00e7inde a\u015fa\u011f\u0131daki action&#8217;\u0131 kullanabilirsiniz.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n        public async Task Logout()\r\n        {\r\n            await HttpContext.SignOutAsync();\r\n        }\r\n<\/pre>\n<p>Velhas\u0131l kelam, art\u0131k uygulamay\u0131 derleyip, \u00e7al\u0131\u015ft\u0131rabilir ve test edebiliriz.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/12\/IdentityServer4-Yazi-Serisi-22-\u2013-Resource-Owner-Credential-Grant-Uygulamasi.gif\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/12\/IdentityServer4-Yazi-Serisi-22-\u2013-Resource-Owner-Credential-Grant-Uygulamasi.gif\" alt=\"IdentityServer4 Yaz\u0131 Serisi #22 \u2013 Resource Owner Credential Grant Uygulamas\u0131\" width=\"800\" height=\"546\" class=\"aligncenter size-full wp-image-19695\" \/><\/a><br \/>\nG\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere MVC uygulamas\u0131 resource owner credential ak\u0131\u015f\u0131yla gayet ba\u015far\u0131l\u0131 bir \u015fekilde Auth Server&#8217;dan yetkilendirilebilmektedir.<\/p>\n<p>Ayriyeten,<br \/>\nAngular vs. gibi SPA uygulamalar\u0131nda yahut Console gibi farkl\u0131 platformlarda resource owner credential kullanmak istiyorsan\u0131z e\u011fer temelde kullanaca\u011f\u0131n\u0131z yap\u0131lanma yine ayn\u0131 tasar\u0131mdan ibaret olacakt\u0131r. Sadece token&#8217;\u0131 elde ettikten sonra authentication property&#8217;leri MVC&#8217;de oldu\u011fu gibi store etmenize gerek kalmayacak, hangi platformda \u00e7al\u0131\u015f\u0131yorsan\u0131z ilgili platformun gere\u011fi ne ise ona g\u00f6re bir tasar\u0131m yap\u0131lmas\u0131 gerekecektir. Tabi, platform olarak Angular gibi SPA tercih ediyorsan\u0131z, uygulama ile Auth Server aras\u0131nda ilgili ak\u0131\u015f\u0131 kullanacak bir API tasarlayabilir ve onun \u00fczerinden Auth Server&#8217;la ili\u015fkiyi kurabilirsiniz.<\/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 uygulamay\u0131 indirebilmek i\u00e7in <a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/12\/PasswordOwnerCredentialExample.zip\">buraya<\/a> t\u0131klay\u0131n\u0131z.<\/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, IdentityServer4 Yaz\u0131 Serisinin yirmiikinci makalesinde Resource Owner Credential Grant ak\u0131\u015f tipini kullanan uygulama geli\u015ftirece\u011fiz. Ba\u015flarken \u0130lk olarak bu ak\u0131\u015f t\u00fcr\u00fcn\u00fcn \u00f6zelli\u011fini hat\u0131rlayarak ba\u015flayal\u0131m. Resource Owner Credential Grant, kullan\u0131c\u0131y\u0131 y\u00f6nlendirme yapmaks\u0131z\u0131n direkt olarak Auth&#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":18168,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3826],"tags":[3827,3988,3987],"class_list":["post-19642","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-identityserver4","tag-identityserver4","tag-iresourceownerpasswordvalidator","tag-resource-owner-credential-grant"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/19642","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=19642"}],"version-history":[{"count":63,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/19642\/revisions"}],"predecessor-version":[{"id":19708,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/19642\/revisions\/19708"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media\/18168"}],"wp:attachment":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media?parent=19642"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/categories?post=19642"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/tags?post=19642"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}