🔖 v1.2.3

This commit is contained in:
冷冷 committed 2018-07-23 15:25:22 +08:00
commit f185add546
198 files changed
+11968

No files matched your search

@@ -0,0 +1,37 @@
/*
*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*
*/
package com.pig4cloud.pigx.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
/**
* @author lengleng
* @date 2018年06月21日
* 网关应用
*/
@SpringCloudApplication
public class PigxGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(PigxGatewayApplication.class, args);
}
}
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.gateway.config;
import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
/**
* @author lengleng
* @date 2018/7/22
* 网关不简要终端配置
*/
@Data
@Configuration
@RefreshScope
@ConditionalOnExpression("!'${ignore}'.isEmpty()")
@ConfigurationProperties(prefix = "ignore")
public class FilterIgnorePropertiesConfig {
private List<String> clients = new ArrayList<>();
}
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.gateway.config;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
/**
* @author lengleng
* @date 2017-12-21 21:12:18
*/
@Configuration
public class KaptchaConfiguration {
private static final String KAPTCHA_BORDER = "kaptcha.border";
private static final String KAPTCHA_TEXTPRODUCER_FONT_COLOR = "kaptcha.textproducer.font.color";
private static final String KAPTCHA_TEXTPRODUCER_CHAR_SPACE = "kaptcha.textproducer.char.space";
private static final String KAPTCHA_IMAGE_WIDTH = "kaptcha.image.width";
private static final String KAPTCHA_IMAGE_HEIGHT = "kaptcha.image.height";
private static final String KAPTCHA_TEXTPRODUCER_CHAR_LENGTH = "kaptcha.textproducer.char.length";
private static final Object KAPTCHA_IMAGE_FONT_SIZE = "kaptcha.textproducer.font.size";
/**
* 默认生成图形验证码宽度
*/
private static final String DEFAULT_IMAGE_WIDTH = "100";
/**
* 默认生成图像验证码高度
*/
private static final String DEFAULT_IMAGE_HEIGHT = "40";
/**
* 默认生成图形验证码长度
*/
private static final String DEFAULT_IMAGE_LENGTH = "4";
/**
* 边框颜色,合法值: r,g,b (and optional alpha) 或者 white,black,blue.
*/
private static final String DEFAULT_COLOR_FONT = "black";
/**
* 图片边框
*/
private static final String DEFAULT_IMAGE_BORDER = "no";
/**
* 默认图片间隔
*/
private static final String DEFAULT_CHAR_SPACE = "5";
/**
* 验证码文字大小
*/
private static final String DEFAULT_IMAGE_FONT_SIZE = "30";
@Bean
public DefaultKaptcha producer() {
Properties properties = new Properties();
properties.put(KAPTCHA_BORDER, DEFAULT_IMAGE_BORDER);
properties.put(KAPTCHA_TEXTPRODUCER_FONT_COLOR, DEFAULT_COLOR_FONT);
properties.put(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, DEFAULT_CHAR_SPACE);
properties.put(KAPTCHA_IMAGE_WIDTH, DEFAULT_IMAGE_WIDTH);
properties.put(KAPTCHA_IMAGE_HEIGHT, DEFAULT_IMAGE_HEIGHT);
properties.put(KAPTCHA_IMAGE_FONT_SIZE, DEFAULT_IMAGE_FONT_SIZE);
properties.put(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, DEFAULT_IMAGE_LENGTH);
Config config = new Config(properties);
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}
@@ -0,0 +1,38 @@
/*
*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*
*/
package com.pig4cloud.pigx.gateway.config;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;
/**
* @author lengleng
* @date 2018/7/1
* 路由限流配置
*/
@Configuration
public class RateLimiterConfiguration {
@Bean(value = "remoteAddrKeyResolver")
public KeyResolver remoteAddrKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
}
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.gateway.config;
import com.pig4cloud.pigx.gateway.handle.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
/**
* @author lengleng
* @date 2018/7/5
* 路由配置信息
*/
@Slf4j
@Configuration
@AllArgsConstructor
public class RouterFunctionConfiguration {
private final HystrixFallbackHandler hystrixFallbackHandler;
private final SwaggerResourceHandler swaggerResourceHandler;
private final SwaggerSecurityHandler swaggerSecurityHandler;
private final SwaggerUiHandler swaggerUiHandler;
private final ImageCodeHandler imageCodeHandler;
@Bean
public RouterFunction routerFunction() {
return RouterFunctions.route(
RequestPredicates.GET("/fallback")
.and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), hystrixFallbackHandler)
.andRoute(RequestPredicates.GET("/code")
.and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), imageCodeHandler)
.andRoute(RequestPredicates.GET("/swagger-resources")
.and(RequestPredicates.accept(MediaType.ALL)), swaggerResourceHandler)
.andRoute(RequestPredicates.GET("/swagger-resources/configuration/ui")
.and(RequestPredicates.accept(MediaType.ALL)), swaggerUiHandler)
.andRoute(RequestPredicates.GET("/swagger-resources/configuration/security")
.and(RequestPredicates.accept(MediaType.ALL)), swaggerSecurityHandler);
}
}
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.gateway.config;
import lombok.AllArgsConstructor;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import java.util.ArrayList;
import java.util.List;
/**
* @author Sywd
* 聚合接口文档注册,和zuul实现类似
*/
@Component
@Primary
@AllArgsConstructor
public class SwaggerProvider implements SwaggerResourcesProvider {
public static final String API_URI = "/v2/api-docs";
private final RouteLocator routeLocator;
private final GatewayProperties gatewayProperties;
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> resources = new ArrayList<>();
List<String> routes = new ArrayList<>();
routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId()))
.forEach(routeDefinition -> routeDefinition.getPredicates().stream()
.filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName()))
.filter(predicateDefinition -> !"pigx-auth".equalsIgnoreCase(routeDefinition.getId()))
.forEach(predicateDefinition -> resources.add(swaggerResource(routeDefinition.getId(),
predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0")
.replace("/**", API_URI)))));
return resources;
}
private SwaggerResource swaggerResource(String name, String location) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion("2.0");
return swaggerResource;
}
}
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.gateway.exception;
/**
* @author lengleng
* @date 2018年07月22日
* 异常包装类
*/
public class CheckedException extends Exception {
private static final long serialVersionUID = 1L;
public CheckedException() {
}
public CheckedException(String message) {
super(message);
}
public CheckedException(Throwable cause) {
super(cause);
}
public CheckedException(String message, Throwable cause) {
super(message, cause);
}
public CheckedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.gateway.exception;
/**
* @author lengleng
*/
public class ValidateCodeException extends Exception {
}
@@ -0,0 +1,186 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.gateway.filter;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import com.pig4cloud.pigx.gateway.config.FilterIgnorePropertiesConfig;
import com.pig4cloud.pigx.gateway.exception.CheckedException;
import com.pig4cloud.pigx.gateway.exception.ValidateCodeException;
import lombok.extern.slf4j.Slf4j;
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.RedisTemplate;
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.io.IOException;
/**
* @author lengleng
* @date 2018/7/4
* 验证码处理
*/
@Slf4j
@Component
public class ImageCodeGatewayFilter extends AbstractGatewayFilterFactory {
public static final String DEFAULT_CODE_KEY = "DEFAULT_CODE_KEY";
public static final String OAUTH_TOKEN_URL = "/oauth/token";
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private FilterIgnorePropertiesConfig filterIgnorePropertiesConfig;
@Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
// 不是登录请求,直接向下执行
if (!StrUtil.containsAnyIgnoreCase(request.getURI().getPath(), OAUTH_TOKEN_URL)) {
return chain.filter(exchange);
}
// 终端设置不校验, 直接向下执行(1. 从请求参数中获取 2.从header取)
String clientId = request.getQueryParams().getFirst("client_id");
if (StrUtil.isNotBlank(clientId)) {
if (filterIgnorePropertiesConfig.getClients().contains(clientId)) {
return chain.filter(exchange);
}
}
try {
String[] clientInfos = extractAndDecodeHeader(request);
if (filterIgnorePropertiesConfig.getClients().contains(clientInfos[0])) {
return chain.filter(exchange);
}
} catch (Exception e) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.PRECONDITION_REQUIRED);
return response.setComplete();
}
//校验验证码合法性
try {
checkCode(request);
} catch (ValidateCodeException e) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.PRECONDITION_REQUIRED);
return response.setComplete();
}
return chain.filter(exchange);
};
}
/**
* 检查code
*
* @param request
* @throws ValidateCodeException 校验异常
*/
private void checkCode(ServerHttpRequest request) throws ValidateCodeException {
String code = request.getQueryParams().getFirst("code");
if (StrUtil.isBlank(code)) {
throw new ValidateCodeException();
}
String randomStr = request.getQueryParams().getFirst("randomStr");
if (StrUtil.isBlank(randomStr)) {
throw new ValidateCodeException();
}
String key = DEFAULT_CODE_KEY + randomStr;
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);
}
private static final String BASIC_ = "Basic ";
/**
* 从header 请求中的clientId/clientsecect
*
* @param header header中的参数
* @throws CheckedException if the Basic header is not present or is not valid
* Base64
*/
public static String[] extractAndDecodeHeader(String header)
throws IOException, CheckedException {
byte[] base64Token = header.substring(6).getBytes("UTF-8");
byte[] decoded;
try {
decoded = Base64.decode(base64Token);
} catch (IllegalArgumentException e) {
throw new CheckedException(
"Failed to decode basic authentication token");
}
String token = new String(decoded, CharsetUtil.UTF_8);
int delim = token.indexOf(":");
if (delim == -1) {
throw new CheckedException("Invalid basic authentication token");
}
return new String[]{token.substring(0, delim), token.substring(delim + 1)};
}
/**
* *从header 请求中的clientId/clientsecect
*
* @param request
* @return
* @throws IOException
*/
public static String[] extractAndDecodeHeader(ServerHttpRequest request)
throws IOException, CheckedException {
String header = request.getHeaders().getFirst("Authorization");
if (header == null || !header.startsWith(BASIC_)) {
throw new CheckedException("请求头中client信息为空");
}
return extractAndDecodeHeader(header);
}
}
@@ -0,0 +1,97 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.gateway.filter;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
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.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.util.Map;
/**
* @author lengleng
* @date 2018/7/15
* 密码解密工具类
*/
@Slf4j
@Component
public class PasswordDecoderFilter extends AbstractGatewayFilterFactory {
private static final String PASSWORD = "password";
private static final String KEY_ALGORITHM = "AES";
private static final String DEFAULT_CIPHER_ALGORITHM = "AES/CBC/NOPadding";
@Value("${security.encode.key:1234567812345678}")
private String encodeKey;
@Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
// 不是登录请求,直接向下执行
if (!StrUtil.containsAnyIgnoreCase(request.getURI().getPath(), ImageCodeGatewayFilter.OAUTH_TOKEN_URL)) {
return chain.filter(exchange);
}
URI uri = exchange.getRequest().getURI();
String queryParam = uri.getRawQuery();
Map<String, String> paramMap = HttpUtil.decodeParamMap(queryParam, CharsetUtil.UTF_8);
String password = paramMap.get(PASSWORD);
if (StrUtil.isNotBlank(password)) {
try {
password = decryptAES(password, encodeKey);
} catch (Exception e) {
log.error("密码解密失败:{}", password);
return Mono.error(e);
}
paramMap.put(PASSWORD, password.trim());
}
URI newUri = UriComponentsBuilder.fromUri(uri)
.replaceQuery(HttpUtil.toParams(paramMap))
.build(true)
.toUri();
ServerHttpRequest newRequest = exchange.getRequest().mutate().uri(newUri).build();
return chain.filter(exchange.mutate().request(newRequest).build());
};
}
private static String decryptAES(String data, String pass) throws Exception {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
SecretKeySpec keyspec = new SecretKeySpec(pass.getBytes(), KEY_ALGORITHM);
IvParameterSpec ivspec = new IvParameterSpec(pass.getBytes());
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
byte[] result = cipher.doFinal(Base64.decode(data.getBytes(CharsetUtil.UTF_8)));
return new String(result, CharsetUtil.UTF_8);
}
}
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.gateway.filter;
import com.pig4cloud.pigx.gateway.config.SwaggerProvider;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
/**
* @author Sywd
* 添加X-Forwarded-Prefix header
*/
@Component
public class SwaggerHeaderFilter extends AbstractGatewayFilterFactory {
private static final String HEADER_NAME = "X-Forwarded-Prefix";
@Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
if (!StringUtils.endsWithIgnoreCase(path, SwaggerProvider.API_URI)) {
return chain.filter(exchange);
}
String basePath = path.substring(0, path.lastIndexOf(SwaggerProvider.API_URI));
ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, basePath).build();
ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
return chain.filter(newExchange);
};
}
}
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.gateway.handle;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
/**
* @author lengleng
* @date 2018/7/5
* Hystrix 降级处理
*/
@Slf4j
@Component
public class HystrixFallbackHandler implements HandlerFunction<ServerResponse> {
@Override
public Mono<ServerResponse> handle(ServerRequest serverRequest) {
log.error("网关执行请求:{}失败,hystrix服务降级处理", serverRequest.uri());
return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR.value())
.contentType(MediaType.TEXT_PLAIN).body(BodyInserters.fromObject("服务异常"));
}
}
@@ -0,0 +1,77 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.gateway.handle;
import com.google.code.kaptcha.Producer;
import com.pig4cloud.pigx.gateway.filter.ImageCodeGatewayFilter;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
* @author lengleng
* @date 2018/7/5
* 验证码生成逻辑处理类
*/
@Slf4j
@Component
@AllArgsConstructor
public class ImageCodeHandler implements HandlerFunction<ServerResponse> {
private final Producer producer;
private final RedisTemplate redisTemplate;
@Override
public Mono<ServerResponse> handle(ServerRequest serverRequest) {
//生成验证码
String text = producer.createText();
BufferedImage image = producer.createImage(text);
//保存验证码信息
String randomStr = serverRequest.queryParam("randomStr").get();
redisTemplate.opsForValue().set(ImageCodeGatewayFilter.DEFAULT_CODE_KEY + randomStr, text, 60, TimeUnit.SECONDS);
// 转换流信息写出
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
try {
ImageIO.write(image, "jpeg", os);
} catch (IOException e) {
log.error("ImageIO write err", e);
return Mono.error(e);
}
return ServerResponse
.status(HttpStatus.OK)
.contentType(MediaType.IMAGE_JPEG)
.body(BodyInserters.fromResource(new ByteArrayResource(os.toByteArray())));
}
}
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.gateway.handle;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
/**
* @author lengleng
* @date 2018-07-19
* SwaggerResourceHandler
*/
@Slf4j
@Component
@AllArgsConstructor
public class SwaggerResourceHandler implements HandlerFunction<ServerResponse> {
private final SwaggerResourcesProvider swaggerResources;
/**
* Handle the given request.
*
* @param request the request to handle
* @return the response
*/
@Override
public Mono<ServerResponse> handle(ServerRequest request) {
return ServerResponse.status(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(BodyInserters.fromObject(swaggerResources.get()));
}
}
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.gateway.handle;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.SecurityConfiguration;
import springfox.documentation.swagger.web.SecurityConfigurationBuilder;
import java.util.Optional;
/**
* @author lengleng
* @date 2018-07-19
* SwaggerSecurityHandler
*/
@Slf4j
@Component
public class SwaggerSecurityHandler implements HandlerFunction<ServerResponse> {
@Autowired(required = false)
private SecurityConfiguration securityConfiguration;
/**
* Handle the given request.
*
* @param request the request to handle
* @return the response
*/
@Override
public Mono<ServerResponse> handle(ServerRequest request) {
return ServerResponse.status(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(BodyInserters.fromObject(
Optional.ofNullable(securityConfiguration)
.orElse(SecurityConfigurationBuilder.builder().build())));
}
}
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.gateway.handle;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger.web.UiConfigurationBuilder;
import java.util.Optional;
/**
* @author lengleng
* @date 2018-07-19
* SwaggerUiHandler
*/
@Slf4j
@Component
public class SwaggerUiHandler implements HandlerFunction<ServerResponse> {
@Autowired(required = false)
private UiConfiguration uiConfiguration;
/**
* Handle the given request.
*
* @param request the request to handle
* @return the response
*/
@Override
public Mono<ServerResponse> handle(ServerRequest request) {
return ServerResponse.status(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(BodyInserters.fromObject(
Optional.ofNullable(uiConfiguration)
.orElse(UiConfigurationBuilder.builder().build())));
}
}