Skip to content

Comments

feat(#2): Kakao OAuth2 login#22

Merged
ParkJiYeoung8297 merged 8 commits intodevfrom
feat/2-kakao-login
Jan 19, 2026
Merged

feat(#2): Kakao OAuth2 login#22
ParkJiYeoung8297 merged 8 commits intodevfrom
feat/2-kakao-login

Conversation

@lingard1234
Copy link
Contributor

개요

OAuth2, JWT 기반 카카오 소셜 로그인 기능 구현
카카오 로그인 → redirect → Access Token

목표

  • 카카오 로그인/회원가입
  • 로그인 성공 시 Access Token 발급

구현 내용

  • Kakao OAuth2 연동
  • JWT Access Token 발급
  • Spring Security 인증 객체 등록
  • OAuth2 로그인 완료 후 리다이렉트 동작 테스트용 엔드포인트 구현
  • 자세한 흐름 노션에 정리

동작 흐름

  1. /oauth2/authorization/kakao 호출
  2. 카카오 로그인
  3. /login/oauth2/code/kakao redirect
  4. CustomOAuth2UserService에서 사용자 조회 또는 생성
  5. OAuth2SuccessHandler에서 JWT 발급

테스트 방법

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @lingard1234, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 풀 리퀘스트는 애플리케이션에 카카오 OAuth2 소셜 로그인 기능을 도입합니다. 사용자가 카카오 계정을 통해 간편하게 로그인하고 JWT 기반의 인증 토큰을 발급받아 서비스에 접근할 수 있도록 하여 사용자 경험을 향상시키고 인증 시스템을 확장하는 것이 주된 목적입니다. Spring Security의 OAuth2 기능을 활용하여 안전하고 효율적인 인증 흐름을 구축했습니다.

Highlights

  • 카카오 OAuth2 로그인 기능 추가: Spring Security OAuth2 클라이언트를 활용하여 카카오 소셜 로그인 기능을 구현했습니다. 이를 통해 사용자는 카카오 계정으로 서비스에 로그인하거나 회원가입할 수 있습니다.
  • JWT 기반 인증 시스템 연동: OAuth2 로그인 성공 시 JWT(Access Token 및 Refresh Token)를 발급하도록 OAuth2SuccessHandler를 구현했습니다. 발급된 토큰은 이후 API 요청에 사용됩니다.
  • 사용자 정보 관리: 카카오로부터 받은 사용자 정보를 기반으로 User 엔티티를 생성하거나 업데이트하는 CustomOAuth2UserService를 구현하여 사용자 데이터를 관리합니다.
  • 보안 설정 업데이트: Spring Security 설정(SecurityConfig)을 업데이트하여 OAuth2 로그인 흐름을 통합하고, JWT 인증 필터(JwtAuthenticationFilter)에서 OAuth2 관련 경로를 제외하도록 수정했습니다.
  • 의존성 및 JWT 라이브러리 조정: build.gradlespring-boot-starter-oauth2-client 의존성을 추가하고, JWT 라이브러리 버전(0.12.3)을 통일하며 jjwt-impljjwt-jackson의 스코프를 runtimeOnly로 변경했습니다.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

카카오 OAuth2 로그인을 구현하신 것을 확인했습니다. Spring Security와 JWT를 활용한 전반적인 흐름은 잘 구성되어 있습니다. 다만, 몇 가지 개선점을 제안합니다. JWT 라이브러리 버전을 최신으로 업데이트하고, 하드코딩된 URL들을 외부 설정으로 분리하는 것이 좋습니다. 또한, JWT 필터의 경로 문제와 사용자 프로필 업데이트 로직의 버그를 수정하고, 데이터베이스 스키마의 확장성을 고려한 변경을 제안합니다. 불필요해 보이는 테스트 파일도 정리하는 것이 좋겠습니다. 자세한 내용은 각 파일에 남긴 코멘트를 참고해주세요.

"/oauth2/",
"/login/oauth2/",
"/oauth/callback",
"/api/v1/test",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

JWT 검증을 건너뛸 경로 목록(EXCLUDED_PATHS)에 /api/v1/test가 포함되어 있습니다. 하지만 TestController/api/test 경로에 매핑되어 있으므로, 현재 설정으로는 의도한 대로 JWT 검증을 건너뛰지 못합니다. 경로를 /api/test로 수정해야 합니다.

Suggested change
"/api/v1/test",
"/api/test",

Comment on lines +51 to +53
implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.3'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

JWT 라이브러리 jjwt의 버전을 0.12.3으로 사용하고 계십니다. 현재 최신 안정 버전은 0.12.5입니다. 특별한 이유가 없다면, 알려진 취약점이 없고 최신 기능 및 버그 수정이 포함된 최신 버전으로 업데이트하는 것을 권장합니다.

	implementation 'io.jsonwebtoken:jjwt-api:0.12.5'
	runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.5'
	runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.5'

.successHandler(oAuth2SuccessHandler)
.failureHandler((request, response, exception) -> {
log.error("OAuth2 login failed", exception);
response.sendRedirect("/api/test?error=" + exception.getMessage());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

OAuth2 로그인 실패 시 리다이렉트되는 경로가 /api/test로 하드코딩되어 있습니다. 이 또한 성공 핸들러의 URL과 마찬가지로, 설정 파일(application.yml 등)을 통해 관리하여 유연성을 높이는 것을 권장합니다.

configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(List.of("*"));
configuration.setAllowCredentials(true); // 쿠키/인증정보 포함 요청
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000", "http://localhost:8080"));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

CORS 허용 origin이 http://localhost:3000, http://localhost:8080으로 하드코딩되어 있습니다. 개발 환경에서는 괜찮지만, 향후 배포 환경(staging, production)이 달라질 것을 대비하여 이 값들을 application.yml 같은 설정 파일로 분리하여 관리하는 것이 좋습니다. 이렇게 하면 환경마다 다른 설정을 유연하게 적용할 수 있습니다.

Comment on lines +47 to +50
String redirectUrl = String.format("http://localhost:8080/api/login/success?accessToken=%s&refreshToken=%s",
URLEncoder.encode(accessToken, StandardCharsets.UTF_8),
URLEncoder.encode(refreshToken, StandardCharsets.UTF_8)
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

로그인 성공 후 리다이렉트 URL이 http://localhost:8080/api/login/success로 하드코딩되어 있습니다. 주석에 언급하신 대로 이 부분은 프론트엔드 주소로 변경되어야 하며, 개발/운영 환경에 따라 달라질 수 있으므로 application.yml 같은 설정 파일에서 값을 주입받아 사용하는 것이 유지보수 및 확장성 측면에서 바람직합니다. 57번째 줄의 에러 리다이렉트 URL도 마찬가지입니다.

Comment on lines +62 to +65
if (email != null && !email.equals(user.getEmail())) {
user.updateProfile(email, name);
userRepository.save(user);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

현재 로직은 사용자의 이메일이 기존과 다를 경우에만 프로필 정보(이메일, 이름)를 업데이트합니다. 만약 사용자가 카카오에서 닉네임만 변경했다면, 우리 서비스의 사용자 이름이 업데이트되지 않는 문제가 발생합니다. 이름이나 이메일 중 하나라도 변경되었다면 프로필을 업데이트하도록 조건을 수정하는 것이 좋습니다.

Suggested change
if (email != null && !email.equals(user.getEmail())) {
user.updateProfile(email, name);
userRepository.save(user);
}
if ((email != null && !email.equals(user.getEmail())) || (name != null && !name.equals(user.getName()))) {
user.updateProfile(email, name);
userRepository.save(user);
}

@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(nullable = false, unique = true)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

providerId 필드에 unique = true 제약조건이 설정되어 있습니다. 현재는 카카오 로그인만 지원하지만, 추후 다른 OAuth2 프로바이더(예: Google, Naver)를 추가할 경우 다른 프로바이더의 사용자와 providerId가 겹칠 수 있습니다. 이를 방지하기 위해, 이 필드의 unique = true를 제거하고, User 엔티티 클래스 상단에 @Table(uniqueConstraints = @UniqueConstraint(columnNames = {"providerId", "provider"})) 어노테이션을 추가하여 providerIdprovider의 조합이 유니크하도록 복합 유니크 키를 설정하는 것을 강력히 권장합니다.

Suggested change
@Column(nullable = false, unique = true)
@Column(nullable = false)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

provider id unique 추가해주세요

Comment on lines +1 to +13
package com.example.RealMatch.test;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

@GetMapping("/success")
public String success() {
return "KAKAO LOGIN SUCCESS";
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

이 테스트 컨트롤러는 OAuth2 로그인 성공 후 리다이렉션을 테스트하기 위해 추가된 것으로 보입니다. 하지만 src/main/java/com/example/RealMatch/global/controller/TestController.java에 이미 /api/login/success라는 거의 동일한 목적의 테스트용 엔드포인트가 구현되어 있습니다. 또한 이 컨트롤러의 /success 경로는 SecurityConfig에 허용되지 않아 접근이 차단됩니다. 중복되고 현재 사용되지 않는 코드로 보이므로 삭제하는 것을 고려해 보세요.

@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(nullable = false, unique = true)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

provider id unique 추가해주세요

@Column(nullable = false)
private String provider; // kakao

private String email;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이메일도 nullable로 해주세요

@ParkJiYeoung8297 ParkJiYeoung8297 merged commit 399ef55 into dev Jan 19, 2026
1 check passed
@ParkJiYeoung8297 ParkJiYeoung8297 deleted the feat/2-kakao-login branch January 19, 2026 07:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants