Asp.NET Core Identity + Angular 14 Eşliğinde Google Login
Merhaba,
Bu içeriğimizde, Angular ile geliştirdiğimiz uygulamalarda kullanıcıların sosyal profillerini kullanarak giriş yapmak istemeleri durumlarına istinaden Google hesabı üzerinden bir oturum açma çalışması sergiliyor olacağız. Tabi bu çalışmada, Angular kısmında @abacritt/angularx-social-login kütüphanesinden istifade edecek ve sosyal ağlardan gelen kayıt ve oturum bilgilerini tutabilmek ve yönetebilmek için backend’de Asp.NET Core Identity mekanizmasını kullanıyor olacağız.
Başlarken
Her şeyden önce hali hazırda temelleri atılmış Angular 14 ve Asp.NET Core Web API uygulamaları oluşturunuz ve özellikle Asp.NET Core uygulamasında Identity konfigürasyonlarını ve hatta JWT gibi authentication yapılanmalarını tamamlayınız.
Google Platformunda Credentials Oluşturma
İlk olarak oturum açma işlemini gerçekleştireceğimiz Google API platformu üzerinden bir kimlik bilgisi oluşturarak işe başlamamız gerekmektedir. Bunun için New Project – Google Cloud Console sayfası üzerinden uygulamanız için Google Cloud’da bir proje oluşturunuz.
Ardından console.cloud.google.com sayfasına gelerek aşağıdaki ekran görüntüsünde olduğu gibi biraz önce oluşturulan projenin seçili olduğundan emin olacak şekilde ‘Quick access’ altındaki işaretli kısma tıklayınız.
Şimdi açılan sayfada uygulamanız için bir yapılandırma oluşturacaksınız. Bu yapılandırma için aşağıdaki ekran görüntüsünde vurgulandığı gibi sol menüden ‘Credentials’ sekmesine geliniz ve ardından ‘Create Credentials’ butonuna oradan da açılan pencereden ‘OAuth client ID’ sekmesine tıklayınız.
Açılan sayfada izin ekranını yapılandırabilmek için sağ taraftaki ‘Configure Consent Screen’ butonuna tıklayınız.
Ardından açılan sayfada aşağıdaki gibi ‘External’i seçerek ilerleyiniz.
Devamında uygulama bilgilerine dair gelen sayfada aşağıdaki gibi basitçe alanları doldurmak şimdilik yeterli olacaktır.
Bundan sonra tüm sayfaları hızlıca geçebilirsiniz.
Artık tekrardan ‘Credentials’ sekmesine gelip ‘Create Credentials’ butonu üzerinden ‘OAuth client ID’ sekmesine tıklarsanız artık bir ‘OAuth client ID’ tanımlama fırsatı elde edebileceksiniz. Evet, biliyorum. Google Cloud bu konuda oldukça zahmetli ve yorucu 🙂 Ama el mahkum, bu aşamaların bir şekilde geçilmesi gerekmektedir… Velhasıl, ‘OAuth client ID’ tanımlarken aşağıdaki görselde olduğu gibi adı ve yetkilendirilmiş javascript origins’leri bildirmemiz gerekmektedir.Burada bizler Angular uygulamasını localhost’ta ayağa kaldıracağımızdan dolayı ‘http://localhost:4200’ adresiyle birlikte ayrıca dikkat ederseniz portsuz hali de bildirilmiştir. Bu durumun gerekliliği önceden edindiğimiz tecrübelerle sabit olan bir durumdur. O yüzden sizlerde eğer local’de çalışma sergiliyorsanız, Google Cloud üzerinde tanımlama yaparken tıpkı buradaki gibi port’suz bir bildiride de bulunmayı ihmal etmeyiniz. Bu tanımlamalardan sonra ‘Create’ neticesinde Google API sizlere aşağıdaki görselde olduğu gibi client id ve client secret keyleri verecektir.
İşte bizler tüm çalışmaları bu keyler üzerinden gerçekleştiriyor olacağız.
Angularx-Social-Login Paketinin Yüklenmesi
Angular uygulamasında; Google login, Facebook login vs. gibi sosyal sitelerden yetkilendirme işlemleri söz konusu olduğu taktirde bizlere oldukça yardımı dokunacak olan angularx-social-login kütüphanesinden istifade edeceğimizi söylemiştik. Şimdi bu paketi npm i @abacritt/angularx-social-login
talimatı eşliğinde Angular uygulamanıza yükleyiniz ve aşağıdaki konfigürasyonları gerçekleştiriniz(Not : İlgili paketi verilen talimat eşliğinde yükleyebilmek için Angular uygulamasının en düşük 14 versiyonunda olması gerekmektedir)
import { GoogleLoginProvider, SocialAuthServiceConfig, SocialLoginModule } from '@abacritt/angularx-social-login'; import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AppRoutingModule, SocialLoginModule ], providers: [ { provide: "SocialAuthServiceConfig", useValue: { autoLogin: false, providers: [ { id: GoogleLoginProvider.PROVIDER_ID, provider: new GoogleLoginProvider("902986185803-4dl068flq4g27bpj299khhlq7es3g988.apps.googleusercontent.com") } ], onError: err => console.log(err) } as SocialAuthServiceConfig } ], bootstrap: [AppComponent] }) export class AppModule { }
Dikkat ederseniz client id değeri burada provider olarak bildirilmektedir. Bu konfigürasyonlardan sonra ‘login.component.ts’ dosyasına geliniz ve aşağıdaki gibi ‘SocialAuthService’i çağırarak işlemleri gerçekleştiriniz.
import { SocialAuthService, SocialUser } from '@abacritt/angularx-social-login'; import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-login', templateUrl: './login.component.html', styleUrls: ['./login.component.scss'] }) export class LoginComponent implements OnInit { constructor(private socialAuthService: SocialAuthService) { this.socialAuthService.authState.subscribe((user: SocialUser) => { console.log(user); }); } ngOnInit(): void { } }
Tabi, bir yandan da Google login butonunu çıkarabilmek için ise ‘login.component.html’ dosyasında aşağıdaki gibi ‘asl-google-signin-button’ direktifini çağırmanız gerekmektedir.
<asl-google-signin-button></asl-google-signin-button>
Tüm bu işlemlerden sonra ilgili butona tıkladığınızda aşağıdaki ekran görüntüsünde olduğu gibi Google açısından kullanıcı tarafından gerekli yetkilendirme sağlanması için bir onay penceresi çıkacaktır.Eğer kullanıcı yetkilendirmeyi sağlarsa Google’dan gelecek olan kullanıcı bilgileri aşağıdaki gibi olacaktır.
Böylece çalışmamızın ilk safhası bitmiştir diyebiliriz. Nihayetinde Angular kısmında kullanıcı Google login gerçekleştirmekte ve uygulama açısından gerekli veriler elde edilmektedir. Şimdi sıra Asp.NET Core Identity kütüphanesiyle bu verileri işlemeye gelmiştir.
Angular’da Gerçekleştirilen Login’i Asp.NET Core Identity İle Backend’de de Gerçekleştirmek
Google’dan gelen idToken
‘ı backend’de de doğrulamak için Google.Apis.Auth kütüphanesinden istifade ediyor olacağız. Haliyle ilgili kütüphaneyi verilen adres üzerinden projenize yükleyiniz ve aşağıdaki geliştirmeyi gerçekleştiriniz.
public class GoogleIdTokenValidationService : IGoogleIdTokenValidationService { readonly IConfiguration _configuration; readonly UserManager<AppUser> _userManager; readonly ITokenHandler _tokenHandler; public GoogleIdTokenValidationService( IConfiguration configuration, UserManager<AppUser> userManager, ITokenHandler tokenHandler) { _configuration = configuration; _userManager = userManager; _tokenHandler = tokenHandler; } public async Task<Token> ValidateIdTokenAsync(GoogleLoginVM model) { ValidationSettings? settings = new GoogleJsonWebSignature.ValidationSettings() { Audience = new List<string>() { _configuration["ExternalLogin:Google-Client-Id"] } }; Payload payload = await GoogleJsonWebSignature.ValidateAsync(model.IdToken, settings); UserLoginInfo userLoginInfo = new(model.Provider, payload.Subject, model.Provider); AppUser user = await _userManager.FindByLoginAsync(userLoginInfo.LoginProvider, userLoginInfo.ProviderKey); bool result = user != null; if (user == null) { user = await _userManager.FindByEmailAsync(payload.Email); if (user == null) { user = new() { Id = Guid.NewGuid().ToString(), Email = payload.Email, UserName = payload.Email, Provider = model.Provider }; IdentityResult createResult = await _userManager.CreateAsync(user); result = createResult.Succeeded; } } if (result) await _userManager.AddLoginAsync(user, userLoginInfo); else throw new Exception("Invalid external authentication."); Token token = _tokenHandler.CreateAccessToken(5); return token; } }
Yukarıdaki kod bloğunu incelerseniz eğer; 18 ile 23. satır aralığında Google Client Id’yi(appsettings.json’dan geliyor) tutan bir ‘ValidationSettings’ nesnesi ayarlanmakta ve client’tan gelen ‘idToken’ bilgisi eşliğinde bu token’ın payload’ı ayrıştırılmaktadır. 25. satırda ise dış kaynaktan gelen kullanıcı bilgilerini ‘AspNetUserLogins’ tablosuna kaydetmemizi sağlayacak olan bir ‘UserLoginInfo’ nesnesi oluşturulmaktadır. 26. satırda FindByLoginAsync
fonksiyonu ile ‘AspNetUserLogins’ tablosunda ‘UserLoginInfo’ nesnesindeki bilgilere karşılık bir kayıt olup olmadığı kontrol edilmekte ve kayıt varsa eğer giriş yaptırılmaktadır. Nihayetinde burada kullanıcı önceden aynı dış kaynaktan geldiyse uygulama tarafından tanınması ve direkt giriş yaptırılması gerekmektedir. 27 ile 37. satır aralığında ise dış kaynaktan gelen kullanıcının önceden gelmediğine dair ‘AspNetUserLogins’ tablosunda bir kaydın olmaması durumu göz önüne alınarak, önce bu kullanıcı email’inde bir kullanıcı olup olmadığı değerlendirilmekte, yoksa bu kullanıcının kaydı gerçekleştirilmektedir. 40. satırda ise AddLoginAsync
fonksiyonu ile dış kaynaktan giriş yapan kullanıcının bilgileri eğer ‘AspNetUserLogins’ tablosunda yoksa işlenmektedir. 44 ile 45. satır aralığında ise artık Google’dan gelen kullanıcı doğrulandıysa yetkilendirmeyi sağlayacak manevra gerçekleştirilmektedir. Tabi biz burada JWT üretiyor ve gönderiyoruz ama sizler farklı bir yetkilendirme davranışı neticesinde client’a dönüş yapabilirsiniz.
Ayrıca 33. satıra bakarsanız gelen login talebinde eklenecek olan kullanıcının hangi provider eşliğinde eklendiğinin de kaydını tutmaktayız. Ne de olsa tüm kullanıcılar ‘AspNetUsers’ tablosunda tutulacaktırlar ve hangisinin nereden geldiğini bilebilmek için kullanıcı seviyesinde bu şekilde bir bilgi tutulması işimizi kolaylaştırabilir. Ha eğer ki sizler bu bilgiyi ‘AspNetUsers’ tablosunda tutmuyorsanız ‘AspNetUserLogins’ tablosunda hangi kullanıcının hangi provider ile geldiğini inner join eşliğinde rahatlıkla öğrenebilirsiniz.(Ki doğrusu bu ikincisidir, çünkü bu makale için görsel açıdan görebilelim diye provider bilgisini ‘AspNetUsers’ tablosunda tutuyorum ama bu durumda da her bir kullanıcı için veri tekrarı söz konusu olacak ve bu da normalizasyona aykırı bir durum ortaya koyacaktır!)
Bu geliştirmeden sonra misal olarak ‘UsersController’ isimli bir controller içerisinde ‘Login’ işlemi için aşağıdaki gibi istek karşılanabilir.
[Route("api/[controller]")] [ApiController] public class UsersController : ControllerBase { readonly IGoogleIdTokenValidationService _googleIdTokenValidationService; public UsersController(IGoogleIdTokenValidationService googleIdTokenValidationService) { _googleIdTokenValidationService = googleIdTokenValidationService; } [HttpPost] public async Task<IActionResult> Login(GoogleLoginVM model) { Token token = await _googleIdTokenValidationService.ValidateIdTokenAsync(model); return Ok(token); } }
Backend’de ki bu geliştirmelerden sonra tek yapılması gereken Angular’da ‘SocialAuthService’in çağrıldığı yerde uygun endpoint’e ‘SocialUser’ türünde veriyi post isteği eşliğinde göndermektir.
import { SocialAuthService, SocialUser } from '@abacritt/angularx-social-login'; import { Component, OnInit } from '@angular/core'; import { HttpClient } from '@angular/common/http' @Component({ selector: 'app-login', templateUrl: './login.component.html', styleUrls: ['./login.component.scss'] }) export class LoginComponent implements OnInit { constructor(private socialAuthService: SocialAuthService, private httpClient: HttpClient) { this.socialAuthService.authState.subscribe((user: SocialUser) => { httpClient.post("https://localhost:7054/api/users/", user).subscribe(token => console.log(token)) }); } ngOnInit(): void { } }
Test Edelim
Geliştirdiğimiz uygulamanın hem Angular hem de API kanatlarını ayağa kaldırıp test edersek eğer;yukarıdaki gibi hem Google doğrulamasının gerçekleştirildiğini hem de backend’den client’a yetkilendirilmiş bir token üretilip gönderildiğini görmüş olacağız.
Nihai olarak,
Angular 14 ile Google hesabı üzerinden dış kaynak login işleminin backend’de Asp.NET Core Identity mekanizması eşliğinde nasıl yapılacağını incelemiş ve tatbik etmiş olduk. İçerik sürecinde geliştirdiğimiz uygulamaların bahsedilmeyen tüm detaylarını aşağıdaki github adreslerinden görebilir ve inceleyebilirsiniz.
İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…
AngularGoogleLoginExampleAPI : https://github.com/gncyyldz/AngularGoogleLoginExampleAPI
AngularGoogleLoginExampleClient: https://github.com/gncyyldz/AngularGoogleLoginExampleClient
Salamlar, mən Asp.NET Core 5.0 – dərslərinizi bitirmədim də, 15ci dərsə qədər gəldim. Direkt burdan davam edə bilərəmmi? Yoxsa 5.0 ı bitirmədən buna başlamayımmı? Lütfən mənə bir yol göstərə bilərmisiniz?
Merhabalar Gençeay Hocam size bir sorum olacaktı , yaptığımız bir angular projesini yine kendi yazdığımız web apimizle beraber kiraladığımız sunucu da yayımlama işlemini yaparken Angular Projesi ile web api projesini nasıl haberleştirip yayımyalabiliriz ? Bu arada youtube eğitimlerinizi takip ediyorum Allah Razı Olsun sizin sayenizde eğtimlerinizden çok faydalanıyorum . Tekrar teşekkür ederim.
Merhaba İbrahim,
Bu soruna karşılık, Mini E-Ticaret eğitiminin sonunda yaptığımız deploy çalışmasını izlemeni tavsiye ederim.
Kolaylıklar dilerim…