diff --git a/pom.xml b/pom.xml index 4dedf6e..2333716 100644 --- a/pom.xml +++ b/pom.xml @@ -63,6 +63,11 @@ org.springframework.boot spring-boot-starter-thymeleaf + + com.google.api-client + google-api-client + 1.32.1 + com.mysql mysql-connector-j diff --git a/src/main/java/com/pet/foundation/pataamiga/config/security/SecurityConfigurations.java b/src/main/java/com/pet/foundation/pataamiga/config/security/SecurityConfigurations.java index a08de08..7d7e353 100644 --- a/src/main/java/com/pet/foundation/pataamiga/config/security/SecurityConfigurations.java +++ b/src/main/java/com/pet/foundation/pataamiga/config/security/SecurityConfigurations.java @@ -62,6 +62,7 @@ public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Excepti .requestMatchers(HttpMethod.POST, "/api/v1/auth/login").permitAll() .requestMatchers(HttpMethod.POST, "/api/v1/auth/register").permitAll() .requestMatchers(HttpMethod.GET, "/api/v1/posts").permitAll() + .requestMatchers(HttpMethod.POST, "/api/v1/auth/login/google").permitAll() .anyRequest().authenticated() ) .addFilterBefore(securityFilter, UsernamePasswordAuthenticationFilter.class) diff --git a/src/main/java/com/pet/foundation/pataamiga/controller/AuthController.java b/src/main/java/com/pet/foundation/pataamiga/controller/AuthController.java index a41bd36..45107e0 100644 --- a/src/main/java/com/pet/foundation/pataamiga/controller/AuthController.java +++ b/src/main/java/com/pet/foundation/pataamiga/controller/AuthController.java @@ -3,6 +3,7 @@ import com.pet.foundation.pataamiga.controller.responses.LoginResponse; import com.pet.foundation.pataamiga.controller.responses.RegisterResponse; import com.pet.foundation.pataamiga.domain.user.dto.LoginDTO; +import com.pet.foundation.pataamiga.domain.user.dto.LoginGoogleDTO; import com.pet.foundation.pataamiga.domain.user.dto.UserCreateDTO; import com.pet.foundation.pataamiga.service.AuthService; import com.pet.foundation.pataamiga.swagger.annotatios.ConflictResponse; @@ -35,6 +36,15 @@ public ResponseEntity login(@RequestBody @Valid LoginDTO loginDTO return ResponseEntity.ok(authService.login(loginDTO)); } + @PostMapping("/login/google") + @Operation(summary = "Login with Google", description = "You can login with your Google account") + @Tag(name = "auth") + @OkResponse + @ForbiddenResponse + public ResponseEntity loginWithGoogle(@RequestBody LoginGoogleDTO loginInfo) throws Exception { + return ResponseEntity.ok(authService.loginWithGoogle(loginInfo.token())); + } + @PostMapping("/register") @Operation(summary = "Register", description = "You can register with your name, email and password") diff --git a/src/main/java/com/pet/foundation/pataamiga/domain/user/dto/LoginGoogleDTO.java b/src/main/java/com/pet/foundation/pataamiga/domain/user/dto/LoginGoogleDTO.java new file mode 100644 index 0000000..8207f8f --- /dev/null +++ b/src/main/java/com/pet/foundation/pataamiga/domain/user/dto/LoginGoogleDTO.java @@ -0,0 +1,6 @@ +package com.pet.foundation.pataamiga.domain.user.dto; + +public record LoginGoogleDTO( + String token +) { +} diff --git a/src/main/java/com/pet/foundation/pataamiga/domain/user/dto/UserCreateDTO.java b/src/main/java/com/pet/foundation/pataamiga/domain/user/dto/UserCreateDTO.java index 716ce45..cce53e9 100644 --- a/src/main/java/com/pet/foundation/pataamiga/domain/user/dto/UserCreateDTO.java +++ b/src/main/java/com/pet/foundation/pataamiga/domain/user/dto/UserCreateDTO.java @@ -4,7 +4,9 @@ import com.pet.foundation.pataamiga.domain.user.User; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; +import lombok.Builder; +@Builder public record UserCreateDTO( @NotBlank(message = "Name is mandatory") @Schema(description = "User name", example = "John Doe") diff --git a/src/main/java/com/pet/foundation/pataamiga/service/AuthService.java b/src/main/java/com/pet/foundation/pataamiga/service/AuthService.java index 1cfc5e8..c8d2465 100644 --- a/src/main/java/com/pet/foundation/pataamiga/service/AuthService.java +++ b/src/main/java/com/pet/foundation/pataamiga/service/AuthService.java @@ -5,8 +5,13 @@ import com.pet.foundation.pataamiga.domain.user.dto.LoginDTO; import com.pet.foundation.pataamiga.domain.user.dto.UserCreateDTO; +import java.io.IOException; +import java.security.GeneralSecurityException; + public interface AuthService { LoginResponse login(LoginDTO loginDTO); + LoginResponse loginWithGoogle(String token) throws Exception; + RegisterResponse register(UserCreateDTO userCreateDTO); } diff --git a/src/main/java/com/pet/foundation/pataamiga/service/impl/AuthServiceImpl.java b/src/main/java/com/pet/foundation/pataamiga/service/impl/AuthServiceImpl.java index 7aecc78..39fb97f 100644 --- a/src/main/java/com/pet/foundation/pataamiga/service/impl/AuthServiceImpl.java +++ b/src/main/java/com/pet/foundation/pataamiga/service/impl/AuthServiceImpl.java @@ -1,5 +1,10 @@ package com.pet.foundation.pataamiga.service.impl; +import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken; +import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload; +import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.json.gson.GsonFactory; import com.pet.foundation.pataamiga.controller.responses.LoginResponse; import com.pet.foundation.pataamiga.controller.responses.RegisterResponse; import com.pet.foundation.pataamiga.domain.user.User; @@ -9,13 +14,22 @@ import com.pet.foundation.pataamiga.service.TokenService; import com.pet.foundation.pataamiga.service.UserService; import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Service; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.List; +import java.util.UUID; + @Service -@AllArgsConstructor +@RequiredArgsConstructor +@Log4j2 public class AuthServiceImpl implements AuthService { private final UserService userService; @@ -24,6 +38,9 @@ public class AuthServiceImpl implements AuthService { private final TokenService tokenService; + @Value("${google.client.id}") + private String GOOGLE_CLIENT_ID; + @Override public LoginResponse login(LoginDTO loginDTO) { UsernamePasswordAuthenticationToken userNamePassword = @@ -34,9 +51,62 @@ public LoginResponse login(LoginDTO loginDTO) { return new LoginResponse(token); } + @Override + public LoginResponse loginWithGoogle(String token) throws Exception { + + log.info("token: {}", token); + GoogleIdTokenVerifier verifier = buildGoogleIdTokenVerifier(); + + log.info("verifier: {}", verifier); + + GoogleIdToken idToken = verifier.verify(token); + log.info("idToken: {}", idToken); + + if (idToken != null) { + Payload payload = idToken.getPayload(); + String email = payload.getEmail(); + String name = (String) payload.get("name"); + String picture = (String) payload.get("picture"); + + User user = userService.getUserByEmail(email); + + log.info("user: {}", user); + + if (user == null) { + UserCreateDTO userCreateDTO = buildUserCreateDTO(email, name, picture); + String userCreatedUuid = userService.createUser(userCreateDTO); + user = userService.getUserByUuid(userCreatedUuid); + String tokenGenerated = tokenService.generateToken(user); + return new LoginResponse(tokenGenerated); + } + + String tokenGenerated = tokenService.generateToken(user); + return new LoginResponse(tokenGenerated); + + } else { + throw new Exception("Invalid ID token"); + } + } + @Override public RegisterResponse register(UserCreateDTO userCreateDTO) { String userCreatedUuid = userService.createUser(userCreateDTO); return new RegisterResponse(userCreatedUuid); } + + private GoogleIdTokenVerifier buildGoogleIdTokenVerifier() { + return new GoogleIdTokenVerifier.Builder(new NetHttpTransport(), new GsonFactory()) + .setAudience(List.of(GOOGLE_CLIENT_ID)) + .build(); + } + + private UserCreateDTO buildUserCreateDTO(String email, String name, String picture) { + return UserCreateDTO.builder() + .email(email) + .name(name) + .profilePicture(picture) + .password(UUID.randomUUID().toString()) + .phone("9 9999-9999") + .build(); + } }