Skip to content

Commit

Permalink
Merge pull request #2 from Mojacknong/main
Browse files Browse the repository at this point in the history
[feat] 스프링 클라우드 게이트웨이 필터
  • Loading branch information
Ryeolee authored Oct 20, 2023
2 parents 1b23051 + 3d776fd commit d115743
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
branches: [ "dev" ]

permissions:
contents: read
Expand Down
8 changes: 8 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ dependencies {
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.projectreactor:reactor-test'

implementation 'org.springframework.boot:spring-boot-starter-security'

implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.2'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.2'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.2'

implementation 'org.springframework.boot:spring-boot-starter-web'
}

dependencyManagement {
Expand Down
30 changes: 30 additions & 0 deletions src/main/java/com/example/farmusgateway/config/FilterConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.example.farmusgateway.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {

@Value("${baseurl.user}")
private String userUrl;

@Bean
public RouteLocator gatewayRoutes(RouteLocatorBuilder builder) {
// application.yml 에 적용한 라우팅 대신에 필터를 적용해서 처리
return builder.routes()
.route(r -> r.path("/api/user/auth/logout")
.filters(f -> f.addRequestHeader("user", "first-request-header"))
.uri(userUrl))

.route(r -> r.path("/api/user/auth/reissue-token")
.filters(f -> f.addRequestHeader("user", "second-request-header")
.addRequestHeader("Authorization","sd")
)
.uri(userUrl))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.example.farmusgateway.filter;


import io.jsonwebtoken.Jwts;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
@Slf4j
public class AuthorizationHeaderFilter extends AbstractGatewayFilterFactory<AuthorizationHeaderFilter.Config> {

@Value("${jwt.secret}")
private String secret;

public AuthorizationHeaderFilter(Environment env) {
super(Config.class);

}

// login -> token -> users (with token) -> header(include token)
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
if(!request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) {
return onError(exchange, "no authorization header", HttpStatus.UNAUTHORIZED);
}

String authorizationHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION).get(0);
String jwt = authorizationHeader.replace("Bearer", "");
if(!isJwtValid(jwt)) {
return onError(exchange, "JWT token is not valid", HttpStatus.UNAUTHORIZED);
}

// Custom Post Filter
return chain.filter(exchange);
};
}

private boolean isJwtValid(String jwt) {
boolean returnValue = true;

String subject = null;
try {
subject = Jwts.parser().setSigningKey(secret)
.parseClaimsJws(jwt).getBody()
.getSubject();
} catch(Exception ex) {
returnValue = false;
}

if(subject == null || subject.isEmpty()) {
returnValue = false;
}

return returnValue;
}

// Mono, Flux -> Spring WebFlux
private Mono<Void> onError(ServerWebExchange exchange, String error, HttpStatus httpStatus) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(httpStatus);

log.error(error);

return response.setComplete();
}

@Data
public static class Config {

}
}

0 comments on commit d115743

Please sign in to comment.