| name | use-passport |
| description | econo-passport(com.github.JNU-econovation:econo-passport)를 현재 Spring Boot MVC 서비스에 통합한다.
의존성 추가 → PassportArgumentResolver 설정 → @PassportAuth 사용 예시 → 테스트 헬퍼까지 한 번에 처리.
다음 상황에서 반드시 이 스킬을 사용한다:
- "passport 연동해줘", "econo-passport 추가해줘", "@PassportAuth 쓰고 싶어"
- "X-User-Passport 헤더 처리", "Gateway 인증 연동", "멤버 정보 받고 싶어"
- "이름/기수 받고 싶어", "Passport 주입 안 돼"
- "/use-passport" 직접 호출
|
use-passport
전제 조건
이 스킬은 서비스가 api-gateway 뒤에서 실행될 때 동작한다.
Gateway가 JWT를 검증하고 X-User-Passport 헤더를 자동으로 주입한다.
직접 노출된 서비스에서는 X-User-Passport 헤더가 없으므로 동작하지 않는다.
Step 1. 프로젝트 파악
다음 파일을 읽어서 현재 상태를 파악한다:
- build.gradle.kts (루트 또는 모듈)
- src/main/java 아래 최상위 패키지 구조
- 기존 Config 파일 (glob: src/main/java/**/*Config.java)
파악할 것:
- JitPack 저장소가 있는가?
com.github.JNU-econovation:econo-passport 의존성이 있는가?
spring-boot-starter-web이 있는가?
@EnableWebMvc가 있는가? ← 핵심 분기점
- 최상위 패키지명
Step 2. build.gradle.kts 업데이트
JitPack이 없는 경우
repositories {
mavenCentral()
maven("https://jitpack.io")
}
의존성이 없는 경우
dependencies {
implementation("com.github.JNU-econovation:econo-passport:1.0.3")
}
주의: spring-boot-starter-web이 없는 Reactive 서비스에서는 @PassportAuth가 동작하지 않는다.
Step 3. PassportArgumentResolver 등록
케이스 A — @EnableWebMvc 없음 (Spring Boot AutoConfiguration 동작)
spring-boot-starter-web이 있으면 자동 등록. Skip.
케이스 B — @EnableWebMvc 있음 ← 주의!
@EnableWebMvc가 있으면 Spring Boot AutoConfiguration이 비활성화된다.
기존 WebMvcConfig(또는 @EnableWebMvc가 붙은 @Configuration 클래스)에 직접 등록:
@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private PassportArgumentResolver passportArgumentResolver;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(passportArgumentResolver);
}
}
또는 별도 Config 클래스로 수동 등록:
@Configuration
@Import(AuthAutoConfiguration.class)
public class PassportConfig {}
⚠️ ROLE_ 접두사 주의
Spring Security의 hasAnyRole("ADMIN")은 내부적으로 ROLE_ADMIN을 찾는다.
econo-passport의 requiredRoles = "ADMIN"은 roles 리스트에서 "ADMIN" 문자열을 직접 비교한다.
Gateway의 PassportTokenCustomizer가 어떤 roles 값을 넣는지 확인 후 맞춰야 한다.
Step 4. 예시 코드 출력
ARGUMENTS로 컨트롤러 이름이 주어졌으면 그 이름을 사용하고, 없으면 ExampleController로 출력한다.
기본 주입
@GetMapping("/api/something")
public ResponseEntity<?> getSomething(@PassportAuth Passport passport) {
Long memberId = passport.getMemberId();
String name = passport.getName();
int generation = passport.getGeneration();
String status = passport.getStatus();
return ResponseEntity.ok(service.get(memberId));
}
권한 체크
@GetMapping("/api/admin/something")
public ResponseEntity<?> adminOnly(
@PassportAuth(requiredRoles = "ADMIN") Passport passport) {
return ResponseEntity.ok(service.adminGet(passport.getMemberId()));
}
@GetMapping("/api/public/something")
public ResponseEntity<?> publicEndpoint(
@PassportAuth(required = false) Passport passport) {
if (passport != null) {
return ResponseEntity.ok(service.getForMember(passport.getMemberId()));
}
return ResponseEntity.ok(service.getPublic());
}
Passport 주요 메서드
passport.getMemberId()
passport.getLoginId()
passport.getName()
passport.getGeneration()
passport.getStatus()
passport.getRoles()
passport.isAdmin()
passport.isActive()
passport.isMember(Long id)
passport.canAccessMember(Long id)
Step 5. 테스트 헬퍼
MockMvc 테스트에서 X-User-Passport 헤더를 직접 주입한다.
import com.econo.common.auth.core.passport.Passport;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Base64;
import java.util.List;
public static String mockPassportHeader(Long memberId, String... roles) throws Exception {
Passport passport = new Passport(
memberId,
"testuser",
"테스트유저",
30,
"AM",
List.of(roles.length > 0 ? roles : new String[]{"USER"}),
LocalDateTime.now(),
LocalDateTime.now().plusHours(1)
);
String json = new ObjectMapper()
.registerModule(new JavaTimeModule())
.writeValueAsString(passport);
return Base64.getEncoder().encodeToString(json.getBytes(StandardCharsets.UTF_8));
}
mockMvc.perform(get("/api/programs")
.header("X-User-Passport", mockPassportHeader(1L)))
.andExpect(status().isOk());
mockMvc.perform(get("/api/admin/users")
.header("X-User-Passport", mockPassportHeader(1L, "ADMIN")))
.andExpect(status().isOk());
Step 6. 인증 흐름 안내
클라이언트 (at 쿠키 또는 Authorization: Bearer)
↓
api-gateway
JWT 검증(JWKS) → Passport 구성 → X-User-Passport: Base64(JSON)
removeRequestHeader("Authorization")
↓
이 서비스 (econo-passport)
PassportArgumentResolver → X-User-Passport 파싱
→ @PassportAuth Passport passport 주입
보안: 이 서비스는 반드시 Gateway 뒤에서만 실행해야 한다.
완료 체크리스트