이전 내용
[Java] Spring Boot: 카카오 로그인 기능 추가하기
이전 내용 [Java] Spring Boot: 구글 로그인 기능 추가하기이전 내용 전반적인 순서1. Gradle 또는 Maven 의존성 추가2. 구글 API Console 설정 - 구글 개발자 콘솔 프로젝트 생성 → OAuth 2.0 클라이언트 ID 생성
puppy-foot-it.tistory.com
네이버 로그인 구현하기
이전에 구글과 카카오 로그인 기능을 구현했으므로, 이번에는 네이버 로그인 기능을 구현해 본다.
네이버 로그인 관련 정보는 네이버 디벨로퍼에서 상세한 정보를 얻을 수 있다.
먼저 Naver Developers에서 Application - Application 등록 클릭
애플리케이션 이름을 넣고, 사용 API를 체크하고 (본인 환경에 맞게)
서비스 환경은 필자의 경우 웹사이트이므로 PC웹을 선택하고, 서비스 URL과 네이버로그인 콜백URL(Redirect URI)를 입력하고, 밑에 동의항목을 체크한 후 [등록하기] 클릭
이 과정을 거치면 네이버의 Client ID와 Client Secret 이 생성된다. 보안을 유지하며 잘 보관한다.
application.properties 작성하기
그리고 IDE(필자의 경우 인텔리제이)로 돌아와서 application.properties에 해당 내용을 추가한다.
spring.security.oauth2.client.registration.naver.client-id= [네이버 클라이언트 ID]
spring.security.oauth2.client.registration.naver.client-secret= [네이버 클라이언트 SecretKey]
spring.security.oauth2.client.registration.naver.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.naver.redirect-uri=https://localhost:9091/login/oauth2/code/naver
spring.security.oauth2.client.registration.naver.scope=[사용 API 범위]
spring.security.oauth2.client.registration.naver.authorization-uri=https://nid.naver.com/oauth2.0/authorize
spring.security.oauth2.client.provider.naver.authorization_uri=https://nid.naver.com/oauth2.0/authorize
spring.security.oauth2.client.provider.naver.token_uri=https://nid.naver.com/oauth2.0/token
spring.security.oauth2.client.provider.naver.user-info-uri=https://openapi.naver.com/v1/nid/me
spring.security.oauth2.client.provider.naver.user_name_attribute=response
네이버 로그인 버튼 이미지
다운 및 적용하기
먼저, 하단의 사이트로 이동해서 버튼 이미지를 다운 받는다.
https://developers.naver.com/docs/login/bi/bi.md
압축을 풀고, 사용하고자 하는 이미지를 하나 복사한 후
main/resources/static/img 폴더 내로 이동시킨 뒤 파일명 변경
그리고 oauthLogin.html 파일에 네이버 로그인 버튼을 삽입시켜준다.
<div class = "mb-2">
<a href="/oauth2/authorization/google">
<img src="/img/google.png">
</a>
</div>
<div class = "mb-2">
<a href="/oauth2/authorization/kakao">
<img src="/img/kakao.png">
</a>
</div>
<div class = "mb-2">
<a href="/oauth2/authorization/naver">
<img src="/img/naver.png">
</a>
</div>
그리고나서 OAuth2SuccessHandler 파일의 코드도 수정해주고
package com.example.spro01.config.oauth;
import com.example.spro01.config.jwt.TokenProvider;
import com.example.spro01.domain.RefreshToken;
import com.example.spro01.domain.User;
import com.example.spro01.repository.RefreshTokenRepository;
import com.example.spro01.service.UserService;
import com.example.spro01.util.CookieUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
import java.io.IOException;
import java.time.Duration;
import java.util.Map;
@RequiredArgsConstructor
@Component
public class OAuth2SuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
public static final String REFRESH_TOKEN_COOKIE_NAME = "refreshToken";
public static final long REFRESH_TOKEN_DURATION = Duration.ofDays(14).toMillis();
public static final long ACCESS_TOKEN_DURATION = Duration.ofDays(1).toMillis();
public static final String REDIRECT_PATH = "/articles";
private final TokenProvider tokenProvider;
private final RefreshTokenRepository refreshTokenRepository;
private final OAuth2AuthorizationRequestBasedOnCookieRepository authorizationRequestRepository;
private final UserService userService;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
OAuth2User oAuth2User = (OAuth2User) authentication.getPrincipal();
// 사용자 이메일 추출
String email = null;
// 카카오 계정에서 이메일 추출
if (oAuth2User.getAttributes().containsKey("kakao_account")) {
Map<String, Object> kakaoAccount = (Map<String, Object>) oAuth2User.getAttributes().get("kakao_account");
if (kakaoAccount != null) {
email = (String) kakaoAccount.get("email");
}
}
// 구글 계정에서 이메일 추출
else if (oAuth2User.getAttributes().containsKey("email")) {
email = (String) oAuth2User.getAttributes().get("email");
}
// 네이버 계정에서 이메일 추출
else if (oAuth2User.getAttributes().containsKey("response")) {
Map<String, Object> responseAttributes = (Map<String, Object>) oAuth2User.getAttributes().get("response");
email = (String) responseAttributes.get("email");
}
// 이메일이 null인 경우 적절한 예외 처리를 추가할 수 있음
if (email == null) {
// 이메일을 찾을 수 없을 때 처리 로직 추가 (예: 예외 발생)
throw new IllegalArgumentException("Email not found in OAuth2 user attributes");
}
User user = userService.findByEmail(email);
// 리프레시 토큰 생성 -> 저장 -> 쿠키에 저장
String refreshToken = tokenProvider.generateToken(REFRESH_TOKEN_DURATION, user);
saveRefreshToken(user.getId(), refreshToken);
addRefreshTokenToCookie(request, response, refreshToken);
// 액세스 토큰 생성 -> 패스에 액세스 토큰 추가
String accessToken = tokenProvider.generateToken(ACCESS_TOKEN_DURATION, user);
String targetUrl = getTargetUrl(accessToken);
// 인증 관련 설정값, 쿠키 제거
clearAuthenticationAttributes(request, response);
// 리다이렉트
getRedirectStrategy().sendRedirect(request, response, targetUrl);
}
// 생성된 리프레시 토큰을 전달받아 데이터베이스에 저장
private void saveRefreshToken(Long userId, String newRefreshToken) {
RefreshToken refreshToken = refreshTokenRepository.findByUserId(userId)
.map(entity -> entity.update(newRefreshToken))
.orElse(new RefreshToken(userId, newRefreshToken));
refreshTokenRepository.save(refreshToken);
}
// 생성된 리프레시 토큰을 쿠키에 저장
private void addRefreshTokenToCookie(HttpServletRequest request, HttpServletResponse response, String refreshToken) {
int cookieMaxAge = (int) REFRESH_TOKEN_DURATION;
CookieUtil.deleteCookie(request, response, REFRESH_TOKEN_COOKIE_NAME);
CookieUtil.addCookie(response, REFRESH_TOKEN_COOKIE_NAME, refreshToken, cookieMaxAge);
}
// 인증 관련 설정값, 쿠키 제거
private void clearAuthenticationAttributes(HttpServletRequest request, HttpServletResponse response) {
super.clearAuthenticationAttributes(request);
authorizationRequestRepository.removeAuthorizationRequestCookies(request, response);
}
// 액세스 토큰을 패스에 추가
private String getTargetUrl(String token) {
return UriComponentsBuilder.fromUriString(REDIRECT_PATH)
.queryParam("token", token)
.build()
.toUriString();
}
}
서버를 다시 시작해보면
네이버 로그인이 정상적으로 작동하는 것을 확인할 수 있다.
[참고]
https://notspoon.tistory.com/41
https://developers.naver.com/main/
NAVER DEVELOPERS
다음 내용
'[Java] > Spring Boot' 카테고리의 다른 글
[Java] Spring Boot: 블로그 앱 만들기 (0) | 2025.04.22 |
---|---|
[Java] Spring Boot: 스프링 시큐리티, OAuth2, JWT (0) | 2025.04.21 |
[Java] Spring Boot: 카카오 로그인 기능 추가하기 (1) | 2025.04.21 |
[Java] Spring Boot: 스프링 MVC , 디스패처 서블릿 (0) | 2025.04.19 |
[Java] Spring Boot: ORM, JPA, 하이버네이트 (0) | 2025.04.19 |