Quellcode durchsuchen

:tada: 优化鉴权逻辑,支持网关鉴权

smallchill vor 6 Jahren
Ursprung
Commit
50a18d5750

+ 5 - 0
blade-gateway/pom.xml

@@ -42,6 +42,11 @@
                 </exclusion>
             </exclusions>
         </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-starter-jwt</artifactId>
+            <version>${bladex.project.version}</version>
+        </dependency>
         <!--Spring-->
         <dependency>
             <groupId>org.springframework.cloud</groupId>

+ 4 - 3
blade-gateway/src/main/java/org/springblade/gateway/config/RouterFunctionConfiguration.java

@@ -19,6 +19,7 @@ package org.springblade.gateway.config;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springblade.gateway.handler.SwaggerResourceHandler;
+import org.springblade.gateway.props.AuthProperties;
 import org.springblade.gateway.props.RouteProperties;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.annotation.Bean;
@@ -40,7 +41,7 @@ import reactor.core.publisher.Mono;
 @Slf4j
 @Configuration
 @AllArgsConstructor
-@EnableConfigurationProperties(RouteProperties.class)
+@EnableConfigurationProperties({RouteProperties.class, AuthProperties.class})
 public class RouterFunctionConfiguration {
 
 	private final SwaggerResourceHandler swaggerResourceHandler;
@@ -48,12 +49,12 @@ public class RouterFunctionConfiguration {
 	@Bean
 	public RouterFunction routerFunction() {
 		return RouterFunctions.route(RequestPredicates.GET("/swagger-resources")
-				.and(RequestPredicates.accept(MediaType.ALL)), swaggerResourceHandler);
+			.and(RequestPredicates.accept(MediaType.ALL)), swaggerResourceHandler);
 
 	}
 
 	/**
-	 * 解决springboot2.0.5版本出现的 Only one connection receive subscriber allowed.
+	 * 解决 Only one connection receive subscriber allowed.
 	 * 参考:https://github.com/spring-cloud/spring-cloud-gateway/issues/541
 	 */
 	@Bean

+ 1 - 1
blade-gateway/src/main/java/org/springblade/gateway/dynamic/service/DynamicRouteService.java → blade-gateway/src/main/java/org/springblade/gateway/dynamic/DynamicRouteService.java

@@ -14,7 +14,7 @@
  *  this software without specific prior written permission.
  *  Author: Chill 庄骞 (smallchill@163.com)
  */
-package org.springblade.gateway.dynamic.service;
+package org.springblade.gateway.dynamic;
 
 import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
 import org.springframework.cloud.gateway.route.RouteDefinition;

+ 1 - 1
blade-gateway/src/main/java/org/springblade/gateway/dynamic/service/DynamicRouteServiceListener.java → blade-gateway/src/main/java/org/springblade/gateway/dynamic/DynamicRouteServiceListener.java

@@ -14,7 +14,7 @@
  *  this software without specific prior written permission.
  *  Author: Chill 庄骞 (smallchill@163.com)
  */
-package org.springblade.gateway.dynamic.service;
+package org.springblade.gateway.dynamic;
 
 import com.alibaba.cloud.nacos.NacosConfigProperties;
 import com.alibaba.cloud.nacos.NacosDiscoveryProperties;

+ 1 - 1
blade-gateway/src/main/java/org/springblade/gateway/dynamic/model/GatewayFilter.java → blade-gateway/src/main/java/org/springblade/gateway/dynamic/GatewayFilter.java

@@ -14,7 +14,7 @@
  *  this software without specific prior written permission.
  *  Author: Chill 庄骞 (smallchill@163.com)
  */
-package org.springblade.gateway.dynamic.model;
+package org.springblade.gateway.dynamic;
 
 import lombok.Data;
 

+ 1 - 1
blade-gateway/src/main/java/org/springblade/gateway/dynamic/model/GatewayPredicate.java → blade-gateway/src/main/java/org/springblade/gateway/dynamic/GatewayPredicate.java

@@ -14,7 +14,7 @@
  *  this software without specific prior written permission.
  *  Author: Chill 庄骞 (smallchill@163.com)
  */
-package org.springblade.gateway.dynamic.model;
+package org.springblade.gateway.dynamic;
 
 import lombok.Data;
 

+ 1 - 1
blade-gateway/src/main/java/org/springblade/gateway/dynamic/model/GatewayRoute.java → blade-gateway/src/main/java/org/springblade/gateway/dynamic/GatewayRoute.java

@@ -14,7 +14,7 @@
  *  this software without specific prior written permission.
  *  Author: Chill 庄骞 (smallchill@163.com)
  */
-package org.springblade.gateway.dynamic.model;
+package org.springblade.gateway.dynamic;
 
 
 import lombok.Data;

+ 3 - 3
blade-gateway/src/main/java/org/springblade/gateway/endpoint/RouteEndpoint.java

@@ -17,9 +17,9 @@
 package org.springblade.gateway.endpoint;
 
 import lombok.AllArgsConstructor;
-import org.springblade.gateway.dynamic.model.GatewayPredicate;
-import org.springblade.gateway.dynamic.model.GatewayRoute;
-import org.springblade.gateway.dynamic.service.DynamicRouteService;
+import org.springblade.gateway.dynamic.GatewayPredicate;
+import org.springblade.gateway.dynamic.GatewayRoute;
+import org.springblade.gateway.dynamic.DynamicRouteService;
 import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
 import org.springframework.cloud.gateway.route.RouteDefinition;
 import org.springframework.cloud.gateway.route.RouteDefinitionLocator;

+ 98 - 0
blade-gateway/src/main/java/org/springblade/gateway/filter/AuthFilter.java

@@ -0,0 +1,98 @@
+/*
+ *      Copyright (c) 2018-2028, Chill Zhuang 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 dreamlu.net 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: Chill 庄骞 (smallchill@163.com)
+ */
+package org.springblade.gateway.filter;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.jsonwebtoken.Claims;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springblade.core.jwt.JwtUtil;
+import org.springblade.gateway.props.AuthProperties;
+import org.springblade.gateway.provider.AuthProvider;
+import org.springblade.gateway.provider.ResponseProvider;
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.GlobalFilter;
+import org.springframework.core.Ordered;
+import org.springframework.core.io.buffer.DataBuffer;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.stereotype.Component;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.nio.charset.StandardCharsets;
+
+/**
+ * 鉴权认证
+ *
+ * @author Chill
+ */
+@Slf4j
+@Component
+@AllArgsConstructor
+public class AuthFilter implements GlobalFilter, Ordered {
+	private AuthProperties authProperties;
+	private ObjectMapper objectMapper;
+
+	@Override
+	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+		String path = exchange.getRequest().getURI().getPath();
+		if (isSkip(path)) {
+			return chain.filter(exchange);
+		}
+		ServerHttpResponse resp = exchange.getResponse();
+		String headerToken = exchange.getRequest().getHeaders().getFirst(AuthProvider.AUTH_HEADER);
+		String paramToken = exchange.getRequest().getQueryParams().getFirst(AuthProvider.AUTH_HEADER);
+		if (StringUtils.isAllBlank(headerToken, paramToken)) {
+			return unAuth(resp, "缺失令牌,鉴权失败");
+		}
+		String auth = StringUtils.isBlank(headerToken) ? paramToken : headerToken;
+		String token = JwtUtil.getToken(auth);
+		Claims claims = JwtUtil.parseJWT(token);
+		if (claims == null) {
+			return unAuth(resp, "请求未授权");
+		}
+		return chain.filter(exchange);
+	}
+
+	private boolean isSkip(String path) {
+		return AuthProvider.getDefaultSkipUrl().stream().map(url -> url.replace(AuthProvider.TARGET, AuthProvider.REPLACEMENT)).anyMatch(path::startsWith)
+			|| authProperties.getSkipUrl().stream().map(url -> url.replace(AuthProvider.TARGET, AuthProvider.REPLACEMENT)).anyMatch(path::startsWith);
+	}
+
+	private Mono<Void> unAuth(ServerHttpResponse resp, String msg) {
+		resp.setStatusCode(HttpStatus.UNAUTHORIZED);
+		resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
+		String result = "";
+		try {
+			result = objectMapper.writeValueAsString(ResponseProvider.unAuth(msg));
+		} catch (JsonProcessingException e) {
+			log.error(e.getMessage(), e);
+		}
+		DataBuffer buffer = resp.bufferFactory().wrap(result.getBytes(StandardCharsets.UTF_8));
+		return resp.writeWith(Flux.just(buffer));
+	}
+
+	@Override
+	public int getOrder() {
+		return -100;
+	}
+
+}

