摘要:自定義校驗(yàn)全局過濾器如何應(yīng)用呢只需要添加注解,不需要進(jìn)行任何額外的配置,實(shí)現(xiàn)接口,自動(dòng)會對所有的路由起作用總結(jié)由于剛接觸,有些地方也不是特別熟悉,上面的示例代碼僅僅作為參考,如果有錯(cuò)誤的地方,還望指正。
一切的業(yè)務(wù)開發(fā)都是基于需求的,首先看看需求:
對訪問網(wǎng)關(guān)的請求進(jìn)行token校驗(yàn),只有當(dāng)token校驗(yàn)通過時(shí),才轉(zhuǎn)發(fā)到后端服務(wù),否則直接返回401
本文給出的示例代碼適用場景:
token存放在redis中, key為用戶的uid
依賴的pom.xml
4.0.0 com.winture api-gateway 0.0.1-SNAPSHOT jar api-gateway Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 2.0.4.RELEASE UTF-8 UTF-8 1.8 Finchley.SR1 org.springframework.cloud spring-cloud-starter-gateway org.springframework.boot spring-boot-starter-data-redis org.springframework.boot spring-boot-starter-test test org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import org.springframework.boot spring-boot-maven-plugin
在Spring Cloud Gateway中,主要有兩種類型的過濾器:GlobalFilter 和 GatewayFilter
GlobalFilter : 全局過濾器,對所有的路由均起作用
GatewayFilter : 只對指定的路由起作用
1、自定義GatewayFilter自定義GatewayFilter又有兩種實(shí)現(xiàn)方式,一種是直接 實(shí)現(xiàn)GatewayFilter接口,另一種是 繼承AbstractGatewayFilterFactory類 ,任意選一種即可
1.1 實(shí)現(xiàn)GatewayFilter接口package com.winture.gateway.filter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.core.Ordered; import org.springframework.data.redis.core.StringRedisTemplate; 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.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; /** * token校驗(yàn)過濾器 * @Version V1.0 */ public class AuthorizeGatewayFilter implements GatewayFilter, Ordered { private static final String AUTHORIZE_TOKEN = "token"; private static final String AUTHORIZE_UID = "uid"; @Autowired private StringRedisTemplate stringRedisTemplate; @Override public Monofilter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); HttpHeaders headers = request.getHeaders(); String token = headers.getFirst(AUTHORIZE_TOKEN); String uid = headers.getFirst(AUTHORIZE_UID); if (token == null) { token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN); } if (uid == null) { uid = request.getQueryParams().getFirst(AUTHORIZE_UID); } ServerHttpResponse response = exchange.getResponse(); if (StringUtils.isEmpty(token) || StringUtils.isEmpty(uid)) { response.setStatusCode(HttpStatus.UNAUTHORIZED); return response.setComplete(); } String authToken = stringRedisTemplate.opsForValue().get(uid); if (authToken == null || !authToken.equals(token)) { response.setStatusCode(HttpStatus.UNAUTHORIZED); return response.setComplete(); } return chain.filter(exchange); } @Override public int getOrder() { return 0; } }
首先從header頭信息中獲取uid和token信息,如果token或者uid為null,則從請求參數(shù)中嘗試再次獲取,如果依然不存在token或者uid,則直接返回401狀態(tài)嗎,同時(shí)結(jié)束請求;如果兩者都存在,則根據(jù)uid從redis中讀取保存的authToken,并和請求中傳輸?shù)膖oken進(jìn)行比對,比對一樣則繼續(xù)通過過濾器鏈,否則直接結(jié)束請求,返回401.
如何應(yīng)用 AuthorizeGatewayFilter 呢?
package com.winture.gateway; import com.winture.gateway.filter.AuthorizeGatewayFilter; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.context.annotation.Bean; @SpringBootApplication public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } @Bean public RouteLocator routeLocator(RouteLocatorBuilder builder) { return builder.routes().route(r -> r.path("/user/list") .uri("http://localhost:8077/api/user/list") .filters(new AuthorizeGatewayFilter()) .id("user-service")) .build(); } }1.2 繼承AbstractGatewayFilterFactory類
package com.winture.gateway.filter.factory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; import org.springframework.data.redis.core.StringRedisTemplate; 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 java.util.Arrays; import java.util.List; @Component public class AuthorizeGatewayFilterFactory extends AbstractGatewayFilterFactory{ private static final Log logger = LogFactory.getLog(AuthorizeGatewayFilterFactory.class); private static final String AUTHORIZE_TOKEN = "token"; private static final String AUTHORIZE_UID = "uid"; @Autowired private StringRedisTemplate stringRedisTemplate; public AuthorizeGatewayFilterFactory() { super(Config.class); logger.info("Loaded GatewayFilterFactory [Authorize]"); } @Override public List shortcutFieldOrder() { return Arrays.asList("enabled"); } @Override public GatewayFilter apply(AuthorizeGatewayFilterFactory.Config config) { return (exchange, chain) -> { if (!config.isEnabled()) { return chain.filter(exchange); } ServerHttpRequest request = exchange.getRequest(); HttpHeaders headers = request.getHeaders(); String token = headers.getFirst(AUTHORIZE_TOKEN); String uid = headers.getFirst(AUTHORIZE_UID); if (token == null) { token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN); } if (uid == null) { uid = request.getQueryParams().getFirst(AUTHORIZE_UID); } ServerHttpResponse response = exchange.getResponse(); if (StringUtils.isEmpty(token) || StringUtils.isEmpty(uid)) { response.setStatusCode(HttpStatus.UNAUTHORIZED); return response.setComplete(); } String authToken = stringRedisTemplate.opsForValue().get(uid); if (authToken == null || !authToken.equals(token)) { response.setStatusCode(HttpStatus.UNAUTHORIZED); return response.setComplete(); } return chain.filter(exchange); }; } public static class Config { // 控制是否開啟認(rèn)證 private boolean enabled; public Config() {} public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } } }
如何應(yīng)用 AuthorizeGatewayFilterFactory 呢?
# 網(wǎng)關(guān)路由配置 spring: cloud: gateway: routes: - id: user-service uri: http://localhost:8077/api/user/list predicates: - Path=/user/list filters: # 關(guān)鍵在下面一句,值為true則開啟認(rèn)證,false則不開啟 # 這種配置方式和spring cloud gateway內(nèi)置的GatewayFilterFactory一致 - Authorize=true
上面的兩種方式都可以實(shí)現(xiàn)對訪問網(wǎng)關(guān)的 特定請求 進(jìn)行token校驗(yàn),如果想對 所有的請求 都進(jìn)行token校驗(yàn),那么可以采用實(shí)現(xiàn) GlobalFilter 方式。
2、自定義GlobalFilterpackage com.winture.gateway.filter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.data.redis.core.StringRedisTemplate; 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.util.StringUtils; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; /** * token校驗(yàn)全局過濾器 * @Version V1.0 */ @Component public class AuthorizeFilter implements GlobalFilter, Ordered { private static final String AUTHORIZE_TOKEN = "token"; private static final String AUTHORIZE_UID = "uid"; @Autowired private StringRedisTemplate stringRedisTemplate; @Override public Monofilter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); HttpHeaders headers = request.getHeaders(); String token = headers.getFirst(AUTHORIZE_TOKEN); String uid = headers.getFirst(AUTHORIZE_UID); if (token == null) { token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN); } if (uid == null) { uid = request.getQueryParams().getFirst(AUTHORIZE_UID); } ServerHttpResponse response = exchange.getResponse(); if (StringUtils.isEmpty(token) || StringUtils.isEmpty(uid)) { response.setStatusCode(HttpStatus.UNAUTHORIZED); return response.setComplete(); } String authToken = stringRedisTemplate.opsForValue().get(uid); if (authToken == null || !authToken.equals(token)) { response.setStatusCode(HttpStatus.UNAUTHORIZED); return response.setComplete(); } return chain.filter(exchange); } @Override public int getOrder() { return 0; } }
如何應(yīng)用 AuthorizeFilter 呢?
只需要添加 @Component 注解,不需要進(jìn)行任何額外的配置,實(shí)現(xiàn)GlobalFilter接口,自動(dòng)會對所有的路由起作用3、總結(jié)
由于剛接觸Spring Cloud Gateway,有些地方也不是特別熟悉,上面的示例代碼僅僅作為參考,如果有錯(cuò)誤的地方,還望指正。
備注:
運(yùn)行上面的代碼,需要先啟動(dòng)redis服務(wù),由于沒有配置redis的地址和端口,默認(rèn)采用localhost和6379端口,如果不一致,請自行在application.yml文件中配置即可;
網(wǎng)關(guān)的端口采用默認(rèn)的8080;
當(dāng)通過網(wǎng)關(guān)訪問/user/list時(shí),如果token驗(yàn)證通過,會轉(zhuǎn)發(fā)到 http://localhost:8077/api/user/list 上,這是另外的一個(gè)接口服務(wù),自行根據(jù)實(shí)際情況修改;
參考學(xué)習(xí):
Spring Cloud Gateway官方文檔
Spring Cloud Gateway源代碼
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/76929.html
摘要:引入依賴自定義過濾器可以繼承或?qū)崿F(xiàn)實(shí)現(xiàn)過濾請求功能只能指定路徑上應(yīng)用去掉路徑的個(gè)前綴輸入過濾器類的名稱前綴可以在全局應(yīng)用 引入依賴 org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} ...
摘要:項(xiàng)目地址本文將分四部分介紹登錄邏輯前置過濾器校驗(yàn)邏輯工具類演示驗(yàn)證一登錄邏輯登錄成功后,將生成的存儲在中。鍵是用戶值是二前置過濾器繼承自,必須實(shí)現(xiàn)的四個(gè)方法。 這兩天在寫項(xiàng)目的全局權(quán)限校驗(yàn),用 Zuul 作為服務(wù)網(wǎng)關(guān),在 Zuul 的前置過濾器里做的校驗(yàn)。 權(quán)限校驗(yàn)或者身份驗(yàn)證就不得不提 Token,目前 Token 的驗(yàn)證方式有很多種,有生成 Token 后將 Token 存儲在 R...
摘要:所以,沒必要過分糾結(jié)這種信息,咬文嚼字有時(shí)候反而會適得其反。若初通用錯(cuò)誤信息異常類請求參數(shù)異常用戶已存在用戶不存在在下面創(chuàng)建一個(gè)工具類用來對用戶進(jìn)行加密來獲取信息。工具類若初加密參考創(chuàng)建用戶的實(shí)現(xiàn),依次實(shí)現(xiàn)其他表操作。 DAO層設(shè)計(jì)實(shí)現(xiàn) 這里我們使用Spring DATA JPA來實(shí)現(xiàn)數(shù)據(jù)庫操作,當(dāng)然大家也可以使用Mybatis,都是一樣的,我們依然以用戶表操作為例: /** * A...
閱讀 2773·2021-11-17 09:33
閱讀 3099·2021-10-25 09:44
閱讀 1207·2021-10-11 10:59
閱讀 2403·2021-09-27 13:34
閱讀 2910·2021-09-07 10:19
閱讀 2140·2019-08-29 18:46
閱讀 1538·2019-08-29 12:55
閱讀 930·2019-08-23 17:11