Skip to content

Conversation

@geniusYoo
Copy link
Contributor

@geniusYoo geniusYoo commented Jun 19, 2025

Related issue 🛠

Work Description ✏️

인증 중앙화로 인해 변경되는 코드들, 노가다 작업 전 베이스 코드를 회의에서 같이 작업했어요.

initial setting

1. 가이드라인 프로젝트 코드 추가

기존 플랫폼 팀에서 제공해주신 가이드라인 코드를 추가했어요.
한 가지 수정 사항이 있다면, jwt를 파싱할 때 Bearer를 substring 하지않고 그대로 사용하도록 변경했어요. (앱팀 클라이언트와 협의 완료)

public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final JwtAuthenticationService jwtAuthenticationService;
    private static final String ACCESS_TOKEN_PREFIX = "Bearer ";

    @Override
    protected void doFilterInternal(
            @NonNull HttpServletRequest request,
            @NonNull HttpServletResponse response,
            @NonNull FilterChain filterChain)
            throws ServletException, IOException {

        String authorizationToken = getAuthorizationToken(request);

       // 비회원 처리
        if (authorizationToken != null) {
            MakersAuthentication authentication = jwtAuthenticationService.authenticate(authorizationToken);
            authentication.setAuthenticated(true);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        filterChain.doFilter(request, response);
    }

    // Bearer 파싱 없이 Authorization 헤더의 값 그대로 전달
    private String getAuthorizationToken(final HttpServletRequest request) {
        return request.getHeader(HttpHeaders.AUTHORIZATION);
    }
}

2. 에러 코드 및 커스텀 예외 추가

커스텀 예외로는 ClientException, JwkException, JwtException
에러 코드는 아래와 같이 추가했어요.

    // AUTH_CLIENT
    RESPONSE_ERROR("외부 서버 응답 오류", HttpStatus.INTERNAL_SERVER_ERROR),
    COMMUNICATION_ERROR("외부 서버 통신 실패", HttpStatus.INTERNAL_SERVER_ERROR),

    // AUTH_JWK
    JWK_KID_NOT_FOUND("해당 kid에 대한 공개키를 찾을 수 없습니다.", HttpStatus.UNAUTHORIZED),
    JWK_INVALID_FORMAT("JWK 형식이 잘못되어 공개키를 파싱할 수 없습니다.", HttpStatus.BAD_REQUEST),
    JWK_FETCH_FAILED("JWK 서버로부터 키를 가져오지 못했습니다.", HttpStatus.INTERNAL_SERVER_ERROR),

    // AUTH_JWT
    JWT_MISSING_AUTH_HEADER("인증 헤더가 존재하지 않습니다.", HttpStatus.UNAUTHORIZED),
    JWT_PARSE_FAILED("잘못된 형식의 JWT입니다.", HttpStatus.UNAUTHORIZED),
    JWT_INVALID_CLAIMS("JWT의 클레임이 유효하지 않습니다.", HttpStatus.UNAUTHORIZED),
    JWT_VERIFICATION_FAILED("JWT 검증에 실패했습니다.", HttpStatus.UNAUTHORIZED),

3. 응답 dto 추가

플랫폼 internal API로 받아오는 유저 정보 응답 dto와 wrapper를 추가했어요.
wrapper에는 같이 응답으로 오는 status, message를 무시하기 위해 @JsonIgnoreProperties를 사용했어요.

@JsonIgnoreProperties(ignoreUnknown = true)
public record PlatformUserInfoWrapper(
        List<PlatformUserInfoResponse> data
) {}

public record PlatformUserInfoResponse(
        int userId,
        String name,
        String profileImage,
        String birthday,
        String phone,
        String email,
        int lastGeneration,
        List<SoptActivities> soptActivities
) {
    public record SoptActivities(
            int activityId,
            int generation,
            String part,
            String team
    ){
    }
}

4. internal API 엔드포인트

