博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
springcloud gateway
阅读量:2378 次
发布时间:2019-05-10

本文共 8172 字,大约阅读时间需要 27 分钟。

了解springcloud Gateway

网关作为流量的入口,常用功能包括路由转发、权限校验、限流控制等。而springcloud gateway作为SpringCloud官方推出的第二代网关框架,取代了Zuul网关。

org.springframework.cloud
spring-cloud-starter-gateway

springcloud gateway使用RouteLocator的Bean进行路由转发,对请求进行处理,并转发给下游服务处理。

@Beanpublic RouteLocator myRoutes(RouteLocatorBuilder builder) {   return builder.routes()    .route(p -> p        .path("/get")        .filters(f -> f.addRequestHeader("Hello", "World"))        .uri("http://httpbin.org:80"))    .build();}

gateway过滤器

sprincloud gateway中主要有两种类型的过滤器:GlobalFilterGatewayFilter

  • GlobalFilter : 全局过滤器,对所有的路由均起作用
  • GatewayFilter : 只对指定的路由起作用,单路由过滤器

自定义GatewayFilter

自定义GatewayFilter有两种实现方式,一种是直接实现GatewayFilter接口,另一种是继承AbstractGatewayFilterFactory类 ,任意选一种即可

1、指定路由,应用GatewayFilter接口

/** * token校验过滤器 */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 Mono
filter(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; }}// 对指定路由的应用@Beanpublic RouteLocator routeLocator(RouteLocatorBuilder builder) { return builder.routes().route(r -> r.path("/user/list") .uri("http://localhost:8080/api/user/list") .filters(new AuthorizeGatewayFilter()) .id("user-service")) .build();}

2、指定路由,继承AbstractGatewayFilterFactory

/** * 自定义basic认证 */@Slf4j@Componentpublic class HttpBasicGatewayFilter extends AbstractGatewayFilterFactory {   @Override   public GatewayFilter apply(Object config) {      return (exchange, chain) -> {         if (hasAuth(exchange)) {            return chain.filter(exchange);         } else {            ServerHttpResponse response = exchange.getResponse();            response.setStatusCode(HttpStatus.UNAUTHORIZED);            response.getHeaders().add(HttpHeaders.WWW_AUTHENTICATE, "Basic Realm=\"xaax\"");            return response.setComplete();         }      };   }   /**    * 简单的basic认证    *    * @param exchange 上下文    * @return 是否有权限    */   private boolean hasAuth(ServerWebExchange exchange) {      ServerHttpRequest request = exchange.getRequest();      String auth = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);      log.info("Basic认证信息为:{}", auth);      return true;   }}

再举一例

/** * @date 2018/7/4 * 验证码处理 */@Slf4j@Component@AllArgsConstructorpublic class ValidateCodeGatewayFilter extends AbstractGatewayFilterFactory {	private final ObjectMapper objectMapper;	private final RedisTemplate redisTemplate;	private final FilterIgnorePropertiesConfig filterIgnorePropertiesConfig;	@Override	public GatewayFilter apply(Object config) {		return (exchange, chain) -> {			ServerHttpRequest request = exchange.getRequest();			// 不是登录请求,直接向下执行			if (!StrUtil.containsAnyIgnoreCase(request.getURI().getPath()					, SecurityConstants.OAUTH_TOKEN_URL, SecurityConstants.SMS_TOKEN_URL					, SecurityConstants.SOCIAL_TOKEN_URL)) {				return chain.filter(exchange);			}			// 刷新token,直接向下执行			String grantType = request.getQueryParams().getFirst("grant_type");			if (StrUtil.equals(SecurityConstants.REFRESH_TOKEN, grantType)) {				return chain.filter(exchange);			}			// 终端设置不校验, 直接向下执行			try {				String[] clientInfos = WebUtils.getClientId(request);				if (filterIgnorePropertiesConfig.getClients().contains(clientInfos[0])) {					return chain.filter(exchange);				}				// 如果是社交登录,判断是否包含SMS				if (StrUtil.containsAnyIgnoreCase(request.getURI().getPath(), SecurityConstants.SOCIAL_TOKEN_URL)) {					String mobile = request.getQueryParams().getFirst("mobile");					if (StrUtil.containsAny(mobile, LoginTypeEnum.SMS.getType())) {						throw new ValidateCodeException("验证码不合法");					} else {						return chain.filter(exchange);					}				}				//校验验证码				checkCode(request);			} catch (Exception e) {				ServerHttpResponse response = exchange.getResponse();				response.setStatusCode(HttpStatus.PRECONDITION_REQUIRED);				try {					return response.writeWith(Mono.just(response.bufferFactory()							.wrap(objectMapper.writeValueAsBytes(									R.builder().msg(e.getMessage())											.code(CommonConstants.FAIL).build()))));				} catch (JsonProcessingException e1) {					log.error("对象输出异常", e1);				}			}			return chain.filter(exchange);		};	}	/**	 * 检查code	 *	 * @param request	 */	@SneakyThrows	private void checkCode(ServerHttpRequest request) {		String code = request.getQueryParams().getFirst("code");		if (StrUtil.isBlank(code)) {			throw new ValidateCodeException("验证码不能为空");		}		String randomStr = request.getQueryParams().getFirst("randomStr");		if (StrUtil.isBlank(randomStr)) {			randomStr = request.getQueryParams().getFirst("mobile");		}		String key = CommonConstants.DEFAULT_CODE_KEY + randomStr;		redisTemplate.setKeySerializer(new StringRedisSerializer());		if (!redisTemplate.hasKey(key)) {			throw new ValidateCodeException("验证码不合法");		}		Object codeObj = redisTemplate.opsForValue().get(key);		if (codeObj == null) {			throw new ValidateCodeException("验证码不合法");		}		String saveCode = codeObj.toString();		if (StrUtil.isBlank(saveCode)) {			redisTemplate.delete(key);			throw new ValidateCodeException("验证码不合法");		}		if (!StrUtil.equals(saveCode, code)) {			redisTemplate.delete(key);			throw new ValidateCodeException("验证码不合法");		}		redisTemplate.delete(key);	}}

自定义GlobalFilter

只需要添加 @Component 注解,不需要进行任何额外的配置,实现GlobalFilter接口,自动会对所有的路由起作用

/** * * token校验全局过滤器 */@Componentpublic 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 Mono
filter(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; }}

springboot依赖

springcloud gateway需要排除spring-boot-starter-web引入spring-boot-starter-webflux

org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-webflux

参考

转载地址:http://sbaxb.baihongyu.com/

你可能感兴趣的文章
2013年江苏通信行业“大数据”回顾
查看>>
大数据“由浅到深”来到身边
查看>>
消失的马航 大数据告诉你航空安全现状
查看>>
大数据时代:从预言走向现实
查看>>
大数据让电商实现精准营销
查看>>
哪些领域的应用因为大数据变得更聪明?
查看>>
大数据驱动电信运营商转型
查看>>
玩转大数据 运动员如何用科技提升成绩
查看>>
广发银行试水大数据 “精细服务”现雏形
查看>>
大数据让社区生活更方便
查看>>
借助互联网大数据打假
查看>>
东信北邮大数据项目获2014中国通信学会科学技术一等奖
查看>>
大数据塑造新时代公共外交
查看>>
海-两篇
查看>>
整理硬盘
查看>>
ERP&SCM&MES發展歷程
查看>>
风-----
查看>>
系统Server架构图
查看>>
我的简历
查看>>
一种自适应的柔性制造系统优化调度算法
查看>>