From bd2410a98eeda264b57c72f4f4b9046055c86a0f Mon Sep 17 00:00:00 2001
From: Kamigen <46357922+Edouard127@users.noreply.github.com>
Date: Mon, 15 Apr 2024 19:10:32 -0400
Subject: [PATCH] Test: Google oauth
---
Directory.Packages.props | 3 +-
src/Application/Application.csproj | 1 +
.../Common/Interfaces/IGoogleService.cs | 8 ++++
.../Common/Interfaces/IIdentityService.cs | 5 ++-
.../Google/Commands/CreateGoogleUser.cs | 20 ++++++++++
src/Domain/Domain.csproj | 1 +
src/Domain/Interfaces/IUserService.cs | 5 ++-
.../Identity/ApplicationUser.cs | 1 +
.../Identity/IdentityService.cs | 18 +++++++++
src/Infrastructure/Services/GoogleService.cs | 24 ++++++++++++
src/Infrastructure/Services/UserService.cs | 39 +++++++++++++------
src/Web/Endpoints/Google.cs | 22 +++++++++++
12 files changed, 132 insertions(+), 15 deletions(-)
create mode 100644 src/Application/Common/Interfaces/IGoogleService.cs
create mode 100644 src/Application/Google/Commands/CreateGoogleUser.cs
create mode 100644 src/Infrastructure/Services/GoogleService.cs
create mode 100644 src/Web/Endpoints/Google.cs
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 74620e0..758ff65 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -7,11 +7,12 @@
-
+
+
diff --git a/src/Application/Application.csproj b/src/Application/Application.csproj
index 8544947..34570d3 100644
--- a/src/Application/Application.csproj
+++ b/src/Application/Application.csproj
@@ -9,6 +9,7 @@
+
diff --git a/src/Application/Common/Interfaces/IGoogleService.cs b/src/Application/Common/Interfaces/IGoogleService.cs
new file mode 100644
index 0000000..aba62f7
--- /dev/null
+++ b/src/Application/Common/Interfaces/IGoogleService.cs
@@ -0,0 +1,8 @@
+using Google.Apis.Oauth2.v2.Data;
+
+namespace Hutopy.Application.Common.Interfaces;
+
+public interface IGoogleService
+{
+ Task GetUserInfoAsync(string accessToken);
+}
diff --git a/src/Application/Common/Interfaces/IIdentityService.cs b/src/Application/Common/Interfaces/IIdentityService.cs
index 5dbcb4c..399b19c 100644
--- a/src/Application/Common/Interfaces/IIdentityService.cs
+++ b/src/Application/Common/Interfaces/IIdentityService.cs
@@ -1,4 +1,5 @@
-using Hutopy.Application.Common.Models;
+using Google.Apis.Oauth2.v2.Data;
+using Hutopy.Application.Common.Models;
namespace Hutopy.Application.Common.Interfaces;
@@ -11,6 +12,8 @@ public interface IIdentityService
Task AuthorizeAsync(string userId, string policyName);
Task<(Result Result, string UserId)> CreateUserAsync(string userName, string password);
+
+ Task<(Result Result, string UserId)> CreateUserAsync(Userinfo userInfo);
Task DeleteUserAsync(string userId);
}
diff --git a/src/Application/Google/Commands/CreateGoogleUser.cs b/src/Application/Google/Commands/CreateGoogleUser.cs
new file mode 100644
index 0000000..a5f2bca
--- /dev/null
+++ b/src/Application/Google/Commands/CreateGoogleUser.cs
@@ -0,0 +1,20 @@
+using Hutopy.Application.Common.Interfaces;
+
+namespace Hutopy.Application.Google.Commands;
+
+public record CreateGoogleUserCommand : IRequest
+{
+ public required string AccessToken { get; init; }
+}
+
+public class CreateGoogleUser(
+ IApplicationDbContext context
+ ) : IRequestHandler
+{
+ public async Task Handle(CreateGoogleUserCommand request, CancellationToken cancellationToken)
+ {
+ await context.SaveChangesAsync(cancellationToken);
+
+ return Guid.NewGuid();
+ }
+}
diff --git a/src/Domain/Domain.csproj b/src/Domain/Domain.csproj
index efab6e8..56e216d 100644
--- a/src/Domain/Domain.csproj
+++ b/src/Domain/Domain.csproj
@@ -6,6 +6,7 @@
+
diff --git a/src/Domain/Interfaces/IUserService.cs b/src/Domain/Interfaces/IUserService.cs
index c3bd5ac..c59cc2a 100644
--- a/src/Domain/Interfaces/IUserService.cs
+++ b/src/Domain/Interfaces/IUserService.cs
@@ -1,4 +1,5 @@
-using Hutopy.Domain.Models;
+using Google.Apis.Oauth2.v2.Data;
+using Hutopy.Domain.Models;
namespace Hutopy.Domain.Interfaces;
@@ -6,6 +7,8 @@ public interface IUserService
{
Task CreateUserAsync(string email, string userName, string firstName, string lastName, string password);
+ Task CreateUserAsync(Userinfo userInfo);
+
Task FindUserByIdAsync(string id);
Task FindUserByEmailAsync(string id);
diff --git a/src/Infrastructure/Identity/ApplicationUser.cs b/src/Infrastructure/Identity/ApplicationUser.cs
index 0462aff..39cb433 100644
--- a/src/Infrastructure/Identity/ApplicationUser.cs
+++ b/src/Infrastructure/Identity/ApplicationUser.cs
@@ -6,4 +6,5 @@ public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
+ //public string Gender { get; set; } = string.Empty;
}
diff --git a/src/Infrastructure/Identity/IdentityService.cs b/src/Infrastructure/Identity/IdentityService.cs
index 71a3886..5b32670 100644
--- a/src/Infrastructure/Identity/IdentityService.cs
+++ b/src/Infrastructure/Identity/IdentityService.cs
@@ -1,3 +1,4 @@
+using Google.Apis.Oauth2.v2.Data;
using Hutopy.Application.Common.Interfaces;
using Hutopy.Application.Common.Models;
using Microsoft.AspNetCore.Authorization;
@@ -30,6 +31,23 @@ public class IdentityService(
return (result.ToApplicationResult(), user.Id);
}
+
+ public async Task<(Result Result, string UserId)> CreateUserAsync(Userinfo userInfo)
+ {
+ var user = new ApplicationUser
+ {
+ UserName = userInfo.Name,
+ Email = userInfo.Email,
+ FirstName = userInfo.GivenName,
+ LastName = userInfo.FamilyName
+ };
+
+ var password = Guid.NewGuid().ToString("N")[..32];
+
+ var result = await userManager.CreateAsync(user, password);
+
+ return (result.ToApplicationResult(), user.Id);
+ }
public async Task IsInRoleAsync(string userId, string role)
{
diff --git a/src/Infrastructure/Services/GoogleService.cs b/src/Infrastructure/Services/GoogleService.cs
new file mode 100644
index 0000000..b8abdf2
--- /dev/null
+++ b/src/Infrastructure/Services/GoogleService.cs
@@ -0,0 +1,24 @@
+using Google.Apis.Auth.OAuth2;
+using Google.Apis.Services;
+using Google.Apis.Oauth2.v2;
+using Google.Apis.Oauth2.v2.Data;
+using Hutopy.Application.Common.Interfaces;
+
+namespace Hutopy.Infrastructure.Services;
+
+public class GoogleService : IGoogleService
+{
+ public async Task GetUserInfoAsync(string accessToken)
+ {
+ var user = GoogleCredential.FromAccessToken(accessToken);
+
+ var service = new Oauth2Service(
+ new BaseClientService.Initializer
+ {
+ HttpClientInitializer = user,
+ ApplicationName = "Hutopy"
+ });
+
+ return await service.Userinfo.Get().ExecuteAsync();
+ }
+}
diff --git a/src/Infrastructure/Services/UserService.cs b/src/Infrastructure/Services/UserService.cs
index 98c0c7c..169c5f3 100644
--- a/src/Infrastructure/Services/UserService.cs
+++ b/src/Infrastructure/Services/UserService.cs
@@ -1,15 +1,13 @@
-using Hutopy.Domain.Interfaces;
+using Google.Apis.Oauth2.v2.Data;
+using Hutopy.Domain.Interfaces;
using Hutopy.Domain.Models;
using Hutopy.Infrastructure.Identity;
-using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Identity;
namespace Hutopy.Infrastructure.Services;
public class UserService(UserManager userManager) : IUserService
{
- private readonly UserManager _userManager = userManager;
-
public async Task CreateUserAsync(string email, string userName, string firstName, string lastName, string password)
{
var applicationUser = new ApplicationUser
@@ -19,19 +17,36 @@ public class UserService(UserManager userManager) : IUserServic
FirstName = firstName,
LastName = lastName
};
-
- //todo: Need to handle errors better for the user.
- var response = await _userManager.CreateAsync(applicationUser, password);
-
- if (response.Errors.Any())
+
+ var response = await userManager.CreateAsync(applicationUser, password);
+
+ if (!response.Succeeded)
{
- throw new InvalidOperationException(response.Errors.First().Description);
+ throw new Exception("Failed to create user");
+ }
+ }
+
+ public async Task CreateUserAsync(Userinfo userInfo)
+ {
+ var applicationUser = new ApplicationUser
+ {
+ UserName = userInfo.Name,
+ Email = userInfo.Email,
+ FirstName = userInfo.GivenName,
+ LastName = userInfo.FamilyName
+ };
+
+ var response = await userManager.CreateAsync(applicationUser, Guid.NewGuid().ToString("N")[..32]);
+
+ if (!response.Succeeded)
+ {
+ throw new Exception("Failed to create user");
}
}
public async Task FindUserByIdAsync(string id)
{
- var response = await _userManager.FindByIdAsync(id);
+ var response = await userManager.FindByIdAsync(id);
if (response == null) return null;
@@ -49,7 +64,7 @@ public class UserService(UserManager userManager) : IUserServic
public async Task FindUserByEmailAsync(string email)
{
- var response = await _userManager.FindByEmailAsync(email);
+ var response = await userManager.FindByEmailAsync(email);
if (response == null) return null;
diff --git a/src/Web/Endpoints/Google.cs b/src/Web/Endpoints/Google.cs
new file mode 100644
index 0000000..129e71f
--- /dev/null
+++ b/src/Web/Endpoints/Google.cs
@@ -0,0 +1,22 @@
+using Hutopy.Application.Common.Interfaces;
+using Hutopy.Application.Google.Commands;
+using Hutopy.Domain.Interfaces;
+
+namespace Hutopy.Web.Endpoints;
+
+public class Google : EndpointGroupBase
+{
+ public override void Map(WebApplication app)
+ {
+ app.MapGroup(this)
+ .MapPost(CreateGoogleUser);
+ }
+
+ public static async Task CreateGoogleUser(ISender sender, CreateGoogleUserCommand command, IUserService userService, IGoogleService googleService)
+ {
+ var user = await googleService.GetUserInfoAsync(command.AccessToken) ?? throw new Exception("Failed to get user info from Google");
+ Console.WriteLine(user);
+ await userService.CreateUserAsync(user);
+ return await sender.Send(command);
+ }
+}