diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermitAllUrlProperties.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermitAllUrlProperties.java index 32b44a7be..c71fd7e3a 100755 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermitAllUrlProperties.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PermitAllUrlProperties.java @@ -42,33 +42,46 @@ import java.util.regex.Pattern; @ConfigurationProperties(prefix = "security.oauth2.client") public class PermitAllUrlProperties implements InitializingBean { - private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}"); + private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}"); - private static final String[] DEFAULT_IGNORE_URLS = new String[] { "/actuator/**", "/error", "/v3/api-docs" }; + private static final String[] DEFAULT_IGNORE_URLS = new String[]{"/actuator/**", "/error", "/v3/api-docs"}; - @Getter - @Setter - private List ignoreUrls = new ArrayList<>(); + @Getter + @Setter + private List ignoreUrls = new ArrayList<>(); - @Override - public void afterPropertiesSet() { - ignoreUrls.addAll(Arrays.asList(DEFAULT_IGNORE_URLS)); - RequestMappingHandlerMapping mapping = SpringContextHolder.getBean("requestMappingHandlerMapping"); - Map map = mapping.getHandlerMethods(); + /** + * 跳过对外 URL + *

+ * 比如某个接口是对外开放的,即使携带 token,也不鉴权 + */ + @Getter + @Setter + private boolean skipPublicUrl = false; - map.keySet().forEach(info -> { - HandlerMethod handlerMethod = map.get(info); + @Override + public void afterPropertiesSet() { + ignoreUrls.addAll(Arrays.asList(DEFAULT_IGNORE_URLS)); + RequestMappingHandlerMapping mapping = SpringContextHolder.getBean("requestMappingHandlerMapping"); + Map map = mapping.getHandlerMethods(); - // 获取方法上边的注解 替代path variable 为 * - Inner method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Inner.class); - Optional.ofNullable(method).ifPresent(inner -> Objects.requireNonNull(info.getPathPatternsCondition()) - .getPatternValues().forEach(url -> ignoreUrls.add(ReUtil.replaceAll(url, PATTERN, "*")))); + map.keySet().forEach(info -> { + HandlerMethod handlerMethod = map.get(info); - // 获取类上边的注解, 替代path variable 为 * - Inner controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Inner.class); - Optional.ofNullable(controller).ifPresent(inner -> Objects.requireNonNull(info.getPathPatternsCondition()) - .getPatternValues().forEach(url -> ignoreUrls.add(ReUtil.replaceAll(url, PATTERN, "*")))); - }); - } + // 获取方法上边的注解 替代path variable 为 * + Inner method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Inner.class); + Optional.ofNullable(method) + .ifPresent(inner -> Objects.requireNonNull(info.getPathPatternsCondition()) + .getPatternValues() + .forEach(url -> ignoreUrls.add(ReUtil.replaceAll(url, PATTERN, "*")))); + + // 获取类上边的注解, 替代path variable 为 * + Inner controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Inner.class); + Optional.ofNullable(controller) + .ifPresent(inner -> Objects.requireNonNull(info.getPathPatternsCondition()) + .getPatternValues() + .forEach(url -> ignoreUrls.add(ReUtil.replaceAll(url, PATTERN, "*")))); + }); + } } diff --git a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxBearerTokenExtractor.java b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxBearerTokenExtractor.java index cc62cc62a..0649dc936 100644 --- a/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxBearerTokenExtractor.java +++ b/pigx-common/pigx-common-security/src/main/java/com/pig4cloud/pigx/common/security/component/PigxBearerTokenExtractor.java @@ -17,7 +17,6 @@ package com.pig4cloud.pigx.common.security.component; import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.server.resource.BearerTokenError; import org.springframework.security.oauth2.server.resource.BearerTokenErrors; @@ -36,86 +35,84 @@ import java.util.regex.Pattern; */ public class PigxBearerTokenExtractor implements BearerTokenResolver { - private static final Pattern authorizationPattern = Pattern.compile("^Bearer (?[a-zA-Z0-9-:._~+/]+=*)$", - Pattern.CASE_INSENSITIVE); + private static final Pattern authorizationPattern = Pattern.compile("^Bearer (?[a-zA-Z0-9-:._~+/]+=*)$", + Pattern.CASE_INSENSITIVE); - private boolean allowFormEncodedBodyParameter = false; - private boolean allowUriQueryParameter = true; + private String bearerTokenHeaderName = HttpHeaders.AUTHORIZATION; - private String bearerTokenHeaderName = HttpHeaders.AUTHORIZATION; + private final PathMatcher pathMatcher = new AntPathMatcher(); - private final PathMatcher pathMatcher = new AntPathMatcher(); + private final PermitAllUrlProperties urlProperties; - private final PermitAllUrlProperties urlProperties; + public PigxBearerTokenExtractor(PermitAllUrlProperties urlProperties) { + this.urlProperties = urlProperties; + } - public PigxBearerTokenExtractor(PermitAllUrlProperties urlProperties) { - this.urlProperties = urlProperties; - } + /** + * 解析令牌 + * + * @param request 请求 + * @return {@link String } + */ + @Override + public String resolve(HttpServletRequest request) { + String requestUri = request.getRequestURI(); + String relativePath = requestUri.substring(request.getContextPath().length()); - @Override - public String resolve(HttpServletRequest request) { - String requestUri = request.getRequestURI(); - String relativePath = requestUri.substring(request.getContextPath().length()); + if (urlProperties.isSkipPublicUrl()) { + boolean match = urlProperties.getIgnoreUrls().stream().anyMatch(url -> pathMatcher.match(url, relativePath)); - boolean match = urlProperties.getIgnoreUrls().stream().anyMatch(url -> pathMatcher.match(url, relativePath)); + if (match) { + return null; + } + } - if (match) { - return null; - } - final String authorizationHeaderToken = resolveFromAuthorizationHeader(request); - final String parameterToken = isParameterTokenSupportedForRequest(request) - ? resolveFromRequestParameters(request) : null; - if (authorizationHeaderToken != null) { - if (parameterToken != null) { - final BearerTokenError error = BearerTokenErrors - .invalidRequest("Found multiple bearer tokens in the request"); - throw new OAuth2AuthenticationException(error); - } - return authorizationHeaderToken; - } - if (parameterToken != null && isParameterTokenEnabledForRequest(request)) { - return parameterToken; - } - return null; - } + final String authorizationHeaderToken = resolveFromAuthorizationHeader(request); - private String resolveFromAuthorizationHeader(HttpServletRequest request) { - String authorization = request.getHeader(this.bearerTokenHeaderName); - if (!StringUtils.startsWithIgnoreCase(authorization, "bearer")) { - return null; - } - Matcher matcher = authorizationPattern.matcher(authorization); - if (!matcher.matches()) { - BearerTokenError error = BearerTokenErrors.invalidToken("Bearer token is malformed"); - throw new OAuth2AuthenticationException(error); - } - return matcher.group("token"); - } + if (authorizationHeaderToken != null) { + return authorizationHeaderToken; + } - private static String resolveFromRequestParameters(HttpServletRequest request) { - String[] values = request.getParameterValues("access_token"); - if (values == null || values.length == 0) { - return null; - } - if (values.length == 1) { - return values[0]; - } - BearerTokenError error = BearerTokenErrors.invalidRequest("Found multiple bearer tokens in the request"); - throw new OAuth2AuthenticationException(error); - } + return resolveFromRequestParameters(request); + } - private boolean isParameterTokenSupportedForRequest(final HttpServletRequest request) { - return (("POST".equals(request.getMethod()) - && MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(request.getContentType())) - || "GET".equals(request.getMethod())); - } + /** + * 从授权标头解析 + * + * @param request 请求 + * @return {@link String } + */ + private String resolveFromAuthorizationHeader(HttpServletRequest request) { + String authorization = request.getHeader(this.bearerTokenHeaderName); + if (!StringUtils.startsWithIgnoreCase(authorization, "bearer")) { + return null; + } + Matcher matcher = authorizationPattern.matcher(authorization); + if (!matcher.matches()) { + BearerTokenError error = BearerTokenErrors.invalidToken("Bearer token is malformed"); + throw new OAuth2AuthenticationException(error); + } + return matcher.group("token"); + } - private boolean isParameterTokenEnabledForRequest(final HttpServletRequest request) { - return ((this.allowFormEncodedBodyParameter && "POST".equals(request.getMethod()) - && MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(request.getContentType())) - || (this.allowUriQueryParameter && "GET".equals(request.getMethod()))); - } + /** + * 从请求参数解析 + * + * @param request 请求 + * @return {@link String } + */ + private static String resolveFromRequestParameters(HttpServletRequest request) { + String[] values = request.getParameterValues("access_token"); + if (values == null || values.length == 0) { + return null; + } + if (values.length == 1) { + return values[0]; + } + BearerTokenError error = BearerTokenErrors.invalidRequest("Found multiple bearer tokens in the request"); + throw new OAuth2AuthenticationException(error); + } }