internal API 요청을 위한 FeignClient 엔드포인트를 작성했어요.
플랫폼 팀의 유저 정보 조회 API 명세에 따라, 동적 쿼리 파라미터로 유저 아이디를 추가해 요청할 수 있도록 @QueryMap을 사용했어요.

    @RequestLine("GET /api/v1/users")
    PlatformUserInfoWrapper getPlatformUserInfo(@HeaderMap final Map<String, String> headers,
                                                @QueryMap Map<String, Collection<String>> queryMap);

key changes

1. api changes

  • @AuthenticationPrincipaluserId를 파싱하도록 했어요.
  • 유저 정보 중 userId만을 SecurityContextHolder에 저장하기 때문에, 이름을 얻기 위해 Internal API를 사용하는 코드를 추가해 이름을 받아왔어요.
    @GetMapping("/word")
    public ResponseEntity<FortuneResponse> getFortune(
            @AuthenticationPrincipal Long userId,
            @DateTimeFormat(pattern = "yyyy-MM-dd")
            @RequestParam(name = "todayDate") LocalDate todayDate
    ) {
        return ResponseEntity.ok(
                FortuneResponse.of(
                        fortuneService.getTodayFortuneWordByUserId(userId, todayDate),
                        platformService.getPlatformUserInfoResponse(userId).name()
                )
        );
    }

2. internal API Service

  • 단일, 다중 유저 정보 조회를 위해 createQueryParams로 동적으로 파라미터를 생성해 요청하도록 했어요.
  • 단일 조회의 경우에는 getFirst로 첫번째 것을 가져오도록 했어요.
  • 요청 시에는 x-api-keyx-service-name을 시크릿에서 주입받아 헤더로 세팅하도록 했어요.
public class PlatformService {

    private final PlatformClient platformClient;

    @Value("${external.auth.api-key}")
    private String apiKey;

    @Value("${external.auth.service-name}")
    private String serviceName;

    public PlatformUserInfoResponse getPlatformUserInfoResponse(Long userId) {
        final Map<String, String> headers = createAuthorizationHeader();
        final Map<String, Collection<String>> params = createQueryParams(Collections.singletonList(userId));
        PlatformUserInfoWrapper platformUserInfoWrapper = platformClient.getPlatformUserInfo(headers, params);
        return platformUserInfoWrapper.data().getFirst();
    }

    public List<PlatformUserInfoResponse> getPlatformUserInfosResponse(List<Long> userIds) {
        final Map<String, String> headers = createAuthorizationHeader();
        final Map<String, Collection<String>> params = createQueryParams(userIds);
        PlatformUserInfoWrapper platformUserInfoWrapper = platformClient.getPlatformUserInfo(headers, params);
        return platformUserInfoWrapper.data();
    }

    private Map<String, String> createAuthorizationHeader() {
        Map<String, String> headers = new HashMap<>();
        headers.put("x-api-key", apiKey);
        headers.put("x-service-name", serviceName);
        return headers;
    }

    private Map<String, Collection<String>> createQueryParams(List<Long> userId) {
        Map<String, Collection<String>> queryParams = new HashMap<>();
        for (Long id : userId) {
            queryParams.put("userIds", Collections.singletonList(id.toString()));
        }
        return queryParams;
    }
}

Trouble Shooting ⚽️

Related ScreenShot 📷

Uncompleted Tasks 😅

To Reviewers 📢

@height
Copy link

height bot commented Jun 19, 2025

Link Height tasks by mentioning a task ID in the pull request title or commit messages, or description and comments with the keyword link (e.g. "Link T-123").

💡Tip: You can also use "Close T-X" to automatically close a task when the pull request is merged.

@geniusYoo geniusYoo changed the base branch from dev to auth-integration June 19, 2025 10:07
@geniusYoo geniusYoo added the ✨ Feat 새로운 피쳐 생성 label Jun 19, 2025
@hyerinhwang-sailin hyerinhwang-sailin merged commit a99531b into auth-integration Jul 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feat 새로운 피쳐 생성 size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 인증 중앙화 작업

2 participants