refactor(common): security 增加配置项,如果设置 skipPublicUrl true 如果接口对外设置,即使携带token 也不鉴权

This commit is contained in:
冷冷 committed 2024-08-21 22:46:48 +08:00
1 parent 8be6f31786
commit f738bed680
2 files changed
+100 -90

No files matched your search

@@ -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<String> ignoreUrls = new ArrayList<>();
@Getter
@Setter
private List<String> ignoreUrls = new ArrayList<>();
@Override
public void afterPropertiesSet() {
ignoreUrls.addAll(Arrays.asList(DEFAULT_IGNORE_URLS));
RequestMappingHandlerMapping mapping = SpringContextHolder.getBean("requestMappingHandlerMapping");
Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
/**
* 跳过对外 URL
* <p>
* 比如某个接口是对外开放的,即使携带 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<RequestMappingInfo, HandlerMethod> 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, "*"))));
});
}
}
@@ -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 (?<token>[a-zA-Z0-9-:._~+/]+=*)$",
Pattern.CASE_INSENSITIVE);
private static final Pattern authorizationPattern = Pattern.compile("^Bearer (?<token>[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);
}
}