本文主要内容是通过SpringCloud Gateway构建一个网关微服务,作为统一的认证授权和访问入口。

配置文件

先引入相关依赖,对应的pom文件内容如下:

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

oauth2-demo

com.zjq

1.0-SNAPSHOT

4.0.0

ms-gateway

org.springframework.cloud

spring-cloud-starter-gateway

org.springframework.cloud

spring-cloud-starter-netflix-eureka-client

com.zjq

commons

1.0-SNAPSHOT

com.battcn

swagger-spring-boot-starter

org.springframework.boot

spring-boot-configuration-processor

true

网关服务的yml配置内容如下:

server:

port: 80

spring:

application:

name: ms-gateway

cloud:

gateway:

discovery:

locator:

enabled: true # 开启配置注册中心进行路由功能

lower-case-service-id: true # 将服务名称转小写

routes:

- id: ms-users

uri: lb://ms-users

predicates:

- Path=/users/**

filters:

- StripPrefix=1

- id: ms-oauth2-server

uri: lb://ms-oauth2-server

predicates:

- Path=/auth/**

filters:

- StripPrefix=1

secure:

ignore:

urls: # 配置白名单路径

- /actuator/**

- /auth/oauth/**

- /users/signin

# 配置 Eureka Server 注册中心

eureka:

instance:

prefer-ip-address: true

instance-id: ${spring.cloud.client.ip-address}:${server.port}

client:

service-url:

defaultZone: http://localhost:7000/eureka/

logging:

pattern:

console: '%d{HH:mm:ss} [%thread] %-5level %logger{50} - %msg%n'

请求白名单配置

加载配置文件中的配置,注入到spring容器中。

secure:

ignore:

urls: # 配置白名单路径

- /actuator/**

- /auth/oauth/**

- /users/signin

/**

* 网关白名单配置

* @author zjq

*/

@Data

@Component

@ConfigurationProperties(prefix = "secure.ignore")

public class IgnoreUrlsConfig {

private List urls;

}

异常处理和rest请求配置

异常处理在全局过滤器中会有用到,代码如下:

@Component

public class HandleException {

@Resource

private ObjectMapper objectMapper;

public Mono writeError(ServerWebExchange exchange, String error) {

ServerHttpResponse response = exchange.getResponse();

ServerHttpRequest request = exchange.getRequest();

response.setStatusCode(HttpStatus.OK);

response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);

ResultInfo resultInfo = ResultInfoUtil.buildError(ApiConstant.NO_LOGIN_CODE, ApiConstant.NO_LOGIN_MESSAGE, request.getURI().getPath());

String resultInfoJson = null;

DataBuffer buffer = null;

try {

resultInfoJson = objectMapper.writeValueAsString(resultInfo);

buffer = response.bufferFactory().wrap(resultInfoJson.getBytes(Charset.forName("UTF-8")));

} catch (JsonProcessingException ex) {

ex.printStackTrace();

}

return response.writeWith(Mono.just(buffer));

}

}

申请授权和认证过程中需要远程调用其他接口,所以我们引入rest请求配置,代码如下:

/**

* REST请求配置

* @author zjq

*/

@Configuration

public class RestTemplateConfiguration {

@LoadBalanced

@Bean

public RestTemplate restTemplate() {

return new RestTemplate();

}

}

全局过滤器配置

配置好了白名单,我们需要在网关过滤器中使用该白名单配置,放行对应的白名单,网关过滤器需要实现全局过滤器接口org.springframework.cloud.gateway.filter.GlobalFilter和过滤器顺序接口org.springframework.core.Ordered相关代码如下:

/**

* 网关全局过滤器

* @author zjq

*/

@Component

public class AuthGlobalFilter implements GlobalFilter, Ordered {

@Resource

private IgnoreUrlsConfig ignoreUrlsConfig;

@Resource

private RestTemplate restTemplate;

@Resource

private HandleException handleException;

/**

* 身份校验处理

*

* @param exchange

* @param chain

* @return

*/

@Override

public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

// 判断当前的请求是否在白名单中

AntPathMatcher pathMatcher = new AntPathMatcher();

boolean flag = false;

String path = exchange.getRequest().getURI().getPath();

for (String url : ignoreUrlsConfig.getUrls()) {

if (pathMatcher.match(url, path)) {

flag = true;

break;

}

}

// 白名单放行

if (flag) {

return chain.filter(exchange);

}

// 获取 access_token

String access_token = exchange.getRequest().getQueryParams().getFirst("access_token");

// 判断 access_token 是否为空

if (StringUtils.isBlank(access_token)) {

return handleException.writeError(exchange, "请登录");

}

// 校验 token 是否有效

String checkTokenUrl = "http://ms-oauth2-server/oauth/check_token?token=".concat(access_token);

try {

// 发送远程请求,验证 token

ResponseEntity entity = restTemplate.getForEntity(checkTokenUrl, String.class);

// token 无效的业务逻辑处理

if (entity.getStatusCode() != HttpStatus.OK) {

return handleException.writeError(exchange,

"Token was not recognised, token: ".concat(access_token));

}

if (StringUtils.isBlank(entity.getBody())) {

return handleException.writeError(exchange,

"This token is invalid: ".concat(access_token));

}

} catch (Exception e) {

return handleException.writeError(exchange,

"Token was not recognised, token: ".concat(access_token));

}

// 放行

return chain.filter(exchange);

}

/**

* 网关过滤器的排序,数字越小优先级越高

*

* @return

*/

@Override

public int getOrder() {

return 0;

}

}

测试验证

登录: 获取当前登录用户信息: 退出登录:

本文内容到此结束了, 如有收获欢迎点赞收藏关注✔️,您的鼓励是我最大的动力。 如有错误❌疑问欢迎各位指出。 主页:共饮一杯无的博客汇总‍

保持热爱,奔赴下一场山海。

文章来源

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: