
Vue3, Java + Spring boot
vue3-google-login 라이브러리를 이용한 구글 로그인 기능을 만들었다.
각자 등록해둔 설정 값에 따라 url 사용방식은 바뀌겠지만 우선은 글대로 따라하면 될 것 같다.
로그인 token 값과 user 정보를 같이 넘겨받는 로직이다.
Vue3 - Front
<GoogleLogin
:callback="handleGoogleLoginSuccess"
@error="handleError"
class="btn-round-line"
/>
import { GoogleLogin } from 'vue3-google-login'
vue3-google-login 은 로그인 버튼을 기본적으로 지원해주고 라이브러리 자체가 Oauth2 작업을 처리해준다.
컴포넌트만 쓰면 되서 아주 간편하다.
- 구글 로그인 API 호출
// 토큰 값 디코딩
const parseJwt = (token) => {
const base64Url = token.split('.')[1]
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/')
const jsonPayload = decodeURIComponent(
atob(base64)
.split('')
.map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
.join('')
)
return JSON.parse(jsonPayload)
}
// 구글 로그인
const handleGoogleLoginSuccess = async (googleUser) => {
console.log('Google 로그인 성공:', googleUser)
const decoded = parseJwt(googleUser.credential)
console.log('디코딩 정보:', decoded)
const providerId = decoded.sub
const email = decoded.email
const name = decoded.name
$axios
.post(
$apiUrls.auth.userGoogleLogin,
{
idToken: googleUser.credential,
provider: "google",
providerId: providerId,
email,
name,
},
{
headers: {
'Content-Type': 'application/json'
}
}
)
.then((res) => {
console.log("Google 로그인 성공", res.data)
const token = res.data.token;
const user = res.data.user;
localStorage.setItem('token', token) // local 저장 - 쿠키사용
localStorage.setItem('user', JSON.stringify(user)) // local 저장
setAuth(token, user) // 내가 auth.js 만들어 사용하는 것
const redirectPath = route.query.redirectTo || '/'
router.push(redirectPath)
})
.catch((err) => {
console.error("Google 로그인 실패", err)
})
};
vue3-google-login 라이브러리 팝업을 통해 로그인을 하면 바로 토큰 값이 넘어온다.
토큰 값을 디코딩 후 정보를 Json 형태로 서버에 전달한다.
전달 후 token , user 정보를 localStoriage에 세팅한다. -> 쿠키에 저장되서 사용
JAVA + Spring boot - Backend
- Controller
@PostMapping("/login/google")
public ResponseEntity<?> googleLogin(@RequestBody Map<String, String> body) {
String idToken = body.get("idToken");
if (idToken == null || idToken.isEmpty()) {
return ResponseEntity.badRequest().body(Map.of("message", "idToken is required"));
}
Map<String, Object> loginResult = authService.googleLogin(body);
return ResponseEntity.status(HttpStatus.OK).body(loginResult);
}
클라이언트에서 전달 받은 token 값을 통해 데이터 가공 후 클라이언트로 해당 정보를 다시 전달한다.
Oauth 2 를 통한 구글 로그인과 다르게 body 에 담아 보내기만 하면 되서 훨씬 간편하다.
원래는 getMapping을 하지만 나는 user정보도 포함해서 넘겨주기 위해 postMapping을 사용했다.
- Service
public Map<String, Object> googleLogin(Map<String, String> body) {
String idToken = body.get("idToken");
// 구글 토큰 검증
GoogleUserEntity googleUser = googleTokenVerifier.verify(idToken);
if (googleUser == null) {
throw new RuntimeException("Invalid Google token");
}
// 유저 생성 - 중복 체크
Optional<UserEntity> userOptional = userRepository.findByProviderAndProviderId(
googleUser.getProvider(),
googleUser.getProviderId()
);
UserEntity user;
if (userOptional.isPresent()) {
user = userOptional.get();
// 가입된 사용자일 경우 마지막 로그인 일시 업데이트 추가
userRepository.updateLastLoginDt(user.getUserId(), LocalDateTime.now());
} else {
// 이메일 중복 확인
boolean emailExists = userRepository.existsByEmail(googleUser.getEmail());
if (emailExists) {
throw new RuntimeException("이미 가입된 이메일입니다.");
}
// 중복 아닐 경우 새로운 사용자 생성
String userId = uniqueKeyGenerator.getUniqueKey(null);
UserEntity newUser = UserEntity.builder()
.userId(userId)
.provider(googleUser.getProvider())
.providerId(googleUser.getProviderId())
.email(googleUser.getEmail())
.userNm(googleUser.getName())
.createdAt(LocalDateTime.now())
.withdrawalDt(null)
.build();
user = userRepository.save(newUser);
//사용자 생성 후 가입메일 발송
boolean mailResult = mailComponent.sendMailBySingUp(user.getEmail(), user.getUserNm());
if(mailResult) {
userRepository.updateMailSendYn(userId, "Y");
}
}
// JWT 토큰 생성
String jwtToken = jwtTokenProvider.generateToken(googleUser);
return Map.of(
"token", jwtToken,
"user", user
);
}
Token 값 검증
-> 유저생성 -> 중복 체크
-> JWT 토큰 생성
-> 클라이언트 전달
- GoogleTokenVerifier
@Component
public class GoogleTokenVerifier {
private final GoogleIdTokenVerifier verifier;
private final String clientId = ""; // 구글 인증 클라이언트 ID
public GoogleTokenVerifier() {
verifier = new GoogleIdTokenVerifier.Builder(
new NetHttpTransport(),
GsonFactory.getDefaultInstance()
)
.setAudience(Collections.singletonList(clientId))
.build();
}
public GoogleUserEntity verify(String idTokenString) {
try {
GoogleIdToken idToken = verifier.verify(idTokenString);
if (idToken != null) {
GoogleIdToken.Payload payload = idToken.getPayload();
String provider = "google";
String providerId = payload.getSubject();
String email = payload.getEmail();
String name = (String) payload.get("name");
return new GoogleUserEntity(provider, providerId, email, name);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
구글 클라이언트 ID를 통해 verifier 를 세팅해준다.
Service 에서 넘겨 받은 tokenString 값으로 해당 토큰값이 구글에 등록 된 값과 일치하는지 비교 후 정보를 담아 return 한다.
GoogleUserEntity 는 google Login 정보를 담을 Entity.
- JwtTokenProvider
@Component
public class JwtTokenProvider {
// JWT 서명 키 - 문자열 복호화해서 시크릿키로 변환
private final SecretKey SECRET_KEY = Keys.hmacShaKeyFor(
java.util.Base64.getDecoder().decode("Base64 인코딩한 문자열")
);
// JWT 만료 시간 설정
private final long EXPIRATION = 1000L * 60 * 60 * 24;
// JWT 에 담길 정보
public String generateToken(GoogleUserEntity user) {
return Jwts.builder()
.setSubject(user.getEmail())
// .claim("userId", user.getUserId())
.claim("name", user.getName())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
.signWith(SECRET_KEY, SignatureAlgorithm.HS256)
.compact();
}
}
상세한 설정과 보안이 중요하다면 라이브러리가 아닌 Oauth 2.0 + google play console 을 이용하는게 좋다.
[JAVA] Vue3 + Spring boot : Oauth2.0 Google 로그인 기능 만들기
Vue3, Java + Spring bootOauth 2.0, Google play console 을 이용한 구글 로그인 기능을 만들었다. 각자 등록해둔 설정 값에 따라 url 사용방식은 바뀌겠지만 우선은 글대로 따라하면 될 것 같다. - Oauth 2.0, Google
devel-log.tistory.com
'JAVA > Spring' 카테고리의 다른 글
| [JAVA] Vue3 + Spring boot : Oauth2.0 Google 로그인 기능 만들기 (1) | 2025.08.28 |
|---|---|
| [JAVA] find image file size - File 이미지 크기(가로X세로) 구하기 (0) | 2024.01.10 |
| [JAVA] 이미지 URL 변환 후 화면에 보여주기(가져오기) (feat.미리보기) (0) | 2024.01.09 |
| [Spring] boot 에서 JWT 인증 토큰 생성 및 사용하기 (0) | 2023.12.01 |
| [Spring] Multi module - 모듈 별 application.yml 파일 환경 설정 및 관리하는 방법 (0) | 2023.12.01 |