+ 1 - 1
blade-gateway/src/main/java/org/springblade/gateway/filter/RequestGlobalFilter.java → blade-gateway/src/main/java/org/springblade/gateway/filter/RequestFilter.java

@@ -25,7 +25,7 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.a
  * @author lengleng
  */
 @Component
-public class RequestGlobalFilter implements GlobalFilter, Ordered {
+public class RequestFilter implements GlobalFilter, Ordered {
 
 	/**
 	 * Process the Web request and (optionally) delegate to the next

+ 2 - 17
blade-gateway/src/main/java/org/springblade/gateway/handler/ErrorExceptionHandler.java

@@ -16,6 +16,7 @@
  */
 package org.springblade.gateway.handler;
 
+import org.springblade.gateway.provider.ResponseProvider;
 import org.springframework.boot.autoconfigure.web.ErrorProperties;
 import org.springframework.boot.autoconfigure.web.ResourceProperties;
 import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
@@ -26,7 +27,6 @@ import org.springframework.http.HttpStatus;
 import org.springframework.web.reactive.function.server.*;
 import org.springframework.web.server.ResponseStatusException;
 
-import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -54,7 +54,7 @@ public class ErrorExceptionHandler extends DefaultErrorWebExceptionHandler {
 		if (error instanceof ResponseStatusException) {
 			code = ((ResponseStatusException) error).getStatus().value();
 		}
-		return response(code, this.buildMessage(request, error));
+		return ResponseProvider.response(code, this.buildMessage(request, error));
 	}
 
 	/**
@@ -98,19 +98,4 @@ public class ErrorExceptionHandler extends DefaultErrorWebExceptionHandler {
 		return message.toString();
 	}
 
-	/**
-	 * 构建返回的JSON数据格式
-	 *
-	 * @param status       状态码
-	 * @param errorMessage 异常信息
-	 * @return
-	 */
-	public static Map<String, Object> response(int status, String errorMessage) {
-		Map<String, Object> map = new HashMap<>(16);
-		map.put("code", status);
-		map.put("message", errorMessage);
-		map.put("data", null);
-		return map;
-	}
-
 }

+ 36 - 0
blade-gateway/src/main/java/org/springblade/gateway/props/AuthProperties.java

@@ -0,0 +1,36 @@
+/*
+ *      Copyright (c) 2018-2028, Chill Zhuang 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 dreamlu.net 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: Chill 庄骞 (smallchill@163.com)
+ */
+package org.springblade.gateway.props;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 权限过滤
+ *
+ * @author Chill
+ */
+@Data
+@ConfigurationProperties("blade.secure")
+public class AuthProperties {
+
+	private final List<String> skipUrl = new ArrayList<>();
+
+}

+ 60 - 0
blade-gateway/src/main/java/org/springblade/gateway/provider/AuthProvider.java

@@ -0,0 +1,60 @@
+/*
+ *      Copyright (c) 2018-2028, Chill Zhuang 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 dreamlu.net 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: Chill 庄骞 (smallchill@163.com)
+ */
+package org.springblade.gateway.provider;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 鉴权配置
+ *
+ * @author Chill
+ */
+public class AuthProvider {
+
+	public static String TARGET = "/**";
+	public static String REPLACEMENT = "";
+	public static String AUTH_HEADER = "Blade-Auth";
+	private static List<String> defaultSkipUrl = new ArrayList<>();
+
+	static {
+		defaultSkipUrl.add("/client/**");
+		defaultSkipUrl.add("/oauth/token/**");
+		defaultSkipUrl.add("/token/**");
+		defaultSkipUrl.add("/actuator/health/**");
+		defaultSkipUrl.add("/v2/api-docs/**");
+		defaultSkipUrl.add("/v2/api-docs-ext/**");
+		defaultSkipUrl.add("/auth/**");
+		defaultSkipUrl.add("/log/**");
+		defaultSkipUrl.add("/menu/routes");
+		defaultSkipUrl.add("/menu/auth-routes");
+		defaultSkipUrl.add("/menu/top-menu");
+		defaultSkipUrl.add("/process/resource-view");
+		defaultSkipUrl.add("/process/diagram-view");
+		defaultSkipUrl.add("/manager/check-upload");
+		defaultSkipUrl.add("/error/**");
+		defaultSkipUrl.add("/assets/**");
+	}
+
+	/**
+	 * 默认无需鉴权的API
+	 */
+	public static List<String> getDefaultSkipUrl() {
+		return defaultSkipUrl;
+	}
+
+}

+ 84 - 0
blade-gateway/src/main/java/org/springblade/gateway/provider/ResponseProvider.java

@@ -0,0 +1,84 @@
+/*
+ *      Copyright (c) 2018-2028, Chill Zhuang 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 dreamlu.net 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: Chill 庄骞 (smallchill@163.com)
+ */
+package org.springblade.gateway.provider;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 请求响应返回
+ *
+ * @author Chill
+ */
+public class ResponseProvider {
+
+	/**
+	 * 成功
+	 *
+	 * @param message 信息
+	 * @return
+	 */
+	public static Map<String, Object> success(String message) {
+		return response(200, message);
+	}
+
+	/**
+	 * 失败
+	 *
+	 * @param message 信息
+	 * @return
+	 */
+	public static Map<String, Object> fail(String message) {
+		return response(400, message);
+	}
+
+	/**
+	 * 未授权
+	 *
+	 * @param message 信息
+	 * @return
+	 */
+	public static Map<String, Object> unAuth(String message) {
+		return response(401, message);
+	}
+
+	/**
+	 * 服务器异常
+	 *
+	 * @param message 信息
+	 * @return
+	 */
+	public static Map<String, Object> error(String message) {
+		return response(500, message);
+	}
+
+	/**
+	 * 构建返回的JSON数据格式
+	 *
+	 * @param status  状态码
+	 * @param message 信息
+	 * @return
+	 */
+	public static Map<String, Object> response(int status, String message) {
+		Map<String, Object> map = new HashMap<>(16);
+		map.put("code", status);
+		map.put("message", message);
+		map.put("data", null);
+		return map;
+	}
+
+}

+ 0 - 1
blade-gateway/src/main/java/org/springblade/gateway/provider/SwaggerProvider.java

@@ -14,7 +14,6 @@
  *  this software without specific prior written permission.
  *  Author: Chill 庄骞 (smallchill@163.com)
  */
-
 package org.springblade.gateway.provider;
 
 import lombok.AllArgsConstructor;

+ 5 - 7
doc/nacos/blade.yaml

@@ -69,14 +69,12 @@ management:
 #blade配置
 blade:
   xss:
-    url:
-      exclude-patterns:
-        - /weixin
-        - /notice/submit
+    skip-url:
+      - /weixin
+      - /notice/submit
   secure:
-    url:
-      exclude-patterns:
-        - /test/**
+    skip-url:
+      - /test/**
     client:
       - client-id: sword
         path-patterns: