본문 바로가기

개발

[Spring Cloud Gateway] module-admin

admin 체크하는 필터만들고 .yml파일에 이어서 적용하려니까 너무 길어지고 복잡하다

모듈들 관리하기 편하라고 GatewayConfig 새로 만들음 

 

apigateway → [GatewayConfig]

@Configuration
public class GatewayConfig {

    @Autowired
    private AdminFilter adminFilter;

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("module-common", r -> r.path("/module-common/**")
                        .uri("lb://MODULE-COMMON"))
                .route("module-admin", r -> r.path("/module-admin/**")
                        .filters(f -> f.filter(adminFilter))
                        .uri("lb://MODULE-ADMIN"))
                .build();
    }
}

 

 

apigateway → [AuthenticationFilter]

Authentication Filter는 Global Filter로 변경해서 특정 예외 경로를 제외하고 전부 필터링할 수 있도록 변경

@Component
@Order(1)
public class AuthenticationFilter implements GlobalFilter {


    private final List<String> excludedPaths = List.of(
            "/eureka",
            "/module-common/auth/login",
            "/module-common/auth/signup",
            "/module-common/auth/find/email",
            "/module-common/auth/email/duplicate",
            "/module-common/auth/phone/find/password",
            "/module-common/auth/kakao/authorize", // <- 이후 컨트롤러와 삭제 필요
            "/module-common/auth/kakao/access",
            "/module-common/auth/kakao/login",
            "/module-common/auth/refresh",
            "/module-common/sms/fake/send",
            "/module-common/sms/verify",
            "/module-admin/admin/login"
            );  // 필터를 적용하지 않을 경로


    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getPath().toString();
        System.out.println("Request Path: " + path);  // 경로를 로그로 확인

        // 로그인 및 회원가입 경로는 JWT 검증하지 않음
        if (excludedPaths.contains(path)) {
            return chain.filter(exchange);
        }

        String authorizationHeader = exchange.getRequest().getHeaders().getFirst("Authorization");

        if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        String token = authorizationHeader.substring(7);

        if (!jwtUtil.validateToken(token)) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

//         로그아웃 체크
        if (jwtUtil.isTokenLogout(token)) {
            throw new UnauthorizedAccessException();
        }

        return chain.filter(exchange);
    }

}

excludePaths 이후에 더 지저분해지면 새로운 파일에 따로 빼야될 듯

 

 

apigateway → [AdminFilter]

@Component
public class AdminFilter implements GatewayFilter {

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getPath().toString();
        System.out.println("path = " + path);

        String authorizationHeader = exchange.getRequest().getHeaders().getFirst("Authorization");

        if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        String token = authorizationHeader.substring(7);
        String role = jwtUtil.getRole(token);
        if (!"ROLE_ADMIN".equals(role)) {
            exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }
}

GatewayFilter를 상속받아서 원하는 곳에만 필터링할 수 있도록 함

 

Claim에서 role을 받아오는 과정에서 Access Token을 발급받을 때 사용하는 CustomUserDetails에서 Collections 타입으로 role을 설정하여 불러오는 과정에서 꽤 귀찮은 과정이 생김

여러가지 role을 설정할 필요는 없을 것 같아서 

 

// getAuthorities()에서 Role을 추출하여 클레임에 설정
        List<String> roles = customUserDetails.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)  // authority 값을 추출
                .collect(Collectors.toList());

        return Jwts.builder()
                .setSubject(customUserDetails.getUsername()) // email
                .claim("user-id", customUserDetails.getId())
                .claim("role", roles.get(0))

role을 get하면 별도의 처리없이 바로 사용할 수 있도록 변경했다.

 

 

 


[module-admin] 실행 Postman 테스트

@RequestMapping("/module-admin/admin")
public class AdminController {

    @PostMapping("/aa")
    private ResponseEntity<?> aabb(){
        System.out.println("들어옴");
        return ResponseEntity.status(HttpStatus.OK).body("aa successfully!");
    }
}

 

 

 

[성공 케이스]

 

[실패 케이스] → Admin이 아닌 일반 user의 액세스 토큰 입력