OAuth2TokenService.java
package org.petify.backend.services;
import org.petify.backend.dto.LoginResponseDTO;
import org.petify.backend.models.ApplicationUser;
import org.petify.backend.models.OAuth2Provider;
import org.petify.backend.models.Role;
import org.petify.backend.repository.OAuth2ProviderRepository;
import org.petify.backend.repository.RoleRepository;
import org.petify.backend.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
@Service
public class OAuth2TokenService {
@Autowired
private UserRepository userRepository;
@Autowired
private OAuth2ProviderRepository oauth2ProviderRepository;
@Autowired
private RoleRepository roleRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private TokenService tokenService;
public LoginResponseDTO exchangeGoogleToken(String accessToken) {
Map<String, Object> googleUserInfo = verifyGoogleToken(accessToken);
if (googleUserInfo == null) {
throw new RuntimeException("Invalid Google access token");
}
ApplicationUser user = findOrCreateUserFromGoogle(googleUserInfo);
Authentication authentication = createAuthenticationFromUser(user);
String token = tokenService.generateJwt(authentication);
return new LoginResponseDTO(user, token);
}
private Map<String, Object> verifyGoogleToken(String accessToken) {
try {
RestTemplate restTemplate = new RestTemplate();
String googleApiUrl = "https://www.googleapis.com/oauth2/v2/userinfo?access_token=" + accessToken;
@SuppressWarnings("unchecked")
Map<String, Object> response = restTemplate.getForObject(googleApiUrl, Map.class);
if (response != null && response.containsKey("email") && response.containsKey("id")) {
return response;
}
return null;
} catch (Exception e) {
System.err.println("Error verifying Google token: " + e.getMessage());
return null;
}
}
@Transactional
protected ApplicationUser findOrCreateUserFromGoogle(Map<String, Object> googleUserInfo) {
String email = (String) googleUserInfo.get("email");
String googleId = (String) googleUserInfo.get("id");
String name = (String) googleUserInfo.get("name");
Optional<OAuth2Provider> existingProvider =
oauth2ProviderRepository.findByProviderIdAndProviderUserId("google", googleId);
if (existingProvider.isPresent()) {
final ApplicationUser user = existingProvider.get().getUser();
existingProvider.get().setEmail(email);
existingProvider.get().setName(name);
oauth2ProviderRepository.save(existingProvider.get());
return user;
}
final ApplicationUser user = userRepository.findByUsername(email)
.orElseGet(() -> {
Role userRole = roleRepository.findByAuthority("USER")
.orElseThrow(() -> new RuntimeException("USER role not found"));
Set<Role> authorities = new HashSet<>();
authorities.add(userRole);
ApplicationUser u = new ApplicationUser();
u.setUsername(email);
u.setEmail(email);
if (name != null) {
String[] nameParts = name.split(" ", 2);
u.setFirstName(nameParts[0]);
if (nameParts.length > 1) {
u.setLastName(nameParts[1]);
}
}
u.setPassword(passwordEncoder.encode(UUID.randomUUID().toString()));
u.setAuthorities(authorities);
return userRepository.save(u);
});
OAuth2Provider provider = new OAuth2Provider(
"google",
googleId,
user,
email,
name
);
oauth2ProviderRepository.save(provider);
return user;
}
private Authentication createAuthenticationFromUser(ApplicationUser user) {
List<SimpleGrantedAuthority> authorities = user.getAuthorities().stream()
.map(role -> {
String authority = role.getAuthority();
if (!authority.startsWith("ROLE_")) {
authority = "ROLE_" + authority;
}
return new SimpleGrantedAuthority(authority);
})
.collect(Collectors.toList());
return new UsernamePasswordAuthenticationToken(
user.getUsername(),
null,
authorities
);
}
}