
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
package com.takensoft.common.oauth.handler;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.takensoft.cms.loginPolicy.service.LoginModeService;
import com.takensoft.cms.loginPolicy.service.LoginPolicyService;
import com.takensoft.cms.mber.service.LgnHstryService;
import com.takensoft.cms.mber.service.MberService;
import com.takensoft.cms.mber.vo.LgnHstryVO;
import com.takensoft.cms.mber.vo.MberAuthorVO;
import com.takensoft.cms.mber.vo.MberVO;
import com.takensoft.cms.token.service.RefreshTokenService;
import com.takensoft.cms.token.vo.RefreshTknVO;
import com.takensoft.common.oauth.vo.CustomOAuth2UserVO;
import com.takensoft.common.util.HttpRequestUtil;
import com.takensoft.common.util.JWTUtil;
import com.takensoft.common.util.SessionUtil;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
@RequiredArgsConstructor
public class OAuth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
private final ApplicationContext applicationContext;
private final JWTUtil jwtUtil;
private final RefreshTokenService refreshTokenService;
private final LgnHstryService lgnHstryService;
private final HttpRequestUtil httpRequestUtil;
private final LoginModeService loginModeService;
private final LoginPolicyService loginPolicyService;
private final SessionUtil sessionUtil;
private final RedisTemplate<String, String> redisTemplate;
@Value("${jwt.accessTime}")
private long jwtAccessTime;
@Value("${jwt.refreshTime}")
private long jwtRefreshTime;
@Value("${cookie.time}")
private int cookieTime;
@Value("${front.url}")
private String frontUrl;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
CustomOAuth2UserVO oAuth2User = (CustomOAuth2UserVO) authentication.getPrincipal();
try {
// MberService를 ApplicationContext에서 가져옴
MberService mberService = applicationContext.getBean(MberService.class);
// OAuth2 사용자 정보로 MberVO 생성 또는 조회
MberVO mber = processOAuth2User(oAuth2User, mberService, request);
// 로그인 이력 저장
saveLoginHistory(request, mber);
// 로그인 모드 확인
String loginMode = loginModeService.getLoginMode();
// 로그인 모드에 따른 처리
if ("S".equals(loginMode)) {
handleSessionMode(request, response, mber);
} else {
handleJwtMode(request, response, mber);
}
// 프론트엔드로 리다이렉트
String redirectUrl = frontUrl + "/login.page?oauth_success=true&loginMode=" + loginMode;
getRedirectStrategy().sendRedirect(request, response, redirectUrl);
} catch (Exception e) {
e.printStackTrace();
handleOAuth2Error(response, e);
}
}
/**
* JWT 모드 처리 - OAuth용 access token 쿠키 추가
*/
private void handleJwtMode(HttpServletRequest request, HttpServletResponse response, MberVO mber) throws IOException {
try {
// JWT 토큰 생성
String accessToken = jwtUtil.createJwt("Authorization",
mber.getMbrId(),
mber.getLgnId(),
mber.getMbrNm(),
(List) mber.getAuthorities(),
jwtAccessTime);
String refreshToken = jwtUtil.createJwt("refresh",
mber.getMbrId(),
mber.getLgnId(),
mber.getMbrNm(),
(List) mber.getAuthorities(),
jwtRefreshTime);
// Refresh 토큰 처리
RefreshTknVO refresh = new RefreshTknVO();
refresh.setMbrId(mber.getMbrId());
if (refreshTokenService.findByCheckRefresh(request, refresh)) {
refreshTokenService.delete(request, refresh);
}
refresh.setToken(refreshToken);
// 헤더와 쿠키 설정
response.setHeader("Authorization", accessToken);
// OAuth 전용 access token 쿠키 생성
Cookie oauthAccessCookie = new Cookie("oauth_access_token", accessToken);
oauthAccessCookie.setPath("/");
oauthAccessCookie.setMaxAge(300); // 5분 후 자동 삭제
oauthAccessCookie.setHttpOnly(false); // 프론트에서 접근 가능하도록
response.addCookie(oauthAccessCookie);
// Refresh 쿠키 생성
Cookie refreshCookie = jwtUtil.createCookie("refresh", refreshToken, cookieTime);
response.addCookie(refreshCookie);
response.setHeader("login-type", "J");
// 중복 로그인 비허용 처리
if (!loginPolicyService.getPolicy()) {
redisTemplate.delete("jwt:" + mber.getMbrId());
redisTemplate.opsForValue().set("jwt:" + mber.getMbrId(), accessToken, jwtAccessTime, TimeUnit.MILLISECONDS);
}
// Refresh 토큰 저장
refreshTokenService.saveRefreshToken(request, response, refresh, jwtRefreshTime);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
/**
* 세션 모드 처리
*/
private void handleSessionMode(HttpServletRequest request, HttpServletResponse response, MberVO mber) {
log.info("세션 모드로 OAuth2 로그인 처리");
// 세션 생성 및 정보 저장
HttpSession session = request.getSession(true);
// 세션에 사용자 정보 저장 (JWT 없이!)
session.setAttribute("mbrId", mber.getMbrId());
session.setAttribute("mbrNm", mber.getMbrNm());
session.setAttribute("lgnId", mber.getLgnId());
session.setAttribute("roles", mber.getAuthorList());
session.setAttribute("loginType", "OAUTH2");
// 중복 로그인 비허용 처리
if (!loginPolicyService.getPolicy()) {
sessionUtil.registerSession(mber.getMbrId(), session);
}
response.setHeader("login-type", "S");
}
/**
* 로그인 이력 저장
*/
private void saveLoginHistory(HttpServletRequest request, MberVO mber) {
try {
String userAgent = httpRequestUtil.getUserAgent(request);
LgnHstryVO loginHistory = new LgnHstryVO();
loginHistory.setLgnId(mber.getLgnId());
loginHistory.setLgnType(mber.getAuthorities().stream()
.anyMatch(r -> r.getAuthority().equals("ROLE_ADMIN")) ? "0" : "1");
loginHistory.setCntnIp(httpRequestUtil.getIp(request));
loginHistory.setCntnOperSys(httpRequestUtil.getOS(userAgent));
loginHistory.setDeviceNm(httpRequestUtil.getDevice(userAgent));
loginHistory.setBrwsrNm(httpRequestUtil.getBrowser(userAgent));
lgnHstryService.LgnHstrySave(loginHistory);
} catch (Exception e) {
log.error("로그인 이력 저장 실패", e);
// 로그인 이력 저장 실패해도 로그인은 계속 진행
}
}
/**
* OAuth2 사용자 처리
*/
private MberVO processOAuth2User(CustomOAuth2UserVO oAuth2User, MberService mberService, HttpServletRequest request) throws JsonProcessingException {
String mbrType = convertProviderToMbrType(oAuth2User.getProvider());
MberVO existingUser = mberService.findByEmailAndProvider(oAuth2User.getEmail(), mbrType);
if (existingUser != null) {
existingUser.setMbrNm(oAuth2User.getName());
return mberService.updateOAuthUser(existingUser);
} else {
MberVO newUser = new MberVO();
newUser.setEml(oAuth2User.getEmail());
newUser.setLgnId(oAuth2User.getEmail().toLowerCase());
newUser.setMbrNm(oAuth2User.getName());
newUser.setNcnm(oAuth2User.getName());
newUser.setMbrType(mbrType);
MberAuthorVO roleUser = new MberAuthorVO();
roleUser.setAuthrtCd("ROLE_USER");
newUser.setAuthorList(Collections.singletonList(roleUser));
return mberService.saveOAuthUser(newUser, request);
}
}
private String convertProviderToMbrType(String provider) {
return switch (provider.toLowerCase()) {
case "kakao" -> "K";
case "naver" -> "N";
case "google" -> "G";
case "facebook" -> "F";
default -> "S";
};
}
private void handleOAuth2Error(HttpServletResponse response, Exception e) throws IOException {
String message = URLEncoder.encode("OAuth 로그인에 실패했습니다.", "UTF-8");
String errorUrl = String.format("%s/login.page?error=oauth2_failed&message=%s", frontUrl, message);
getRedirectStrategy().sendRedirect(null, response, errorUrl);
}
}