package com.takensoft.common.service; import com.takensoft.cms.mber.vo.MberVO; import com.takensoft.common.exception.CustomAccessDeniedException; import com.takensoft.common.util.JWTUtil; import lombok.RequiredArgsConstructor; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpSession; import jakarta.servlet.http.Cookie; /** * @author takensoft * @since 2025.01.22 * @modification * since | author | description * 2025.01.22 | takensoft | 최초 등록 * * 사용자 검증 서비스 */ @Service("authorizationService") @RequiredArgsConstructor public class VerificationService { private final JWTUtil jwtUtil; /** * @return 현재 인증된 사용자 정보 * @throws CustomAccessDeniedException 인증되지 않은 경우 예외 발생 * * 현재 로그인된 사용자를 가져오는 공통 메서드 */ private MberVO getAuthenticatedUser() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if(authentication == null || !authentication.isAuthenticated()) { throw new CustomAccessDeniedException("접근 권한이 없습니다."); } Object principal = authentication.getPrincipal(); if(!(principal instanceof MberVO)) { throw new CustomAccessDeniedException("접근 권한이 없습니다."); } return (MberVO) principal; } /** * @param targetUserId 접근하려는 사용자 ID * @throws CustomAccessDeniedException - 접근 권한이 없을 경우 예외 발생 * * 특정 사용자 ID에 대한 접근 권한 검증 */ public void verifyAccess(String targetUserId) { MberVO user = getAuthenticatedUser(); // 관리자 권한 여부 boolean isAdmin = user.getAuthorList().stream() .anyMatch(auth -> "ROLE_ADMIN".equals(auth.getAuthrtCd())); // 본인 여부 boolean isOwner = user.getMbrId().equals(targetUserId); if(!isAdmin && !isOwner) { throw new CustomAccessDeniedException("접근 권한이 없습니다."); } } /** * @return 관리자 여부(true, false) * * 관리자 여부 검증 */ public boolean verifyAdmin() { MberVO user = getAuthenticatedUser(); // 관리자 권한 여부 반환 return user.getAuthorList().stream() .anyMatch(auth -> "ROLE_ADMIN".equals(auth.getAuthrtCd())); } /** * @return 현재 로그인된 사용자 ID * * 로그인된 사용자 아이디 반환 * - 등록자, 수정자 입력 시 사용 */ public String getCurrentUserId() { String userId = null; try { // 1. SecurityContext에서 시도 Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if(authentication != null && authentication.isAuthenticated()) { Object principal = authentication.getPrincipal(); if(principal instanceof MberVO) { userId = ((MberVO) principal).getMbrId(); } } // 2. SecurityContext에서 조회 실패시 세션에서 직접 조회 if (userId == null) { try { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); HttpServletRequest request = attributes.getRequest(); HttpSession session = request.getSession(false); if (session != null) { userId = (String) session.getAttribute("mbrId"); } } catch (Exception e) { e.printStackTrace(); } } // 3. JWT 토큰에서 조회 시도 (JWT 모드인 경우) if (userId == null) { try { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // Authorization 헤더에서 토큰 추출 String authHeader = request.getHeader("Authorization"); String token = null; if (authHeader != null && authHeader.startsWith("Bearer ")) { token = authHeader.substring(7); } else if (request.getCookies() != null) { // 쿠키에서 토큰 추출 for (Cookie cookie : request.getCookies()) { if ("Authorization".equals(cookie.getName()) || "refresh".equals(cookie.getName())) { token = cookie.getValue(); if (token.startsWith("Bearer ")) { token = token.substring(7); } break; } } } if (token != null && jwtUtil != null) { userId = (String) jwtUtil.getClaim(token, "mbrId"); } } catch (Exception e) { e.printStackTrace(); } } } catch (Exception e) { e.printStackTrace(); } return userId; } }