Login Servicesの追加[3]Gateway認証


前の記事までにloginトークンを配布しました.これで、ログイン後に他のサービスを使用する場合、Gatewayでトークン値の処理を試み、有効かどうかを確認してから操作を続行します.

🔨任意のサービスの作成

login-servieでは、自身がフィルタでフィルタリングされているため、ゲートウェイで正しくフィルタリングされていることを確認するために、order-serviceが生成されるので、ランダムにサービスが作成され、追加される.

👉サービスの作成



選択したオプションは次のとおりです.
server:
  port: 0

spring:
  application:
    name: order-service
    
eureka:
  instance:
    instance-id: ${spring.application.name}:${spring.application.instance_id:${random.value}}
設定情報を入力します.
configサーバに登録してconfigを使用していない場合はgradleでconfigを注釈して使用します.

@SpringBootApplication
@EnableDiscoveryClient
public class OrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }

}
Eurekaで見つけられるように設定
@RestController
@RequestMapping("/")
public class HelloController {
    @GetMapping("/hello")
    public String hello(){
        return "hello Order Service!";
    }
}
リクエストを

👉ゲートウェイ設定の変更

server:
  port: 8000

eureka:
  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka
# token 추가해줘야함!!!!
token:
  expiration_time: 86400000 #ms단위
  secret: 토큰 값
  
spring:
  application:  #gateway service 이름름
    name: gateway-service
  cloud:
    gateway:  #gateway 설정
      routes:
        # login service
        - id: login-service
          uri: lb://LOGIN-SERVICE
          predicates:
            - Path=/login-service/**
            - Method=GET, POST
          filters:
            - RemoveRequestHeader=Cookie
            - RewritePath=/login-service(?<segment>.*), /$\{segment}
        # order service
        - id: order-service
          uri: lb://ORDER-SERVICE
          predicates:
            - Path=/order-service/**
            - Method=GET, POST
          filters:
            - RemoveRequestHeader=Cookie
            - RewritePath=/order-service(?<segment>.*), /$\{segment}
gateway.ymlファイルの内容を次のように設定します.orderサービスが追加されました.

その後、テストを行い、トークン値がなくても正常に処理できることを確認できます.今修正して、コインがなければ処理できません.

🔨ゲートウェイ設定の変更

implementation 'io.jsonwebtoken:jjwt:0.9.1'
implementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.1'
2つの依存項目を追加します.
@Component
@Slf4j
@RequiredArgsConstructor
public class AuthFilter extends AbstractGatewayFilterFactory<AuthFilter.Config> {

    private final Environment env;

    public static class Config{
        //설정에 필요한 내용 정의
    }

    //인증 요청시 확인
    @Override
    public GatewayFilter apply(Config config) {
        return ((exchange, chain)->{
            ServerHttpRequest request = exchange.getRequest();

            if(!request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)){
                //헤더에 AUTHORIZATION key 자체가 존재하지 않을 경우
                return onError(exchange, "no AUTHORIZATION header", HttpStatus.UNAUTHORIZED);   //401 반환
            }

            String authorizationHeader = request.getHeaders().get(org.springframework.http.HttpHeaders.AUTHORIZATION).get(0);   //AUTHORIZATION key 값으로 value 가져옴
            String jwt = authorizationHeader.replace("Bearer", ""); //JWT, OAuth는 Bearer로 붙여서 전송하기로 약속함

            if(!isJwtValid(jwt)){
                return onError(exchange, "JWT Token is not valid", HttpStatus.UNAUTHORIZED);
            }

            return chain.filter(exchange);
        });
    }
    //token이 유효한지 확인
    private boolean isJwtValid(String jwt) {
        boolean returnValue = true;


        String subject = null;
        try {
            subject = Jwts.parser().setSigningKey(env.getProperty("token.secret"))  //secret key 값을 통해 parse
                    .parseClaimsJws(jwt).getBody()  //token의 내용을 가져옴
                    .getSubject();
        }catch (Exception e){
            returnValue = false;
        }

        if(subject == null || subject.equals("")){
            returnValue = false;
        }
        return returnValue;
    }

    //에러 발생시 에러 값을 response
    //Mono, Flux -> Spring WebFlux 개념 / 데이터 단위 단일=Mono, 복수=Flux
    private Mono<Void> onError(ServerWebExchange exchange, String err, HttpStatus httpStatus) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(httpStatus);

        log.error(err);
        return response.setComplete();  //Mono 데이터 return
    }
}
フィルタを追加しましょうfilterの内容はlogin-serviceの認証とほぼ同じですが、WebFluxのMonとServer Httpを使用しています.まだ内容を深く見ていないので、よくわかりませんが、必ず勉強しなければならない部分です!

🔨gatewayプロファイルの変更

server:
  port: 8000

eureka:
  client:
    fetch-registry: true
    register-with-eureka: true
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka

token:
  expiration_time: 86400000 #ms단위
  secret: 토큰 값

spring:
  application:  #gateway service 이름름
    name: gateway-service
  cloud:
    gateway:  #gateway 설정
      routes:
        # login service
        - id: login-service
          uri: lb://LOGIN-SERVICE
          predicates:
            - Path=/login-service/**
            - Method=GET, POST
          filters:
            - RemoveRequestHeader=Cookie
            - RewritePath=/login-service(?<segment>.*), /$\{segment}
        # order service
        - id: order-service
          uri: lb://ORDER-SERVICE
          predicates:
            - Path=/order-service/**
            - Method=GET, POST
          filters:
            - RemoveRequestHeader=Cookie
            - RewritePath=/order-service(?<segment>.*), /$\{segment}
            - AuthFilter	#토큰 처리 필터 적용
最終的に、ゲートウェイのプロファイルは次のように変更する必要があります.

👊テスト



では、今401で返します.

gatewayは私たちが設定したエラーメッセージを出力します.

会員加入後

登録後に発行されるコイン

適用後、正常に戻ることを確認できます!