﻿
{"id":17985,"date":"2020-10-02T00:05:10","date_gmt":"2020-10-02T00:05:10","guid":{"rendered":"https:\/\/www.gencayyildiz.com\/blog\/?p=17985"},"modified":"2020-10-02T00:05:10","modified_gmt":"2020-10-02T00:05:10","slug":"asp-net-core-signalr-serisi-10-derinlemesine-kimlik-dogrulamaauthentication-ve-yetkilendirmeauthorization","status":"publish","type":"post","link":"https:\/\/www.gencayyildiz.com\/blog\/asp-net-core-signalr-serisi-10-derinlemesine-kimlik-dogrulamaauthentication-ve-yetkilendirmeauthorization\/","title":{"rendered":"Asp.NET Core \u2013 SignalR Serisi #10 &#8211; Derinlemesine Kimlik Do\u011frulama(Authentication) ve Yetkilendirme(Authorization)"},"content":{"rendered":"<div id=\"fb-root\"><\/div>\n<p>Merhaba,<\/p>\n<p>Klasik web uygulamalar\u0131nda oldu\u011fu gibi SignalR mimarisiyle real time \u00e7al\u0131\u015fan uygulamalarda da kullan\u0131c\u0131 do\u011frulama ve yetkilendirme ihtiyac\u0131 hissedebilir ve e\u015fzamanl\u0131 veri ak\u0131\u015f\u0131 esnas\u0131nda tan\u0131ml\u0131 kullan\u0131c\u0131lar d\u0131\u015f\u0131nda etkile\u015fime m\u00fcdahale olunmas\u0131n\u0131 istemeyebiliriz. Bu i\u00e7eri\u011fimizde, bu ihtiyaca istinaden t\u00fcm detaylar\u0131yla bir izahatte bulunacak ve SignalR mimarisinde <em>Authentication<\/em> ve <em>Authorization<\/em> i\u015flemlerini ele alaca\u011f\u0131z.<\/p>\n<h3 style=\"color: #e83e8c;\">Ba\u015flarken<\/h3>\n<p>\u0130\u00e7eri\u011fimizin derinliklerine girmeden \u00f6nce izleyece\u011fimiz yolu genel hatlar\u0131yla g\u00f6sterebilmek i\u00e7in klavuz niteli\u011finde a\u00e7\u0131klama yapmakta fayda var. SignalR ile authentication ve authorization yap\u0131lanmas\u0131n\u0131 inceleyebilmek i\u00e7in JWT&#8217;den faydalanacak ve t\u00fcm detaylar\u0131yla bir Asp.NET Core Web API uygulamas\u0131na JWT entegrasyonunun nas\u0131l yap\u0131ld\u0131\u011f\u0131n\u0131 inceleyece\u011fiz. Ard\u0131ndan SignalR&#8217;\u0131n bildi\u011fimiz yap\u0131lanmas\u0131 ile basit bir uygulama geli\u015ftirecek ve bunun yan\u0131nda kullan\u0131c\u0131 ekleme ve login olma gibi i\u015flemleri Hub&#8217;lar \u00fczerinden ger\u00e7ekle\u015ftirece\u011fiz. Kullan\u0131c\u0131 do\u011frulama ard\u0131ndan yetkilendirme(authorization) konusuna de\u011finece\u011fiz. S\u00fcreci daha da efektif bir hale getirebilmek i\u00e7in Refresh Token stratejisinden faydalanaca\u011f\u0131z. T\u00fcm s\u00fcre\u00e7; real time bir \u015fekilde, gerekli kritikleri gerekti\u011fi noktalarda yaparak ad\u0131m ad\u0131m bir \u015fekilde tasarlanacakt\u0131r.<\/p>\n<p>\u015eimdi bir Asp.NET Core Web API uygulamas\u0131 olu\u015fturup, hali haz\u0131rda i\u00e7eri\u011fe devam edebiliriz.<\/p>\n<h3 style=\"color: #e83e8c;\">JWT Mekanizmas\u0131n\u0131n \u0130n\u015fas\u0131<\/h3>\n<p>Konumuz her ne kadar SignalR&#8217;da olsa JWT ile authentication ve authorization i\u015flemleri ger\u00e7ekle\u015ftireceksek e\u011fer illaki \u00f6ncelikle JWT \u00fcretebilecek mekanizmay\u0131 in\u015fa etmemiz gerekmektedir. Normalde bu mekanizmay\u0131 <a href=\"https:\/\/www.gencayyildiz.com\/blog\/asp-net-core-3-1-ile-token-bazli-kimlik-dogrulamasi-ve-refresh-token-kullanimijwt\/\" rel=\"noopener noreferrer\" target=\"_blank\">Asp.NET Core 3.1 ile Token Bazl\u0131 Kimlik Do\u011frulamas\u0131 ve Refresh Token Kullan\u0131m\u0131(JWT)<\/a> ba\u015fl\u0131kl\u0131 makaleyi referans ederek, in\u015fa edildi\u011fini varsay\u0131p ge\u00e7ebilirdik. Lakin sizlerin ilgili konuyu peki\u015ftirmeniz ve daha da hakim olabilmeniz i\u00e7in burada da tekrardan entegrasyon s\u00fcrecine de\u011finmeyi ve ele almay\u0131 uygun g\u00f6rmekteyim.<\/p>\n<p>Hadi ba\u015flayal\u0131m \ud83d\ude42<\/p>\n<ul>\n<li><strong>Ad\u0131m 1<\/strong><br \/>\nHer \u015feyden \u00f6nce uygulamada kullan\u0131c\u0131lara kar\u015f\u0131l\u0131k gelecek olan &#8216;User&#8217; modelini ve context nesnesini olu\u015fturarak ba\u015flayal\u0131m.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class User\r\n    {\r\n        public int Id { get; set; }\r\n        public string Username { get; set; }\r\n        public string Password { get; set; }\r\n        public string RefreshToken { get; set; }\r\n        public DateTime RefreshTokenEndDate { get; set; }\r\n    }\r\n<\/pre>\n<p>Burada dikkat ederseniz e\u011fer kullan\u0131c\u0131 oturumunun s\u00fcreklili\u011fine dair refresh token stratejisini uygulayaca\u011f\u0131m\u0131zdan dolay\u0131 &#8216;RefrestToken&#8217; ve &#8216;RefreshTokenEndDate&#8217; propertyleri tan\u0131mlanm\u0131\u015ft\u0131r. Konuya dair daha detayl\u0131 bilgi i\u00e7in bknz : <a style=\"font-size:10px;\" href=\"https:\/\/www.gencayyildiz.com\/blog\/asp-net-core-3-1-ile-token-bazli-kimlik-dogrulamasi-ve-refresh-token-kullanimijwt\/\" rel=\"noopener noreferrer\" target=\"_blank\">Asp.NET Core 3.1 ile Token Bazl\u0131 Kimlik Do\u011frulamas\u0131 ve Refresh Token Kullan\u0131m\u0131(JWT)<\/a><\/p>\n<p>Tasarlayaca\u011f\u0131n\u0131z context nesnesi \u00fczerinden olu\u015fturdu\u011fumuz &#8216;User&#8217; entity&#8217;sini DbSet olarak belirtiniz ve bu i\u015flem neticesinde gerekli migration i\u015flemlerini ve migrate etmeyi ger\u00e7ekle\u015ftiriniz. Konuyu fazla da\u011f\u0131tmamak ad\u0131na bu k\u0131s\u0131mlar\u0131n icra edildi\u011fini varsay\u0131yorum. <span style=\"font-size:10px;\">Bknz : <a href=\"https:\/\/www.gencayyildiz.com\/blog\/asp-net-core-2-mvcde-migrations-ile-veritabani-islemleri\/\" rel=\"noopener noreferrer\" target=\"_blank\">Asp.NET Core 2 MVC\u2019de Migrations \u0130le Veritaban\u0131 \u0130\u015flemleri<\/a><\/span>\n<\/li>\n<li><strong>Ad\u0131m 2<\/strong><br \/>\n&#8216;Startup.cs&#8217; dosyas\u0131nda JWT konfig\u00fcrasyonunu ger\u00e7ekle\u015ftirelim. Bunun i\u00e7in a\u015fa\u011f\u0131daki gibi &#8216;Authentication&#8217; ve &#8216;JwtBearer&#8217; servisini uygulamaya dahil edelim.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n       services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)\r\n                .AddJwtBearer(options =&gt;\r\n                {\r\n                    options.TokenValidationParameters = 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                    };\r\n                });\r\n<\/pre>\n<p>Burada JWT konfig\u00fcrasyonu i\u00e7in uygulamaya <a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.AspNetCore.Authentication.JwtBearer\" rel=\"noopener noreferrer\" target=\"_blank\">Microsoft.AspNetCore.Authentication.JwtBearer<\/a> k\u00fct\u00fcphanesinin y\u00fcklenmesi gerekmektedir. Tan\u0131mlama s\u00fcrecinde propertylerin ne oldu\u011funa dair detayl\u0131 bilgi i\u00e7in <a href=\"https:\/\/www.gencayyildiz.com\/blog\/asp-net-core-3-1-ile-token-bazli-kimlik-dogrulamasi-ve-refresh-token-kullanimijwt\/\" rel=\"noopener noreferrer\" target=\"_blank\">Asp.NET Core 3.1 ile Token Bazl\u0131 Kimlik Do\u011frulamas\u0131 ve Refresh Token Kullan\u0131m\u0131(JWT)<\/a> adresindeki makaleye g\u00f6z atabilirsiniz. Ayr\u0131ca &#8216;appsettings.json&#8217; dosyas\u0131ndaki statik de\u011ferler i\u00e7in a\u015fa\u011f\u0131daki gibi tan\u0131mlama yapabilirsiniz.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n{\r\n  .\r\n  .\r\n  .\r\n  &quot;JWT&quot;: {\r\n    &quot;Audience&quot;: &quot;localhost&quot;,\r\n    &quot;Issuer&quot;: &quot;www.gencayyildiz.com&quot;,\r\n    &quot;SecurityKey&quot;: &quot;sebepsiz bo\u015f yere ayr\u0131lacaksann. ... .&quot;\r\n  }\r\n}\r\n<\/pre>\n<\/li>\n<li><strong>Ad\u0131m 3<\/strong><br \/>\nWeb taray\u0131c\u0131s\u0131 \u00fczerinden client&#8217;lar\u0131n eri\u015fimini sa\u011fl\u0131kl\u0131 bir \u015fekilde sa\u011flayabilmek i\u00e7in &#8216;Startup.cs&#8217; \u00fczerinden CORS politikas\u0131n\u0131 ayarlayal\u0131m. <span style=\"font-size:10px\">Tabi ki de client&#8217;lar sadece web tabanl\u0131 olmak zorunda de\u011fil. Console, Windows, Mobile, Ak\u0131ll\u0131 \u00fct\u00fc vs. olabilir \ud83d\ude42 <\/span><\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n        public void ConfigureServices(IServiceCollection services)\r\n        {\r\n            .\r\n            .\r\n            .\r\n            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)\r\n            .AddJwtBearer(options =&gt;\r\n             {\r\n                 options.TokenValidationParameters = 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                 };\r\n             });\r\n            .\r\n            .\r\n            .\r\n        }\r\n<\/pre>\n<p>&#8216;UseCors&#8217; middleware&#8217;ini \u00e7a\u011f\u0131ral\u0131m.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n            .\r\n            .\r\n            .\r\n            app.UseCors();\r\n            .\r\n            .\r\n            .\r\n<\/pre>\n<\/li>\n<li><strong>Ad\u0131m 4<\/strong><br \/>\nUygulamada authentication ve authorization i\u015flevlerini kullanabilmek i\u00e7in &#8216;UseAuthentication&#8217; ve &#8216;UseAuthorization&#8217; middleware&#8217;lerini \u00e7a\u011f\u0131ral\u0131m.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\r\n        {\r\n            .\r\n            .\r\n            .\r\n            app.UseRouting();\r\n            app.UseCors();\r\n\r\n            app.UseAuthentication();\r\n            app.UseAuthorization();\r\n\r\n            app.UseEndpoints...\r\n            .\r\n            .\r\n            .\r\n        }\r\n<\/pre>\n<p>Bu middleware&#8217;ler sayesinde tasarlad\u0131\u011f\u0131m\u0131z uygulamaya t\u00fcm kullan\u0131c\u0131 denetimi ve rol y\u00f6netimi i\u015flevleri kazand\u0131r\u0131lmaktad\u0131r.\n<\/li>\n<li><strong>Ad\u0131m 5<\/strong><br \/>\n\u00dcretilecek token ve refresh token de\u011ferlerini ta\u015f\u0131yacak model&#8217;i tasarlayal\u0131m.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class Token\r\n    {\r\n        public string AccessToken { get; set; }\r\n        public DateTime Expiration { get; set; }\r\n        public string RefreshToken { get; set; }\r\n    }\r\n<\/pre>\n<\/li>\n<li><strong>Ad\u0131m 6<\/strong><br \/>\nT\u00fcm bu in\u015falardan sonra art\u0131k token \u00fcretiminden sorumlu Token Handler s\u0131n\u0131f\u0131n\u0131 olu\u015fturabiliriz.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class TokenHandler\r\n    {\r\n        readonly IConfiguration _configuration;\r\n        public TokenHandler(IConfiguration configuration)\r\n        {\r\n            _configuration = configuration;\r\n        }\r\n        public Token CreateAccessToken(int duration)\r\n        {\r\n            Token tokenInstance = new Token();\r\n            SymmetricSecurityKey securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration&#x5B;&quot;JWT:SecurityKey&quot;]));\r\n            SigningCredentials signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);\r\n            tokenInstance.Expiration = DateTime.Now.AddMinutes(duration);\r\n            JwtSecurityToken securityToken = new JwtSecurityToken\r\n                (\r\n                issuer: _configuration&#x5B;&quot;JWT:Issuer&quot;],\r\n                audience: _configuration&#x5B;&quot;JWT:Audience&quot;],\r\n                expires: tokenInstance.Expiration,\r\n                notBefore: DateTime.Now,\r\n                signingCredentials: signingCredentials\r\n            );\r\n            JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();\r\n            tokenInstance.AccessToken = tokenHandler.WriteToken(securityToken);\r\n            tokenInstance.RefreshToken = CreateRefreshToken();\r\n            return tokenInstance;\r\n        }\r\n        public string CreateRefreshToken()\r\n        {\r\n            byte&#x5B;] number = new byte&#x5B;32];\r\n            using RandomNumberGenerator random = RandomNumberGenerator.Create();\r\n            random.GetBytes(number);\r\n            return Convert.ToBase64String(number);\r\n        }\r\n    }\r\n<\/pre>\n<\/li>\n<\/ul>\n<p>Evet, bu ad\u0131mlar neticesinde uygulamaya JWT entegrasyonunu ba\u015far\u0131yla sa\u011flam\u0131\u015f bulunmaktay\u0131z. \u015eimdi s\u0131ra SignalR mimarisi ile uygulamay\u0131 geli\u015ftirmeye geldi.<\/p>\n<h3 style=\"color: #e83e8c;\">SignalR Uygulamas\u0131n\u0131n Geli\u015ftirilmesi<\/h3>\n<p>SignalR mimarisi, server ve client olmak \u00fczere ikiye ayr\u0131ld\u0131\u011f\u0131ndan dolay\u0131 bizler \u00f6ncelikle server k\u0131sm\u0131n\u0131 in\u015fa edecek ve ard\u0131ndan client olarak web uygulamas\u0131 geli\u015ftirece\u011fiz. S\u00fcre\u00e7te programatik davran\u0131\u015f\u0131 tercih edece\u011fimizden dolay\u0131, Hub&#8217;lar\u0131 <a href=\"https:\/\/www.gencayyildiz.com\/blog\/asp-net-core-signalr-serisi-9-strongly-typed-hubs\/\" rel=\"noopener noreferrer\" target=\"_blank\">Strongly Typed Hubs<\/a> \u00f6zelli\u011fini kullanarak geli\u015ftirmeye \u00f6zen g\u00f6sterece\u011fiz.<\/p>\n<p><strong>SignalR Server Side<\/strong><br \/>\n\u0130lk olarak kullan\u0131c\u0131 kay\u0131t ve giri\u015f i\u015flemlerinin sorumlulu\u011funu \u00fcstlenen hub&#8217;u geli\u015ftirelim. Bunun i\u00e7in \u00f6ncelikle &#8216;ILoginHub&#8217; aray\u00fcz\u00fcn\u00fc, ard\u0131ndan &#8216;LoginHub&#8217; s\u0131n\u0131f\u0131n\u0131 a\u015fa\u011f\u0131daki gibi in\u015fa edelim.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public interface ILoginHub\r\n    {\r\n        Task Login(Token token);\r\n        Task Create(bool result);\r\n    }\r\n<\/pre>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class LoginHub : Hub&lt;ILoginHub&gt;\r\n    {\r\n        readonly IConfiguration _configuration;\r\n        readonly SignalRExampleContext _context;\r\n        public LoginHub(IConfiguration configuration, SignalRExampleContext context)\r\n        {\r\n            _configuration = configuration;\r\n            _context = context;\r\n        }\r\n        public async Task Create(string userName, string password)\r\n        {\r\n            await _context.Users.AddAsync(new User\r\n            {\r\n                Password = password,\r\n                Username = userName\r\n            });\r\n\r\n            await Clients.Caller.Create(await _context.SaveChangesAsync() &gt; 0);\r\n        }\r\n        public async Task Login(string userName, string password)\r\n        {\r\n            User user = await _context.Users.FirstOrDefaultAsync(u =&gt; u.Username == userName &amp;&amp; u.Password == password);\r\n            Token token = null;\r\n            if (user != null)\r\n            {\r\n                TokenHandler tokenHandler = new TokenHandler(_configuration);\r\n                token = tokenHandler.CreateAccessToken(5);\r\n                user.RefreshToken = token.RefreshToken;\r\n                user.RefreshTokenEndDate = token.Expiration.AddMinutes(3);\r\n                await _context.SaveChangesAsync();\r\n            }\r\n            await Clients.Caller.Login(user != null ? token : null);\r\n        }\r\n    }\r\n<\/pre>\n<p>Yukar\u0131daki kod blo\u011funu incelerseniz e\u011fer ilgili hub kullan\u0131c\u0131 kay\u0131t ve giri\u015f i\u015flemlerinin sorumlulu\u011funu \u00fcstlenmekte ve access token ile birlikte refresh token de\u011ferlerini \u00fcretmektedir. B\u00f6ylece i\u00e7eri\u011fimizin ilk paragraflar\u0131nda da de\u011finildi\u011fi \u00fczere authentication i\u015flemleri i\u00e7in hub&#8217;lar \u00fczerinden y\u00fcr\u00fct\u00fclecek \u015fekilde bir tasar\u0131m ger\u00e7ekle\u015ftirilmektedir.<\/p>\n<p>Devam\u0131nda ise mesaj iletiminden sorumlu olan &#8216;MessageHub&#8217; isimli class&#8217;\u0131da yine ayn\u0131 \u015fekilde in\u015fa edelim.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public interface IMessageHub\r\n    {\r\n        Task ReceiveMessage(string message);\r\n    }\r\n<\/pre>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    &#x5B;Authorize]\r\n    public class MessageHub : Hub&lt;IMessageHub&gt;\r\n    {\r\n        public async Task SendMessage(string message)\r\n        {\r\n            await Clients.Others.ReceiveMessage(message);\r\n        }\r\n    }\r\n<\/pre>\n<p>Burada dikkatinizi &#8216;Authorize&#8217; attribute&#8217;una \u00e7ekerim. &#8216;Authorize&#8217; attribute&#8217;u sayesinde, SignalR ile &#8216;MessageHub&#8217;a ba\u011flanabilmek i\u00e7in ge\u00e7erli bir JWT&#8217;ye ihtiya\u00e7 duyulmakta ve b\u00f6ylece kullan\u0131c\u0131 denetimi sa\u011flanm\u0131\u015f olmaktad\u0131r. Makalenin ilerleyen sat\u0131rlar\u0131nda rol y\u00f6netimininde nas\u0131l ger\u00e7ekle\u015ftirilebilece\u011fi de ele al\u0131nacakt\u0131r.<\/p>\n<p>Server taraf\u0131nda son olarak; SignalR servisiyle birlikte, geli\u015ftirilen bu hub&#8217;lar\u0131n endpointlerini a\u015fa\u011f\u0131daki gibi tan\u0131mlayal\u0131m.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class Startup\r\n    {\r\n        public void ConfigureServices(IServiceCollection services)\r\n        {\r\n            .\r\n            .\r\n            .\r\n            services.AddSignalR();\r\n        }\r\n\r\n        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\r\n        {\r\n            .\r\n            .\r\n            .\r\n            app.UseEndpoints(endpoints =&gt;\r\n            {\r\n                endpoints.MapHub&lt;LoginHub&gt;(&quot;\/login&quot;);\r\n                endpoints.MapHub&lt;MessageHub&gt;(&quot;\/message&quot;);\r\n            });\r\n        }\r\n    }\r\n<\/pre>\n<p><strong>SignalR Client Side<\/strong><br \/>\nYap\u0131sal olarak; kullan\u0131c\u0131 kay\u0131t, giri\u015f ve chat olmak \u00fczere \u00fc\u00e7 a\u015famal\u0131 olacak \u015fekilde son kullan\u0131c\u0131ya t\u00fcm detaylar\u0131yla hitap edecek \u00f6zellikte bir client \u00e7al\u0131\u015fmas\u0131 ger\u00e7ekle\u015ftirece\u011fiz. \u0130lk olarak kullan\u0131c\u0131 kay\u0131t sayfas\u0131n\u0131 geli\u015ftirerek ba\u015flayal\u0131m.<br \/>\n<u>Create.html;<\/u><\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n&lt;!DOCTYPE html&gt;\r\n&lt;html lang=&quot;en&quot;&gt;\r\n&lt;head&gt;\r\n    &lt;script src=&quot;signalr.min.js&quot;&gt;&lt;\/script&gt;\r\n    &lt;script src=&quot;jquery.min.js&quot;&gt;&lt;\/script&gt;\r\n    &lt;script src=&quot;bootstrap.min.js&quot;&gt;&lt;\/script&gt;\r\n    &lt;link rel=&quot;stylesheet&quot; href=&quot;bootstrap.min.css&quot;&gt;\r\n    &lt;script&gt;\r\n        $(document).ready(() =&gt; {\r\n\r\n            const login = new signalR.HubConnectionBuilder()\r\n                .withUrl(&quot;https:\/\/localhost:5001\/login&quot;)\r\n                .build();\r\n\r\n            login.start();\r\n\r\n            $(&quot;#btnCreateUser&quot;).click(() =&gt; login.invoke(&quot;Create&quot;, $(&quot;#txtUsername&quot;).val(), $(&quot;#txtPassword&quot;).val()));\r\n\r\n            login.on(&quot;Create&quot;, result =&gt; {\r\n                if (result)\r\n                    alert(&quot;Kay\u0131t i\u015flemi ba\u015far\u0131yla ger\u00e7ekle\u015ftirildi.&quot;)\r\n                else\r\n                    alert(&quot;Kay\u0131t ger\u00e7ekle\u015ftirilirken beklenmeyen bir hatayla kar\u015f\u0131la\u015f\u0131ld\u0131.&quot;)\r\n            });\r\n        });\r\n    &lt;\/script&gt;\r\n&lt;\/head&gt;\r\n&lt;body&gt;\r\n    &lt;ul class=&quot;nav&quot;&gt;\r\n        &lt;li class=&quot;nav-item&quot;&gt;\r\n            &lt;a class=&quot;nav-link active&quot; href=&quot;create.html&quot;&gt;Create User&lt;\/a&gt;\r\n        &lt;\/li&gt;\r\n        &lt;li class=&quot;nav-item&quot;&gt;\r\n            &lt;a class=&quot;nav-link&quot; href=&quot;login.html&quot;&gt;Login&lt;\/a&gt;\r\n        &lt;\/li&gt;\r\n        &lt;li class=&quot;nav-item&quot;&gt;\r\n            &lt;a class=&quot;nav-link&quot; href=&quot;chatroom.html&quot;&gt;Chat Room&lt;\/a&gt;\r\n        &lt;\/li&gt;\r\n    &lt;\/ul&gt;\r\n    &lt;div class=&quot;row&quot;&gt;\r\n        &lt;div class=&quot;col-md-3&quot;&gt;&lt;\/div&gt;\r\n        &lt;div class=&quot;col-md-6&quot;&gt;\r\n            &lt;h2&gt;Create User&lt;\/h2&gt;\r\n            &lt;div class=&quot;form-group&quot;&gt;\r\n                &lt;label&gt;User Name&lt;\/label&gt;\r\n                &lt;input type=&quot;text&quot; class=&quot;form-control&quot; id=&quot;txtUsername&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; class=&quot;form-control&quot; id=&quot;txtPassword&quot;&gt;\r\n            &lt;\/div&gt;\r\n            &lt;button type=&quot;submit&quot; class=&quot;btn btn-primary&quot; id=&quot;btnCreateUser&quot;&gt;Create User&lt;\/button&gt;\r\n        &lt;\/div&gt;\r\n        &lt;div class=&quot;col-md-3&quot;&gt;&lt;\/div&gt;\r\n    &lt;\/div&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/pre>\n<p>Kaynak kodu incelerseniz e\u011fer &#8216;\/login&#8217; hub&#8217;\u0131na ba\u011flan\u0131lmakta ve ilgili hub \u00fczerinden a\u015fa\u011f\u0131daki ekran g\u00f6r\u00fcnt\u00fcs\u00fcnde oldu\u011fu gibi kullan\u0131c\u0131 kayd\u0131 ger\u00e7ekle\u015ftirilmektedir.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/09\/Asp.NET-Core-\u2013-SignalR-Serisi-10-Kimlik-DogrulamaAuthentication-ve-YetkilendirmeAuthorization.gif\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/09\/Asp.NET-Core-\u2013-SignalR-Serisi-10-Kimlik-DogrulamaAuthentication-ve-YetkilendirmeAuthorization.gif\" alt=\"Asp.NET Core \u2013 SignalR Serisi #10 - Kimlik Do\u011frulama(Authentication) ve Yetkilendirme(Authorization)\" width=\"800\" height=\"459\" class=\"aligncenter size-full wp-image-18028\" \/><\/a><br \/>\nVeritaban\u0131nada g\u00f6z at\u0131ld\u0131\u011f\u0131nda ise,<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/09\/Asp.NET-Core-\u2013-SignalR-Serisi-10-Kimlik-DogrulamaAuthentication-ve-YetkilendirmeAuthorization.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/09\/Asp.NET-Core-\u2013-SignalR-Serisi-10-Kimlik-DogrulamaAuthentication-ve-YetkilendirmeAuthorization.jpg\" alt=\"Asp.NET Core \u2013 SignalR Serisi #10 - Kimlik Do\u011frulama(Authentication) ve Yetkilendirme(Authorization)\" width=\"502\" height=\"62\" class=\"aligncenter size-full wp-image-18030\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/09\/Asp.NET-Core-\u2013-SignalR-Serisi-10-Kimlik-DogrulamaAuthentication-ve-YetkilendirmeAuthorization.jpg 502w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/09\/Asp.NET-Core-\u2013-SignalR-Serisi-10-Kimlik-DogrulamaAuthentication-ve-YetkilendirmeAuthorization-300x37.jpg 300w\" sizes=\"auto, (max-width: 502px) 100vw, 502px\" \/><\/a><br \/>\nkayd\u0131n ba\u015far\u0131yla ger\u00e7ekle\u015ftirildi\u011fini g\u00f6receksiniz.<\/p>\n<p>S\u0131ra kullan\u0131c\u0131 giri\u015f sayfas\u0131n\u0131 olu\u015fturmaya geldi.<br \/>\n<u>Login.html;<\/u><\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n&lt;!DOCTYPE html&gt;\r\n&lt;html lang=&quot;en&quot;&gt;\r\n&lt;head&gt;\r\n   &lt;script src=&quot;signalr.min.js&quot;&gt;&lt;\/script&gt;\r\n   &lt;script src=&quot;jquery.min.js&quot;&gt;&lt;\/script&gt;\r\n   &lt;script src=&quot;bootstrap.min.js&quot;&gt;&lt;\/script&gt;\r\n   &lt;link rel=&quot;stylesheet&quot; href=&quot;bootstrap.min.css&quot;&gt;\r\n   &lt;script&gt;\r\n      $(document).ready(() =&gt; {\r\n\r\n         const login = new signalR.HubConnectionBuilder()\r\n            .withUrl(&quot;https:\/\/localhost:5001\/login&quot;)\r\n            .build();\r\n\r\n         login.start();\r\n\r\n         $(&quot;#btnLogin&quot;).click(() =&gt; login.invoke(&quot;Login&quot;, $(&quot;#txtUsername&quot;).val(), $(&quot;#txtPassword&quot;).val()));\r\n\r\n         login.on(&quot;Login&quot;, token =&gt; {\r\n            if (token) {\r\n               localStorage.setItem(&quot;accessToken&quot;, token.accessToken);\r\n               localStorage.setItem(&quot;refreshToken&quot;, token.refreshToken);\r\n               alert(&quot;Giri\u015f ba\u015far\u0131l\u0131.&quot;);\r\n            } else\r\n               alert(&quot;L\u00fctfen kullan\u0131c\u0131 ad\u0131 ve \u015fifrenizi kontrol ediniz.&quot;);\r\n         });\r\n      });\r\n   &lt;\/script&gt;\r\n&lt;\/head&gt;\r\n&lt;body&gt;\r\n   &lt;ul class=&quot;nav&quot;&gt;\r\n      &lt;li class=&quot;nav-item&quot;&gt;\r\n         &lt;a class=&quot;nav-link active&quot; href=&quot;create.html&quot;&gt;Create User&lt;\/a&gt;\r\n      &lt;\/li&gt;\r\n      &lt;li class=&quot;nav-item&quot;&gt;\r\n         &lt;a class=&quot;nav-link&quot; href=&quot;login.html&quot;&gt;Login&lt;\/a&gt;\r\n      &lt;\/li&gt;\r\n      &lt;li class=&quot;nav-item&quot;&gt;\r\n         &lt;a class=&quot;nav-link&quot; href=&quot;chatroom.html&quot;&gt;Chat Room&lt;\/a&gt;\r\n      &lt;\/li&gt;\r\n   &lt;\/ul&gt;\r\n   &lt;div class=&quot;row&quot;&gt;\r\n      &lt;div class=&quot;col-md-3&quot;&gt;&lt;\/div&gt;\r\n      &lt;div class=&quot;col-md-6&quot;&gt;\r\n         &lt;h2&gt;Login&lt;\/h2&gt;\r\n         &lt;div class=&quot;form-group&quot;&gt;\r\n            &lt;label&gt;User Name&lt;\/label&gt;\r\n            &lt;input type=&quot;text&quot; class=&quot;form-control&quot; id=&quot;txtUsername&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; class=&quot;form-control&quot; id=&quot;txtPassword&quot;&gt;\r\n         &lt;\/div&gt;\r\n         &lt;button type=&quot;submit&quot; class=&quot;btn btn-primary&quot; id=&quot;btnLogin&quot;&gt;Login&lt;\/button&gt;\r\n      &lt;\/div&gt;\r\n      &lt;div class=&quot;col-md-3&quot;&gt;&lt;\/div&gt;\r\n   &lt;\/div&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/pre>\n<p>Burada ise kullan\u0131c\u0131 ad\u0131 ve \u015fifre ile bulunulan giri\u015f talebine, server&#8217;da &#8216;\/login&#8217; hub&#8217;\u0131 taraf\u0131ndan kar\u015f\u0131l\u0131k verilmekte ve daha \u00f6nce olu\u015fturdu\u011fumuz &#8216;TokenHandler&#8217; s\u0131n\u0131f\u0131 ile acess token ve refresh token \u00fcretilmektedir. \u00dcretilen token de\u011ferleri local storage \u00fczerinde uygun anahtarlar e\u015fli\u011finde depolanmaktad\u0131r.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/10\/Asp.NET-Core-\u2013-SignalR-Serisi-10-Kimlik-DogrulamaAuthentication-ve-YetkilendirmeAuthorization.gif\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/10\/Asp.NET-Core-\u2013-SignalR-Serisi-10-Kimlik-DogrulamaAuthentication-ve-YetkilendirmeAuthorization.gif\" alt=\"Asp.NET Core \u2013 SignalR Serisi #10 - Kimlik Do\u011frulama(Authentication) ve Yetkilendirme(Authorization)\" width=\"716\" height=\"416\" class=\"aligncenter size-full wp-image-18036\" \/><\/a><br \/>\nLocal storage&#8217;a g\u00f6z at\u0131ld\u0131\u011f\u0131nda ise,<\/p>\n<p><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/10\/Asp.NET-Core-\u2013-SignalR-Serisi-10-Kimlik-DogrulamaAuthentication-ve-YetkilendirmeAuthorization.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/10\/Asp.NET-Core-\u2013-SignalR-Serisi-10-Kimlik-DogrulamaAuthentication-ve-YetkilendirmeAuthorization.jpg\" alt=\"Asp.NET Core \u2013 SignalR Serisi #10 - Kimlik Do\u011frulama(Authentication) ve Yetkilendirme(Authorization)\" width=\"796\" height=\"340\" class=\"aligncenter size-full wp-image-18037\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/10\/Asp.NET-Core-\u2013-SignalR-Serisi-10-Kimlik-DogrulamaAuthentication-ve-YetkilendirmeAuthorization.jpg 796w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/10\/Asp.NET-Core-\u2013-SignalR-Serisi-10-Kimlik-DogrulamaAuthentication-ve-YetkilendirmeAuthorization-300x128.jpg 300w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/10\/Asp.NET-Core-\u2013-SignalR-Serisi-10-Kimlik-DogrulamaAuthentication-ve-YetkilendirmeAuthorization-768x328.jpg 768w\" sizes=\"auto, (max-width: 796px) 100vw, 796px\" \/><\/a><br \/>\ntoken de\u011ferlerinin kaydedildi\u011fini g\u00f6receksiniz.<\/p>\n<p>Son olarak kullan\u0131c\u0131lar aras\u0131nda mesajla\u015fman\u0131n ger\u00e7ekle\u015ftirilebilmesi i\u00e7in s\u0131ra chat sayfas\u0131n\u0131n tasarlanmas\u0131na geldi.<br \/>\n<u>Chatroom.html;<\/u><\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n&lt;!DOCTYPE html&gt;\r\n&lt;html lang=&quot;en&quot;&gt;\r\n&lt;head&gt;\r\n   &lt;script src=&quot;signalr.min.js&quot;&gt;&lt;\/script&gt;\r\n   &lt;script src=&quot;jquery.min.js&quot;&gt;&lt;\/script&gt;\r\n   &lt;link rel=&quot;stylesheet&quot; href=&quot;bootstrap.min.css&quot;&gt;\r\n   &lt;script src=&quot;https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/popper.js\/1.16.0\/umd\/popper.min.js&quot;&gt;&lt;\/script&gt;\r\n   &lt;script src=&quot;bootstrap.min.js&quot;&gt;&lt;\/script&gt;\r\n   &lt;script&gt;\r\n      function connectionMessageWrite(state, message) {\r\n         $(&quot;#connectionMessage&quot;).find(&quot;div&quot;)&#x5B;1].removeAttribute(&quot;class&quot;);\r\n         $(&quot;#connectionMessage&quot;).find(&quot;div&quot;)&#x5B;1].setAttribute(&quot;class&quot;, &quot;alert alert-&quot; + state);\r\n         $(&quot;#connectionMessage&quot;).find(&quot;div&quot;)&#x5B;1].innerHTML = message;\r\n         $(&quot;#connectionMessage&quot;).show(2000);\r\n      }\r\n      $(document).ready(() =&gt; {\r\n         $(&quot;#logOut&quot;).click(() =&gt; {\r\n            localStorage.removeItem(&quot;accessToken&quot;);\r\n            localStorage.removeItem(&quot;refreshToken&quot;);\r\n         });\r\n\r\n         $(&quot;.toast&quot;).toast('show');\r\n         const message = new signalR.HubConnectionBuilder()\r\n            .withUrl(&quot;https:\/\/localhost:5001\/message&quot;,\r\n               { accessTokenFactory: () =&gt; localStorage.getItem(&quot;accessToken&quot;) != null ? localStorage.getItem(&quot;accessToken&quot;) : &quot;&quot; })\r\n            .withAutomaticReconnect(&#x5B;10])\r\n            .build();\r\n\r\n         message.start()\r\n            .then(() =&gt; connectionMessageWrite(&quot;success&quot;, &quot;Ba\u011flant\u0131 ba\u015far\u0131l\u0131.&quot;))\r\n            .catch(err =&gt; connectionMessageWrite(&quot;danger&quot;, &quot;Ba\u011flant\u0131 ba\u015far\u0131s\u0131z! L\u00fctfen oturum a\u00e7\u0131n\u0131z.&quot;));\r\n         message.onclose((err) =&gt; $(&quot;#connectionMessage&quot;).hide(2000, () =&gt; {\r\n            connectionMessageWrite(&quot;warning&quot;, &quot;Ba\u011flant\u0131 koptu!&quot;);\r\n         }));\r\n\r\n         $(&quot;#btnSendMessage&quot;).click(() =&gt; {\r\n            message.invoke(&quot;SendMessage&quot;, $(&quot;#txtMessage&quot;).val());\r\n            $(&quot;#txtMessage&quot;).val(&quot;&quot;);\r\n         });\r\n         let messageCount = 0;\r\n         message.on(&quot;ReceiveMessage&quot;, message =&gt; {\r\n\r\n            let object = '&lt;div style=&quot;margin-top: 10px;&quot; class=&quot;toast&quot; id=&quot;toast-' + ++messageCount + '&quot; role=&quot;alert&quot; aria-live=&quot;assertive&quot; aria-atomic=&quot;true&quot; data-delay=&quot;5000&quot;&gt;';\r\n            object += ' &lt;div class=&quot;toast-header&quot;&gt;';\r\n            object += '    &lt;img src=&quot;messageicon.png&quot; width=&quot;20px&quot; class=&quot;rounded mr-2&quot; alt=&quot;...&quot;&gt;';\r\n            object += '    &lt;strong class=&quot;mr-auto&quot;&gt;Client&lt;\/strong&gt;';\r\n            object += '    &lt;small class=&quot;text-muted&quot;&gt;Biraz \u00f6nce&lt;\/small&gt;';\r\n            object += '    &lt;button type=&quot;button&quot; class=&quot;ml-2 mb-1 close&quot; data-dismiss=&quot;toast&quot; aria-label=&quot;Close&quot;&gt;';\r\n            object += '       &lt;span aria-hidden=&quot;true&quot;&gt;&amp;times;&lt;\/span&gt;';\r\n            object += '    &lt;\/button&gt;'\r\n            object += ' &lt;\/div&gt;'\r\n            object += ' &lt;div class=&quot;toast-body&quot;&gt;';\r\n            object += message;\r\n            object += ' &lt;\/div&gt;';\r\n            object += '&lt;\/div&gt;';\r\n            $(&quot;#divMessage&quot;).append(object);\r\n            $(&quot;#toast-&quot; + messageCount).toast('show');\r\n         });\r\n\r\n      });\r\n   &lt;\/script&gt;\r\n&lt;\/head&gt;\r\n&lt;body&gt;\r\n   &lt;ul class=&quot;nav&quot;&gt;\r\n      &lt;li class=&quot;nav-item&quot;&gt;\r\n         &lt;a class=&quot;nav-link active&quot; href=&quot;create.html&quot;&gt;Create User&lt;\/a&gt;\r\n      &lt;\/li&gt;\r\n      &lt;li class=&quot;nav-item&quot;&gt;\r\n         &lt;a class=&quot;nav-link&quot; href=&quot;login.html&quot;&gt;Login&lt;\/a&gt;\r\n      &lt;\/li&gt;\r\n      &lt;li class=&quot;nav-item&quot;&gt;\r\n         &lt;a class=&quot;nav-link&quot; href=&quot;chatroom.html&quot;&gt;Chat Room&lt;\/a&gt;\r\n      &lt;\/li&gt;\r\n      &lt;li class=&quot;nav-item&quot;&gt;\r\n         &lt;a class=&quot;nav-link&quot; style=&quot;cursor: pointer;&quot; id=&quot;logOut&quot;&gt;Logout&lt;\/a&gt;\r\n      &lt;\/li&gt;\r\n   &lt;\/ul&gt;\r\n   &lt;div class=&quot;row&quot; id=&quot;connectionMessage&quot; style=&quot;display: none;&quot;&gt;\r\n      &lt;div class=&quot;col-md-3&quot;&gt;\r\n      &lt;\/div&gt;\r\n      &lt;div class=&quot;col-md-6&quot;&gt;\r\n         &lt;div role=&quot;alert&quot;&gt;\r\n\r\n         &lt;\/div&gt;\r\n      &lt;\/div&gt;\r\n      &lt;div class=&quot;col-md-3&quot;&gt;\r\n      &lt;\/div&gt;\r\n   &lt;\/div&gt;\r\n   &lt;div class=&quot;row&quot;&gt;\r\n      &lt;div class=&quot;col-md-3&quot;&gt;&lt;\/div&gt;\r\n      &lt;div class=&quot;col-md-6&quot;&gt;\r\n         &lt;h2&gt;Chat Room&lt;\/h2&gt;\r\n         &lt;div class=&quot;form-group&quot;&gt;\r\n            &lt;label&gt;Message&lt;\/label&gt;\r\n            &lt;textarea class=&quot;form-control&quot; id=&quot;txtMessage&quot; placeholder=&quot;Mesaj\u0131n\u0131z\u0131 giriniz.&quot; rows=&quot;3&quot;&gt;&lt;\/textarea&gt;\r\n         &lt;\/div&gt;\r\n         &lt;button type=&quot;submit&quot; class=&quot;btn btn-primary&quot; id=&quot;btnSendMessage&quot;&gt;Send Message&lt;\/button&gt;\r\n      &lt;\/div&gt;\r\n      &lt;div class=&quot;col-md-3&quot;&gt;&lt;\/div&gt;\r\n      &lt;div class=&quot;col-md-3&quot;&gt;&lt;\/div&gt;\r\n      &lt;div class=&quot;col-md-6&quot; id=&quot;divMessage&quot;&gt;\r\n\r\n      &lt;\/div&gt;\r\n      &lt;div class=&quot;col-md-3&quot;&gt;&lt;\/div&gt;\r\n   &lt;\/div&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/pre>\n<p>Yukar\u0131daki kod blo\u011funu incelerseniz e\u011fer; &#8216;Authorize&#8217; attribute&#8217;u ile i\u015faretlenmi\u015f olan &#8216;\/message&#8217; hub&#8217;\u0131na client&#8217;tan eri\u015fim sa\u011flayabilmek i\u00e7in <em><strong>24.<\/strong><\/em> sat\u0131rda bulunan &#8216;withUrl&#8217; metodunun ikinci parametresine, i\u00e7erisinde &#8216;accessTokenFactory&#8217; alan\u0131n\u0131 bar\u0131nd\u0131ran bir object verilmesi ve bu alana server&#8217;dan gelen token&#8217;\u0131n set edilmesi yeterli olacakt\u0131r. B\u00f6ylece SignalR mimarisi, bahsedilen konfig\u00fcrasyon sayesinde client&#8217;tan gelecek olan token de\u011ferini elde edip do\u011frulayacak ve kullan\u0131c\u0131n\u0131n ba\u011flant\u0131 kurmas\u0131n\u0131 sa\u011flayacakt\u0131r. Tabi ki de ge\u00e7ersiz bir token de\u011ferinin kullan\u0131lmas\u0131 yahut token&#8217;\u0131n s\u00fcresinin dolmas\u0131 neticesinde hub&#8217;a ba\u011flant\u0131 sa\u011flanamayacak ve b\u00f6ylece denetim sa\u011flanm\u0131\u015f olacakt\u0131r.<\/p>\n<p>\u0130lgili sayfan\u0131n i\u015flevsel a\u00e7\u0131dan ekran g\u00f6r\u00fcnt\u00fcs\u00fc a\u015fa\u011f\u0131daki gibidir;<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/10\/Asp.NET-Core-\u2013-SignalR-Serisi-10-Kimlik-DogrulamaAuthentication-ve-YetkilendirmeAuthorization-1.gif\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/10\/Asp.NET-Core-\u2013-SignalR-Serisi-10-Kimlik-DogrulamaAuthentication-ve-YetkilendirmeAuthorization-1.gif\" alt=\"Asp.NET Core \u2013 SignalR Serisi #10 - Kimlik Do\u011frulama(Authentication) ve Yetkilendirme(Authorization)\" width=\"800\" height=\"772\" class=\"aligncenter size-full wp-image-18040\" \/><\/a><br \/>\nToken ald\u0131ktan sonra client&#8217;lar aras\u0131 mesaj iletimi ise a\u015fa\u011f\u0131daki gibidir;<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/10\/Asp.NET-Core-\u2013-SignalR-Serisi-10-Kimlik-DogrulamaAuthentication-ve-YetkilendirmeAuthorization-2.gif\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/10\/Asp.NET-Core-\u2013-SignalR-Serisi-10-Kimlik-DogrulamaAuthentication-ve-YetkilendirmeAuthorization-2.gif\" alt=\"Asp.NET Core \u2013 SignalR Serisi #10 - Kimlik Do\u011frulama(Authentication) ve Yetkilendirme(Authorization)\" width=\"800\" height=\"513\" class=\"aligncenter size-full wp-image-18043\" \/><\/a><\/p>\n<h3 style=\"color: #e83e8c;\">SignalR \u0130le Refresh Token Kullan\u0131m\u0131<\/h3>\n<p>SignalR ile birlikte refresh token&#8217;\u0131 kullanabilmek i\u00e7in server&#8217;\u0131n refresh token stratejisini benimsemesi gerekmektedir. Bizler bu i\u00e7eri\u011fimizin yukar\u0131daki sat\u0131rlar\u0131nda JWT mekanizmas\u0131n\u0131n in\u015fas\u0131n\u0131 ele al\u0131rken refresh token in\u015fas\u0131n\u0131 da olu\u015fturmu\u015ftuk. Lakin ekstradan refresh token \u00fczerinden giri\u015f kodunu da geli\u015ftirmemiz gerekmektedir. Bunun i\u00e7in &#8216;\/login&#8217; hub&#8217;da a\u015fa\u011f\u0131daki gibi bir geli\u015ftirme ger\u00e7ekle\u015ftirebiliriz;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class LoginHub : Hub&lt;ILoginHub&gt;\r\n    {\r\n        readonly IConfiguration _configuration;\r\n        readonly SignalRExampleContext _context;\r\n        .\r\n        .\r\n        .\r\n        public async Task RefreshTokenLogin(string refreshToken)\r\n        {\r\n            User user = await _context.Users.FirstOrDefaultAsync(x =&gt; x.RefreshToken == refreshToken);\r\n            Token token = null;\r\n            if (user != null &amp;&amp; user?.RefreshTokenEndDate &gt; DateTime.Now)\r\n            {\r\n                TokenHandler tokenHandler = new TokenHandler(_configuration);\r\n                token = tokenHandler.CreateAccessToken(1);\r\n\r\n                user.RefreshToken = token.RefreshToken;\r\n                user.RefreshTokenEndDate = token.Expiration.AddMinutes(1);\r\n                await _context.SaveChangesAsync();\r\n            }\r\n            await Clients.Caller.Login(user != null ? token : null);\r\n        }\r\n    }\r\n<\/pre>\n<p>Ard\u0131ndan client&#8217;ta a\u015fa\u011f\u0131daki gibi geli\u015ftirme yap\u0131lmas\u0131 gerekmektedir;<br \/>\n<u>Chatroom.html<\/u>;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n         .\r\n         .\r\n         .\r\n         const message = new signalR.HubConnectionBuilder()\r\n            .withUrl(&quot;https:\/\/localhost:5001\/message&quot;,\r\n               { accessTokenFactory: () =&gt; localStorage.getItem(&quot;accessToken&quot;) != null ? localStorage.getItem(&quot;accessToken&quot;) : &quot;&quot; })\r\n            .withAutomaticReconnect(&#x5B;10])\r\n            .build();\r\n\r\n         function start() {\r\n            message.start()\r\n               .then(() =&gt; connectionMessageWrite(&quot;success&quot;, &quot;Ba\u011flant\u0131 ba\u015far\u0131l\u0131.&quot;))\r\n               .catch(err =&gt; connectionMessageWrite(&quot;danger&quot;, &quot;Ba\u011flant\u0131 ba\u015far\u0131s\u0131z! L\u00fctfen oturum a\u00e7\u0131n\u0131z.&quot;));\r\n         }\r\n         start();\r\n\r\n         message.onclose(() =&gt; $(&quot;#connectionMessage&quot;).hide(2000, () =&gt; {\r\n            const login = new signalR.HubConnectionBuilder()\r\n               .withUrl(&quot;https:\/\/localhost:5001\/login&quot;)\r\n               .build();\r\n            connectionMessageWrite(&quot;warning&quot;, &quot;Ba\u011flant\u0131 koptu!&quot;);\r\n            login.start().then(() =&gt; {\r\n               login.invoke(&quot;RefreshTokenLogin&quot;, localStorage.getItem(&quot;refreshToken&quot;));\r\n               login.on(&quot;login&quot;, token =&gt; {\r\n                  localStorage.setItem(&quot;accessToken&quot;, token.accessToken);\r\n                  localStorage.setItem(&quot;refreshToken&quot;, token.refreshToken);\r\n                  message.connection.accessTokenFactory = token.accessToken;\r\n                  start();\r\n               });\r\n            });\r\n         }));\r\n         .\r\n         .\r\n         .\r\n<\/pre>\n<p>Yukar\u0131daki kod blo\u011funu incelerseniz e\u011fer &#8216;\/message&#8217; hub&#8217;\u0131na olan ba\u011flant\u0131 close oldu\u011fu zaman &#8216;onclose&#8217; fonksiyonu tetiklenmekte ve ilgili event i\u00e7erisinde &#8216;\/login&#8217; hub&#8217;\u0131na ba\u011flant\u0131 sa\u011flanarak server&#8217;da ki &#8216;RefreshTokenLogin&#8217; metoduna refresh token de\u011feri ileti olarak g\u00f6nderilmektedir. Sunucuda do\u011frulanan refresh token, kullan\u0131c\u0131ya dair yeni bir access token \u00fcretilmesini sa\u011flamakta ve bu token de\u011feri server taraf\u0131ndan tetiklenen client&#8217;ta ki &#8216;Login&#8217; fonksiyonu(<em><strong>24.<\/strong><\/em> sat\u0131r) arac\u0131l\u0131\u011f\u0131yla g\u00f6nderilmekte ve client taraf\u0131ndan kar\u015f\u0131lanmaktad\u0131r. Ard\u0131ndan client, elde edilen bu token de\u011feri ile &#8216;\/message&#8217; hub&#8217;\u0131nda ki &#8216;accessTokenFactory&#8217; de\u011ferini de\u011fi\u015ftirmekte ve tekrardan ilgili hub&#8217;a ba\u011flant\u0131y\u0131 tazelemektedir. Tabi burada <a href=\"https:\/\/www.gencayyildiz.com\/blog\/asp-net-core-signalr-serisi-5-clientda-otomatik-baglanti-konfigurasyonu-ve-durum-fonksiyonlari\/\" rel=\"noopener noreferrer\" target=\"_blank\">otomatik ba\u011flant\u0131<\/a> konfig\u00fcrasyonunun kullan\u0131ld\u0131\u011f\u0131na dikkatinizi \u00e7ekmekte fayda g\u00f6rmekteyim.<\/p>\n<p>En nihayetinde yap\u0131lan bu refresh token yap\u0131lanmas\u0131 a\u015fa\u011f\u0131daki ekran g\u00f6r\u00fcnt\u00fcs\u00fcnde oldu\u011fu gibi davran\u0131\u015f sergilemekte ve e\u015fzamanl\u0131 veri ak\u0131\u015f\u0131n\u0131 hi\u00e7bir zaman sekteye u\u011fratmayacak \u015fekilde i\u015flevselli\u011fini g\u00f6stermektedir.<br \/>\n<div id=\"attachment_18054\" style=\"width: 810px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/10\/Asp.NET-Core-\u2013-SignalR-Serisi-10-Kimlik-DogrulamaAuthentication-ve-YetkilendirmeAuthorization-3.gif\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-18054\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/10\/Asp.NET-Core-\u2013-SignalR-Serisi-10-Kimlik-DogrulamaAuthentication-ve-YetkilendirmeAuthorization-3.gif\" alt=\"Asp.NET Core \u2013 SignalR Serisi #10 - Kimlik Do\u011frulama(Authentication) ve Yetkilendirme(Authorization)\" width=\"800\" height=\"451\" class=\"size-full wp-image-18054\" \/><\/a><p id=\"caption-attachment-18054\" class=\"wp-caption-text\">\u00d6rnek ama\u00e7l\u0131 farazi bir s\u00fcreli\u011fine olu\u015fturulmu\u015f token de\u011ferinin refresh token ile kullan\u0131c\u0131 talebi olmaks\u0131z\u0131n temsili yenilenmesi&#8230;<\/p><\/div><\/p>\n<h3 style=\"color: #e83e8c;\">SignalR \u0130le Rol Y\u00f6netimi<\/h3>\n<p>SignalR ile rol y\u00f6netimi, bildi\u011finiz Asp.NET Core MVC yahut Web API ile birebir ayn\u0131 mant\u0131kta i\u015flemektedir. \u00d6rne\u011fin; nas\u0131l ki Asp.NET Core Web API&#8217;da &#8216;Authorize&#8217; olan controller&#8217;lara rol tan\u0131mlayabilmek i\u00e7in &#8216;Roles=&#8221;&#8230;&#8221;&#8216; propertysi kullan\u0131l\u0131yorsa benzer mant\u0131kla SignalR&#8217;da ki hub&#8217;lar i\u00e7inde ayn\u0131 \u00f6zelli\u011fin kullan\u0131lmas\u0131 gerekmektedir.<\/p>\n<p>S\u00f6zgelimi &#8216;\/message&#8217; hub&#8217;\u0131n\u0131 ele al\u0131rsak;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    &#x5B;Authorize(Roles = &quot;Admin&quot;)]\r\n    public class MessageHub : Hub&lt;IMessageHub&gt;\r\n    {\r\n        public async Task SendMessage(string message)\r\n        {\r\n            await Clients.Others.ReceiveMessage(message);\r\n        }\r\n    }\r\n<\/pre>\n<p>\u015feklinde tan\u0131mlanmas\u0131, bu hub&#8217;a &#8216;Admin&#8217; rol\u00fcne sahip olan yetkili ki\u015filerin eri\u015febilece\u011fini ifade etmektedir.<\/p>\n<p><strong>Peki kullan\u0131c\u0131n\u0131n \u00fcstlenece\u011fi rol\u00fc nereden belirleyece\u011fiz?<\/strong><br \/>\nAsl\u0131nda bu sorununda cevab\u0131 yine bilinen klasik rol tan\u0131mlamas\u0131nda yatmaktad\u0131r. Yani claim yap\u0131lanmas\u0131nda. Kullan\u0131c\u0131 giri\u015f talebinde bulunup, do\u011fruland\u0131\u011f\u0131 vakit, token de\u011ferinin \u00fcretilebilmesi i\u00e7in yukar\u0131larda olu\u015fturdu\u011fumuz &#8216;TokenHandler&#8217; s\u0131n\u0131f\u0131 kullan\u0131lmaktad\u0131r. Haliyle ilgili s\u0131n\u0131f i\u00e7erisinde &#8216;JwtSecurityToken&#8217; nesnesinin &#8216;claims&#8217; parametresi bu i\u015flem i\u00e7in yeterli olacakt\u0131r. \u015e\u00f6yle ki;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class TokenHandler\r\n    {\r\n        readonly IConfiguration _configuration;\r\n        .\r\n        .\r\n        .\r\n        public Token CreateAccessToken(int duration)\r\n        {\r\n            .\r\n            .\r\n            .\r\n            JwtSecurityToken securityToken = new JwtSecurityToken\r\n                (\r\n                issuer: _configuration&#x5B;&quot;JWT:Issuer&quot;],\r\n                .\r\n                .\r\n                .\r\n                claims: new List&lt;Claim&gt;\r\n                {\r\n                    new Claim(ClaimTypes.Role, &quot;Admin&quot;)\r\n                }\r\n            );\r\n            .\r\n            .\r\n            .\r\n        }\r\n        .\r\n        .\r\n        .\r\n    }\r\n<\/pre>\n<p>Yukar\u0131daki kaynak kodun <em><strong>20.<\/strong><\/em> sat\u0131r\u0131nda, \u00fcretilecek token&#8217;a &#8216;Admin&#8217; rol\u00fc eklenmekte ve ilgili token ile yap\u0131lan isteklerde &#8216;Authorize(Roles = &#8220;Admin&#8221;)&#8217; attribute&#8217;una kar\u015f\u0131l\u0131k do\u011frulama ba\u015far\u0131yla ger\u00e7ekle\u015ftirilmektedir.<\/p>\n<h3 style=\"color: #e83e8c;\">Client Web D\u0131\u015f\u0131nda Console App. yahut Windows Form Olursa?<\/h3>\n<p>Yaz\u0131 serimizin sonraki makalelerinde, SignalR ile etkile\u015fime giren client&#8217;lar\u0131n web d\u0131\u015f\u0131nda farkl\u0131 platformlardan olma durumunu ayr\u0131 bir ba\u015fl\u0131k alt\u0131nda tam teferruatl\u0131 inceleyece\u011fiz. Lakin yeri gelmi\u015fken farkl\u0131 platformlarda da authentication durumunun nas\u0131l ger\u00e7ekle\u015ftirildi\u011fine dair detaya de\u011finmekte fayda g\u00f6rmekteyim.<\/p>\n<p>E\u011fer ki client olarak web d\u0131\u015f\u0131nda bir Console Application yahut Windows Form&#8217;da \u00e7al\u0131\u015f\u0131yor ve bir yandan da authentication kullan\u0131yorsan\u0131z her ikisinde de a\u015fa\u011f\u0131daki \u00e7al\u0131\u015fmay\u0131 ger\u00e7ekle\u015ftirebilirsiniz.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class Program\r\n    {\r\n        static HubConnection connection;\r\n        async static Task Main(string&#x5B;] args)\r\n        {\r\n            connection = new HubConnectionBuilder().WithUrl(&quot;https:\/\/localhost:5001\/message&quot;,\r\n                options =&gt; options.AccessTokenProvider = () =&gt; Task.FromResult(&quot;...Token Value...&quot;)).Build();\r\n            await connection.StartAsync();\r\n            Console.WriteLine(connection.State);\r\n            connection.On&lt;string&gt;(&quot;receiveMessage&quot;, message =&gt;\r\n            {\r\n                Console.WriteLine($&quot;---&gt;{message}&quot;);\r\n            });\r\n\r\n            while (true)\r\n            {\r\n                Console.WriteLine(&quot;G\u00f6nderilecek mesaj\u0131 yaz\u0131n\u0131z.&quot;);\r\n                await connection.InvokeAsync(&quot;SendMessage&quot;, Console.ReadLine());\r\n            }\r\n        }\r\n    }\r\n<\/pre>\n<p>G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere <em><strong>7.<\/strong><\/em> sat\u0131rdaki &#8216;AccessTokenProvider&#8217; \u00f6zelli\u011fi arac\u0131l\u0131\u011f\u0131yla elde edilen token de\u011feri ba\u011flant\u0131 talebine verilerek, connection ba\u015far\u0131yla sa\u011flanabilmektedir.<\/p>\n<p>\u0130\u015fte bu kadar&#8230;<\/p>\n<p>Nihai olarak, e\u015fzamanl\u0131 uygulamalarda authentication, authorization, refresh token gibi yap\u0131land\u0131rmas\u0131 zor ve a\u011f\u0131r olan i\u015flemlerin nas\u0131l efektif bir \u015fekilde in\u015fa edildi\u011fini ad\u0131m ad\u0131m irdelemi\u015f bulunmaktay\u0131z. Umar\u0131m kalemim gam teline vurmu\u015f, m\u00fcrekkebim anla\u015f\u0131labilir olmu\u015ftur. Bu noktaya kadar sabredip okuyan, \u00f6zellikle okurken makaleye e\u015flik eden siz de\u011ferli okuyucular\u0131ma te\u015fekk\u00fcr ederim&#8230;<\/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 server ve UI uygulamalar\u0131n\u0131 indirebilmek i\u00e7in a\u015fa\u011f\u0131daki linklere t\u0131klay\u0131n\u0131z.<\/p>\n<ul>\n<li>(Server)<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/10\/SignalRAuthorizationExample.zip\">SignalRAuthorizationExample<\/a><\/li>\n<li>(Client-Web-Console)<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/10\/SignalRAuthorizationExampleUI.zip\">SignalRAuthorizationExampleUI<\/a><\/li>\n<\/ul>\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, Klasik web uygulamalar\u0131nda oldu\u011fu gibi SignalR mimarisiyle real time \u00e7al\u0131\u015fan uygulamalarda da kullan\u0131c\u0131 do\u011frulama ve yetkilendirme ihtiyac\u0131 hissedebilir ve e\u015fzamanl\u0131 veri ak\u0131\u015f\u0131 esnas\u0131nda tan\u0131ml\u0131 kullan\u0131c\u0131lar d\u0131\u015f\u0131nda etkile\u015fime m\u00fcdahale olunmas\u0131n\u0131 istemeyebiliriz. Bu i\u00e7eri\u011fimizde, bu&#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":17653,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3760],"tags":[3818,3819,3813,3814,3815,3817,3820,3822,3823,3816,3821],"class_list":["post-17985","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-signalr","tag-accesstokenfactory","tag-signalr-accesstokenfactory","tag-signalr-authentication","tag-signalr-authorization","tag-signalr-jwt","tag-signalr-refresh-token","tag-signalr-refresh-token-kullanimi","tag-signalr-rol-yonetimi","tag-signalr-role-management","tag-signalr-token","tag-using-signalr-refresh-token"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/17985","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=17985"}],"version-history":[{"count":77,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/17985\/revisions"}],"predecessor-version":[{"id":18071,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/17985\/revisions\/18071"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media\/17653"}],"wp:attachment":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media?parent=17985"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/categories?post=17985"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/tags?post=17985"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}