前言
本篇文章繼續上一篇gateway的鑑權使用說明。主要包含全局過濾器的設置和多路由跳轉,附帶做一下配置中心的講解。
一、全局過濾器
在gateway的官方文檔中,分兩種過濾器:全局過濾和路由過濾。本次採用全局過濾來輔助完成鑑權
@Component
public class Filter implements GlobalFilter {
/*白名單暫時不做,只提一個登錄接口*/
private final static String LOGIN_PATH = "/user/login";
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
if(LOGIN_PATH.equals(exchange.getRequest().getPath().toString())) {
exchange.getResponse().setStatusCode(HttpStatus.OK);
return chain.filter(exchange);
}
/*暫時定義鑑權邏輯:有token就通過並刷新,沒有就直接不允許*/
exchange.getResponse().setStatusCode(HttpStatus.FAILED_DEPENDENCY);
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if(StringUtils.isNotEmpty(token)) {
String str = redisTemplate.opsForValue().get(token);
if(StringUtils.isNotEmpty(str)) {
@SuppressWarnings("unchecked")
Map<String,Object> map = (Map)JSONObject.parse(str);
long timestamp = Long.parseLong(map.get("outTime").toString());
LocalDateTime time =LocalDateTime.ofEpochSecond(timestamp/1000,0, ZoneOffset.ofHours(8));
map.put("outTime",time.plusMinutes(10).toInstant(ZoneOffset.of("+8")).toEpochMilli());
String jsonString = JSONObject.toJSONString(map);
redisTemplate.opsForValue().set(token,jsonString);
exchange.getResponse().setStatusCode(HttpStatus.OK);
}
}
return chain.filter(exchange);
}
}
這裏藉助了GlobalFilter來實現全局的一個請求過濾,主要複寫了filter,當中定義了我設想的token校驗邏輯;對於白名單暫時只是將登錄接口做免校驗。。。
二、路由轉發
在gateway的官方說明中,是提供兩種方式的路由轉發的。一是在配置文件中配置,如:
routes:
# =====================================
# to run server
# $ wscat --listen 9000
# to run client
# $ wscat --connect ws://localhost:8080/echo
- id: websocket_test
uri: ws://localhost:9000
order: 9000
predicates:
- Path=/echo
# =====================================
- id: default_path_to_httpbin
uri: ${test.uri}
order: 10000
predicates:
- Path=/**
另一種方式是api做路由轉發,如:
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route (r -> r.path ("/u/**")
.filters (f -> f.stripPrefix (1))
.uri ("lb://user")
.order (0)
.id ("user-route")
)
.route (r -> r.path ("/db/**")
.filters (f -> f.stripPrefix (1))
.uri ("lb://dbmanagement")
.order (0)
.id ("db-route")
)
.build();
}
這裏簡單的闡述一下兩種方式的共同的參數意義
id:路由的唯一標識
uri:轉發的地址
order:序號(越大優先級越高)
filter:url斷言規則
(其實在配置文件中的路由轉發,本人並沒有實現,不知道是哪裏配出了問題,所以採用的是api的方式,望有大佬路過告知)
三、配置中心
關於springcloud config的配置和說明網上已經太多了,我這裏只是附帶提一下。
1、jar
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
2、啓動項註解
@EnableConfigServer
3、配置文件集中管理
類似如此的文件配置,丟在config服務下靜態資源處。
server:
port: 19000
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: config
profiles:
active: native
cloud:
config:
fail-fast: true
server:
native:
search-locations: classpath:/config/
指定config讀取本地(profiles:active: native)
4、其他服務獲取配置文件
spring:
cloud:
config:
profile: user
discovery:
enabled: true
service-id: CONFIG
fail-fast: true
指定配置中心服務的爲 CONFIG
文件名爲 user的配置文件
如此就可以在服務啓動時從配置中心拉取配置文件,eg: