mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 21:57:56 +08:00
网关可校验token
This commit is contained in:
@@ -32,12 +32,14 @@ import com.gitee.sop.gatewaycommon.validate.ApiSigner;
|
||||
import com.gitee.sop.gatewaycommon.validate.ApiValidator;
|
||||
import com.gitee.sop.gatewaycommon.validate.Encrypter;
|
||||
import com.gitee.sop.gatewaycommon.validate.Signer;
|
||||
import com.gitee.sop.gatewaycommon.validate.TokenValidator;
|
||||
import com.gitee.sop.gatewaycommon.validate.Validator;
|
||||
import com.gitee.sop.gatewaycommon.zuul.configuration.ZuulErrorController;
|
||||
import com.gitee.sop.gatewaycommon.zuul.param.ZuulParamBuilder;
|
||||
import com.gitee.sop.gatewaycommon.zuul.result.ZuulResultExecutor;
|
||||
import com.netflix.zuul.context.RequestContext;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -152,6 +154,11 @@ public class ApiConfig {
|
||||
|
||||
private ParameterFormatter parameterFormatter;
|
||||
|
||||
/**
|
||||
* 校验token
|
||||
*/
|
||||
private TokenValidator tokenValidator = apiParam -> apiParam != null && StringUtils.isNotBlank(apiParam.fetchAccessToken());
|
||||
|
||||
// -------- fields ---------
|
||||
|
||||
/**
|
||||
|
@@ -1,46 +0,0 @@
|
||||
package com.gitee.sop.gatewaycommon.bean;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class BaseRouteDefinition {
|
||||
|
||||
/**
|
||||
* 路由的Id
|
||||
*/
|
||||
private String id;
|
||||
/**
|
||||
* 路由规则转发的目标uri
|
||||
*/
|
||||
private String uri;
|
||||
|
||||
/**
|
||||
* uri后面跟的path
|
||||
*/
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* 路由执行的顺序
|
||||
*/
|
||||
private int order = 0;
|
||||
|
||||
/**
|
||||
* 是否忽略验证,业务参数验证除外
|
||||
*/
|
||||
private int ignoreValidate;
|
||||
|
||||
/**
|
||||
* 是否合并结果
|
||||
*/
|
||||
private int mergeResult;
|
||||
|
||||
/**
|
||||
* 接口是否需要授权才能访问
|
||||
*/
|
||||
private int permission;
|
||||
}
|
@@ -1,19 +0,0 @@
|
||||
package com.gitee.sop.gatewaycommon.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Data
|
||||
public class BaseServiceRouteInfo<T extends BaseRouteDefinition> {
|
||||
private String serviceId;
|
||||
private List<T> routeDefinitionList = Collections.emptyList();
|
||||
|
||||
public String fetchServiceIdLowerCase() {
|
||||
return this.serviceId.toLowerCase();
|
||||
}
|
||||
}
|
@@ -70,4 +70,9 @@ public class RouteDefinition {
|
||||
* 是否需要授权才能访问
|
||||
*/
|
||||
private int permission;
|
||||
|
||||
/**
|
||||
* 是否需要token
|
||||
*/
|
||||
private int needToken;
|
||||
}
|
@@ -16,6 +16,8 @@ import com.gitee.sop.gatewaycommon.manager.AbstractConfiguration;
|
||||
import com.gitee.sop.gatewaycommon.manager.RouteRepositoryContext;
|
||||
import com.gitee.sop.gatewaycommon.param.ParamBuilder;
|
||||
import com.gitee.sop.gatewaycommon.param.ParamNames;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
@@ -25,13 +27,19 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
||||
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.reactive.function.BodyInserters;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicate;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicates;
|
||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||
import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import org.springframework.web.reactive.result.view.ViewResolver;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
@@ -41,6 +49,7 @@ import java.util.List;
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@Slf4j
|
||||
public class BaseGatewayConfiguration extends AbstractConfiguration {
|
||||
|
||||
public BaseGatewayConfiguration() {
|
||||
@@ -152,12 +161,20 @@ public class BaseGatewayConfiguration extends AbstractConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "sop.restful.enable", havingValue = "true")
|
||||
RouterFunction<ServerResponse> routerFunction() {
|
||||
return RouterFunctions.route(RequestPredicates.GET(restPath + "/**"), (serverRequest) -> {
|
||||
String url = serverRequest.path();
|
||||
int index = url.indexOf(restPath);
|
||||
RequestPredicate requestPredicate = RequestPredicates.all()
|
||||
.and(RequestPredicates.path(restPath + "/**"));
|
||||
return RouterFunctions.route(requestPredicate, (serverRequest) -> {
|
||||
String path = serverRequest.path();
|
||||
int index = path.indexOf(restPath);
|
||||
// 取/rest的后面部分
|
||||
String path = url.substring(index + restPath.length());
|
||||
String query = ParamNames.API_NAME + "=" + path + "&" + ParamNames.VERSION_NAME + "=";
|
||||
String servletPath = path.substring(index + restPath.length());
|
||||
String query = serverRequest.uri().getQuery();
|
||||
String appendQuery = ParamNames.API_NAME + "=" + servletPath + "&" + ParamNames.VERSION_NAME + "=";
|
||||
if (StringUtils.isBlank(query)) {
|
||||
query = appendQuery;
|
||||
} else {
|
||||
query += '&' + appendQuery;
|
||||
}
|
||||
return ServerResponse
|
||||
.temporaryRedirect(URI.create("/?" + query))
|
||||
.build();
|
||||
|
@@ -21,7 +21,12 @@ public enum EnvironmentKeys {
|
||||
/**
|
||||
* sop.restful.enable=true,开启传统web开发模式
|
||||
*/
|
||||
SOP_RESTFUL_ENABLE("sop.restful.enable");
|
||||
SOP_RESTFUL_ENABLE("sop.restful.enable"),
|
||||
|
||||
/**
|
||||
* sop.restful.path=/xx ,指定请求前缀,默认/rest
|
||||
*/
|
||||
SOP_RESTFUL_PATH("sop.restful.path", "/rest");
|
||||
|
||||
private String key;
|
||||
private String defaultValue;
|
||||
|
@@ -83,6 +83,7 @@ public class ApiValidator implements Validator {
|
||||
checkFormat(param);
|
||||
checkUploadFile(param);
|
||||
checkPermission(param);
|
||||
checkToken(param);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -238,7 +239,7 @@ public class ApiValidator implements Validator {
|
||||
/**
|
||||
* 校验访问权限
|
||||
*
|
||||
* @param apiParam
|
||||
* @param apiParam 参数
|
||||
*/
|
||||
protected void checkPermission(ApiParam apiParam) {
|
||||
String routeId = apiParam.fetchNameVersion();
|
||||
@@ -254,4 +255,23 @@ public class ApiValidator implements Validator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验token
|
||||
*
|
||||
* @param apiParam 参数
|
||||
*/
|
||||
protected void checkToken(ApiParam apiParam) {
|
||||
String routeId = apiParam.fetchNameVersion();
|
||||
TargetRoute targetRoute = RouteRepositoryContext.getRouteRepository().get(routeId);
|
||||
RouteDefinition routeDefinition = targetRoute.getRouteDefinition();
|
||||
boolean needToken = BooleanUtils.toBoolean(routeDefinition.getNeedToken());
|
||||
if (needToken) {
|
||||
TokenValidator tokenValidator = ApiConfig.getInstance().getTokenValidator();
|
||||
boolean rightToken = tokenValidator.validateToken(apiParam);
|
||||
if (!rightToken) {
|
||||
throw ErrorEnum.AOP_INVALID_APP_AUTH_TOKEN.getErrorMeta().getException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,11 @@
|
||||
package com.gitee.sop.gatewaycommon.validate;
|
||||
|
||||
import com.gitee.sop.gatewaycommon.param.ApiParam;
|
||||
|
||||
/**
|
||||
* @author tanghc
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface TokenValidator {
|
||||
boolean validateToken(ApiParam apiParam);
|
||||
}
|
@@ -35,4 +35,9 @@ public @interface ApiAbility {
|
||||
* 指定接口是否需要授权才能访问,可在admin中进行修改
|
||||
*/
|
||||
boolean permission() default false;
|
||||
|
||||
/**
|
||||
* 是否需要appAuthToken,设置为true,网关端会校验token是否存在
|
||||
*/
|
||||
boolean needToken() default false;
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@ public @interface ApiMapping {
|
||||
|
||||
/**
|
||||
* 版本号,默认版本号是""<br>
|
||||
* 改默认版本号:<code>ServiceContext.getSopServerConfig().setDefaultVersion("1.0");</code>
|
||||
* 改默认版本号:<code>ServiceConfig.getInstance().setDefaultVersion("1.0");</code>
|
||||
*/
|
||||
String version() default "";
|
||||
|
||||
@@ -44,6 +44,11 @@ public @interface ApiMapping {
|
||||
*/
|
||||
boolean permission() default false;
|
||||
|
||||
/**
|
||||
* 是否需要appAuthToken,设置为true,网关端会校验token是否存在
|
||||
*/
|
||||
boolean needToken() default false;
|
||||
|
||||
// ------------ 自定义属性 end ------------
|
||||
|
||||
|
||||
|
@@ -80,12 +80,23 @@ public interface OpenContext<T> extends OpenBeanFactory {
|
||||
*/
|
||||
Date getTimestamp();
|
||||
|
||||
/**
|
||||
* 返回token,即access_token.
|
||||
*
|
||||
* @deprecated 废弃,使用getAppAuthToken()
|
||||
* @return 返回token
|
||||
*/
|
||||
@Deprecated
|
||||
String appAuthToken();
|
||||
|
||||
/**
|
||||
* 返回token,即access_token
|
||||
*
|
||||
* @return 返回token
|
||||
*/
|
||||
String appAuthToken();
|
||||
default String getAppAuthToken() {
|
||||
return appAuthToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回回调地址
|
||||
|
@@ -28,6 +28,8 @@ public class ServiceApiInfo {
|
||||
private int mergeResult;
|
||||
/** 是否需要授权才能访问 */
|
||||
private int permission;
|
||||
/** 是否需要token */
|
||||
private int needToken;
|
||||
/** 是否是原始Mapping */
|
||||
private boolean originalMapping;
|
||||
|
||||
|
@@ -87,6 +87,7 @@ public class ApiMetaBuilder {
|
||||
apiMeta.setIgnoreValidate(BooleanUtils.toInteger(apiMappingInfo.isIgnoreValidate()));
|
||||
apiMeta.setMergeResult(BooleanUtils.toInteger(apiMappingInfo.isMergeResult()));
|
||||
apiMeta.setPermission(BooleanUtils.toInteger(apiMappingInfo.isPermission()));
|
||||
apiMeta.setNeedToken(BooleanUtils.toInteger(apiMappingInfo.isNeedToken()));
|
||||
return apiMeta;
|
||||
} else {
|
||||
if (!ServiceContext.getCurrentContext().getBoolean(ServiceContext.RESTFUL_KEY, false)) {
|
||||
|
@@ -50,8 +50,8 @@ public class ServiceRouteInfoBuilder {
|
||||
List<ServiceApiInfo.ApiMeta> apis = serviceApiInfo.getApis();
|
||||
List<RouteDefinition> routeDefinitionList = new ArrayList<>(apis.size());
|
||||
for (ServiceApiInfo.ApiMeta apiMeta : apis) {
|
||||
RouteDefinition gatewayRouteDefinition = this.buildGatewayRouteDefinition(serviceApiInfo, apiMeta);
|
||||
routeDefinitionList.add(gatewayRouteDefinition);
|
||||
RouteDefinition routeDefinition = this.buildGatewayRouteDefinition(serviceApiInfo, apiMeta);
|
||||
routeDefinitionList.add(routeDefinition);
|
||||
}
|
||||
ServiceRouteInfo serviceRouteInfo = new ServiceRouteInfo();
|
||||
serviceRouteInfo.setServiceId(serviceApiInfo.getServiceId());
|
||||
|
@@ -35,9 +35,10 @@ public class ApiMappingHandlerMapping extends RequestMappingHandlerMapping imple
|
||||
method.setAccessible(true);
|
||||
String name = null;
|
||||
String version;
|
||||
boolean ignoreValidate = false;
|
||||
boolean mergeResult = true;
|
||||
boolean permission = false;
|
||||
boolean ignoreValidate;
|
||||
boolean mergeResult;
|
||||
boolean permission;
|
||||
boolean needToken = false;
|
||||
ApiMapping apiMapping = method.getAnnotation(ApiMapping.class);
|
||||
if (apiMapping != null) {
|
||||
name = apiMapping.value()[0];
|
||||
@@ -45,6 +46,7 @@ public class ApiMappingHandlerMapping extends RequestMappingHandlerMapping imple
|
||||
ignoreValidate = apiMapping.ignoreValidate();
|
||||
mergeResult = apiMapping.mergeResult();
|
||||
permission = apiMapping.permission();
|
||||
needToken = apiMapping.needToken();
|
||||
} else {
|
||||
ApiAbility apiAbility = this.findApiAbilityAnnotation(method);
|
||||
if (apiAbility != null) {
|
||||
@@ -52,6 +54,7 @@ public class ApiMappingHandlerMapping extends RequestMappingHandlerMapping imple
|
||||
ignoreValidate = apiAbility.ignoreValidate();
|
||||
mergeResult = apiAbility.mergeResult();
|
||||
permission = apiAbility.permission();
|
||||
needToken = apiAbility.needToken();
|
||||
} else {
|
||||
return super.getCustomMethodCondition(method);
|
||||
}
|
||||
@@ -75,6 +78,7 @@ public class ApiMappingHandlerMapping extends RequestMappingHandlerMapping imple
|
||||
apiMappingInfo.setIgnoreValidate(ignoreValidate);
|
||||
apiMappingInfo.setMergeResult(mergeResult);
|
||||
apiMappingInfo.setPermission(permission);
|
||||
apiMappingInfo.setNeedToken(needToken);
|
||||
logger.info("注册接口,name:" + method + ", version:" + version);
|
||||
return new ApiMappingRequestCondition(apiMappingInfo);
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@ public class ApiMappingInfo {
|
||||
private boolean ignoreValidate;
|
||||
private boolean mergeResult;
|
||||
private boolean permission;
|
||||
private boolean needToken;
|
||||
|
||||
public ApiMappingInfo(String name, String version) {
|
||||
this.name = name;
|
||||
|
@@ -68,4 +68,9 @@ public class RouteDefinition {
|
||||
* 是否需要授权才能访问
|
||||
*/
|
||||
private int permission;
|
||||
|
||||
/**
|
||||
* 是否需要token
|
||||
*/
|
||||
private int needToken;
|
||||
}
|
Reference in New Issue
Block a user