From c004c2cfca81b59904d97b8cd11282cebba0242f Mon Sep 17 00:00:00 2001 From: Sardor Date: Mon, 29 Apr 2024 06:55:38 +0500 Subject: [PATCH 1/5] Google Authorization Added --- .../MVC/Controllers/AuthController.cs | 100 +++++++++++++++++- src/BookStore.Presentation/MVC/MVC.csproj | 1 + .../MVC/Models/Auth/LoginDTO.cs | 7 +- src/BookStore.Presentation/MVC/Program.cs | 7 +- .../MVC/Views/Auth/Login.cshtml | 26 ++++- .../MVC/Views/Auth/Login.cshtml.css | 13 ++- .../MVC/Views/Auth/Profile.cshtml.css | 1 + 7 files changed, 145 insertions(+), 10 deletions(-) diff --git a/src/BookStore.Presentation/MVC/Controllers/AuthController.cs b/src/BookStore.Presentation/MVC/Controllers/AuthController.cs index bfea9ab..4357687 100644 --- a/src/BookStore.Presentation/MVC/Controllers/AuthController.cs +++ b/src/BookStore.Presentation/MVC/Controllers/AuthController.cs @@ -6,6 +6,7 @@ using Microsoft.JSInterop; using MVC.Models; using MVC.Models.Auth; +using System.Security.Claims; namespace MVC.Controllers { @@ -37,9 +38,15 @@ public IActionResult Index() return View(); } - public async Task Login() + public async Task Login(string? ReturnUrl = null) { - return View(); + var model = new LoginDTO + { + ReturnUrl = ReturnUrl, + ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList() + }; + + return View(model); } public async Task Register() @@ -188,6 +195,95 @@ public async Task Update(User user) else throw new Exception("Something went wrong"); } + + [HttpPost] + public IActionResult ExternalLogin(string provider, string returnUrl) + { + //This call will generate a URL that directs to the ExternalLoginCallback action method in the Account controller + //with a route parameter of ReturnUrl set to the value of returnUrl. + var redirectUrl = Url.Action(action: "ExternalLoginCallback", controller: "Auth", values: new { ReturnUrl = returnUrl }); + // Configure the redirect URL, provider and other properties + var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl); + //This will redirect the user to the external provider's login page + return new ChallengeResult(provider, properties); + } + + public async Task ExternalLoginCallback(string? returnUrl, string? remoteError) + { + returnUrl = returnUrl ?? Url.Content("~/"); + + LoginDTO loginViewModel = new LoginDTO + { + ReturnUrl = returnUrl, + ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList() + }; + + if (remoteError != null) + { + ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}"); + + return View("Login", loginViewModel); + } + + // Get the login information about the user from the external login provider + var info = await _signInManager.GetExternalLoginInfoAsync(); + if (info == null) + { + ModelState.AddModelError(string.Empty, "Error loading external login information."); + + return View("Login", loginViewModel); + } + + // If the user already has a login (i.e., if there is a record in AspNetUserLogins table) + // then sign-in the user with this external login provider + var signInResult = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, + info.ProviderKey, isPersistent: false, bypassTwoFactor: true); + + if (signInResult.Succeeded) + { + return LocalRedirect(returnUrl); + } + + // If there is no record in AspNetUserLogins table, the user may not have a local account + else + { + // Get the email claim value + var email = info.Principal.FindFirstValue(ClaimTypes.Email); + + if (email != null) + { + // Create a new user without password if we do not have a user already + var user = await _userManager.FindByEmailAsync(email); + + if (user == null) + { + user = new User + { + UserName = info.Principal.FindFirstValue(ClaimTypes.Email), + Email = info.Principal.FindFirstValue(ClaimTypes.Email), + FullName = info.Principal.FindFirstValue(ClaimTypes.GivenName) + info.Principal.FindFirstValue(ClaimTypes.Surname), + }; + + //This will create a new user into the AspNetUsers table without password + await _userManager.CreateAsync(user); + } + + // Add a login (i.e., insert a row for the user in AspNetUserLogins table) + await _userManager.AddLoginAsync(user, info); + + //Then Signin the User + await _signInManager.SignInAsync(user, isPersistent: false); + + return LocalRedirect(returnUrl); + } + + // If we cannot find the user email we cannot continue + ViewBag.ErrorTitle = $"Email claim not received from: {info.LoginProvider}"; + ViewBag.ErrorMessage = "Please contact support on info@dotnettutorials.net"; + + return View("Error"); + } + } } } diff --git a/src/BookStore.Presentation/MVC/MVC.csproj b/src/BookStore.Presentation/MVC/MVC.csproj index d1a012c..151579f 100644 --- a/src/BookStore.Presentation/MVC/MVC.csproj +++ b/src/BookStore.Presentation/MVC/MVC.csproj @@ -8,6 +8,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/BookStore.Presentation/MVC/Models/Auth/LoginDTO.cs b/src/BookStore.Presentation/MVC/Models/Auth/LoginDTO.cs index 6505f61..bc1684f 100644 --- a/src/BookStore.Presentation/MVC/Models/Auth/LoginDTO.cs +++ b/src/BookStore.Presentation/MVC/Models/Auth/LoginDTO.cs @@ -1,8 +1,13 @@ -namespace MVC.Models.Auth +using Microsoft.AspNetCore.Authentication; + +namespace MVC.Models.Auth { public class LoginDTO { public string Password { get; set; } public string Email { get; set; } + + public string? ReturnUrl { get; set; } + public IList? ExternalLogins { get; set; } } } diff --git a/src/BookStore.Presentation/MVC/Program.cs b/src/BookStore.Presentation/MVC/Program.cs index 44af41b..d9821c7 100644 --- a/src/BookStore.Presentation/MVC/Program.cs +++ b/src/BookStore.Presentation/MVC/Program.cs @@ -21,7 +21,12 @@ builder.Services.AddIdentity() .AddEntityFrameworkStores(); -builder.Services.AddAuthentication(); +builder.Services.AddAuthentication() + .AddGoogle(options => + { + options.ClientId = "733255891197-6kjvhbtu55ioc4uansrsuhh7bn4gi4ig.apps.googleusercontent.com"; + options.ClientSecret = "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"; + }); // Logger var logger = new LoggerConfiguration() diff --git a/src/BookStore.Presentation/MVC/Views/Auth/Login.cshtml b/src/BookStore.Presentation/MVC/Views/Auth/Login.cshtml index 522adb0..0ac8013 100644 --- a/src/BookStore.Presentation/MVC/Views/Auth/Login.cshtml +++ b/src/BookStore.Presentation/MVC/Views/Auth/Login.cshtml @@ -1,7 +1,8 @@ @using MVC.Models.Auth @model LoginDTO -
+
+
@@ -11,9 +12,30 @@
- + +@if (Model.ExternalLogins?.Count == 0) +{ +
No external logins configured
+} +else +{ + +} +
+