refactor: 优化匿名访问URL处理逻辑,优化Swagger接口认证配置
This commit is contained in:
parent
15599f8f6e
commit
fc5fbe0c85
@ -15,7 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package me.zhengjie.config.webmvc;
|
package me.zhengjie.config.webmvc;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import me.zhengjie.utils.AnonTagUtils;
|
||||||
|
import me.zhengjie.utils.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import springfox.documentation.builders.ApiInfoBuilder;
|
import springfox.documentation.builders.ApiInfoBuilder;
|
||||||
@ -31,6 +35,9 @@ import springfox.documentation.spring.web.plugins.Docket;
|
|||||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* api页面 /doc.html
|
* api页面 /doc.html
|
||||||
@ -39,14 +46,20 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableSwagger2
|
@EnableSwagger2
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class SwaggerConfig {
|
public class SwaggerConfig {
|
||||||
|
|
||||||
|
@Value("${server.servlet.context-path:}")
|
||||||
|
private String apiPath;
|
||||||
|
|
||||||
@Value("${jwt.header}")
|
@Value("${jwt.header}")
|
||||||
private String tokenHeader;
|
private String tokenHeader;
|
||||||
|
|
||||||
@Value("${swagger.enabled}")
|
@Value("${swagger.enabled}")
|
||||||
private Boolean enabled;
|
private Boolean enabled;
|
||||||
|
|
||||||
|
private final ApplicationContext applicationContext;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@SuppressWarnings("all")
|
@SuppressWarnings("all")
|
||||||
public Docket createRestApi() {
|
public Docket createRestApi() {
|
||||||
@ -87,10 +100,14 @@ public class SwaggerConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private SecurityContext getContextByPath() {
|
private SecurityContext getContextByPath() {
|
||||||
|
Set<String> urls = AnonTagUtils.getAllAnonymousUrl(applicationContext);
|
||||||
|
urls = urls.stream().filter(url -> !url.equals("/")).collect(Collectors.toSet());
|
||||||
|
String regExp = "^(?!" + apiPath + String.join("|" + apiPath, urls) + ").*$";
|
||||||
return SecurityContext.builder()
|
return SecurityContext.builder()
|
||||||
.securityReferences(defaultAuth())
|
.securityReferences(defaultAuth())
|
||||||
// 表示 /auth/code、/auth/login 接口不需要使用securitySchemes即不需要带token
|
.operationSelector(o->o.requestMappingPattern()
|
||||||
.operationSelector(o->o.requestMappingPattern().matches("^(?!/auth/code|/auth/login).*$"))
|
// 排除不需要认证的接口
|
||||||
|
.matches(regExp))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019-2020 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package me.zhengjie.utils;
|
||||||
|
|
||||||
|
import me.zhengjie.annotation.AnonymousAccess;
|
||||||
|
import me.zhengjie.utils.enums.RequestMethodEnum;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.method.HandlerMethod;
|
||||||
|
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Zheng Jie
|
||||||
|
* @description 匿名标记工具
|
||||||
|
* @date 2025-01-13
|
||||||
|
**/
|
||||||
|
public class AnonTagUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取匿名标记的URL
|
||||||
|
* @param applicationContext /
|
||||||
|
* @return /
|
||||||
|
*/
|
||||||
|
public static Map<String, Set<String>> getAnonymousUrl(ApplicationContext applicationContext){
|
||||||
|
RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) applicationContext.getBean("requestMappingHandlerMapping");
|
||||||
|
Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods();
|
||||||
|
Map<String, Set<String>> anonymousUrls = new HashMap<>(8);
|
||||||
|
// 获取匿名标记
|
||||||
|
Set<String> get = new HashSet<>();
|
||||||
|
Set<String> post = new HashSet<>();
|
||||||
|
Set<String> put = new HashSet<>();
|
||||||
|
Set<String> patch = new HashSet<>();
|
||||||
|
Set<String> delete = new HashSet<>();
|
||||||
|
Set<String> all = new HashSet<>();
|
||||||
|
for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {
|
||||||
|
HandlerMethod handlerMethod = infoEntry.getValue();
|
||||||
|
AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);
|
||||||
|
if (null != anonymousAccess) {
|
||||||
|
List<RequestMethod> requestMethods = new ArrayList<>(infoEntry.getKey().getMethodsCondition().getMethods());
|
||||||
|
RequestMethodEnum request = RequestMethodEnum.find(requestMethods.isEmpty() ? RequestMethodEnum.ALL.getType() : requestMethods.get(0).name());
|
||||||
|
if (infoEntry.getKey().getPatternsCondition()!=null) {
|
||||||
|
switch (Objects.requireNonNull(request)) {
|
||||||
|
case GET:
|
||||||
|
get.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
|
||||||
|
break;
|
||||||
|
case POST:
|
||||||
|
post.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
|
||||||
|
break;
|
||||||
|
case PUT:
|
||||||
|
put.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
|
||||||
|
break;
|
||||||
|
case PATCH:
|
||||||
|
patch.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
|
||||||
|
break;
|
||||||
|
case DELETE:
|
||||||
|
delete.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
all.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
anonymousUrls.put(RequestMethodEnum.GET.getType(), get);
|
||||||
|
anonymousUrls.put(RequestMethodEnum.POST.getType(), post);
|
||||||
|
anonymousUrls.put(RequestMethodEnum.PUT.getType(), put);
|
||||||
|
anonymousUrls.put(RequestMethodEnum.PATCH.getType(), patch);
|
||||||
|
anonymousUrls.put(RequestMethodEnum.DELETE.getType(), delete);
|
||||||
|
anonymousUrls.put(RequestMethodEnum.ALL.getType(), all);
|
||||||
|
return anonymousUrls;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有匿名标记的URL
|
||||||
|
* @param applicationContext /
|
||||||
|
* @return /
|
||||||
|
*/
|
||||||
|
public static Set<String> getAllAnonymousUrl(ApplicationContext applicationContext){
|
||||||
|
Set<String> allUrl = new HashSet<>();
|
||||||
|
Map<String, Set<String>> anonymousUrls = getAnonymousUrl(applicationContext);
|
||||||
|
for (String key : anonymousUrls.keySet()) {
|
||||||
|
allUrl.addAll(anonymousUrls.get(key));
|
||||||
|
}
|
||||||
|
return allUrl;
|
||||||
|
}
|
||||||
|
}
|
@ -46,7 +46,6 @@ public class AppRun {
|
|||||||
springApplication.addListeners(new ApplicationPidFileWriter());
|
springApplication.addListeners(new ApplicationPidFileWriter());
|
||||||
springApplication.run(args);
|
springApplication.run(args);
|
||||||
log.info("---------------------------------------------");
|
log.info("---------------------------------------------");
|
||||||
log.info("Backend service started successfully");
|
|
||||||
log.info("Local: {}", "http://localhost:8000");
|
log.info("Local: {}", "http://localhost:8000");
|
||||||
log.info("Swagger: {}", "http://localhost:8000/doc.html");
|
log.info("Swagger: {}", "http://localhost:8000/doc.html");
|
||||||
log.info("---------------------------------------------");
|
log.info("---------------------------------------------");
|
||||||
@ -59,7 +58,6 @@ public class AppRun {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 访问首页提示
|
* 访问首页提示
|
||||||
*
|
|
||||||
* @return /
|
* @return /
|
||||||
*/
|
*/
|
||||||
@AnonymousGetMapping("/")
|
@AnonymousGetMapping("/")
|
||||||
|
@ -16,11 +16,11 @@
|
|||||||
package me.zhengjie.modules.security.config;
|
package me.zhengjie.modules.security.config;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import me.zhengjie.annotation.AnonymousAccess;
|
|
||||||
import me.zhengjie.modules.security.config.bean.SecurityProperties;
|
import me.zhengjie.modules.security.config.bean.SecurityProperties;
|
||||||
import me.zhengjie.modules.security.security.*;
|
import me.zhengjie.modules.security.security.*;
|
||||||
import me.zhengjie.modules.security.service.OnlineUserService;
|
import me.zhengjie.modules.security.service.OnlineUserService;
|
||||||
import me.zhengjie.modules.security.service.UserCacheManager;
|
import me.zhengjie.modules.security.service.UserCacheManager;
|
||||||
|
import me.zhengjie.utils.AnonTagUtils;
|
||||||
import me.zhengjie.utils.enums.RequestMethodEnum;
|
import me.zhengjie.utils.enums.RequestMethodEnum;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@ -35,11 +35,7 @@ import org.springframework.security.config.http.SessionCreationPolicy;
|
|||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
import org.springframework.web.filter.CorsFilter;
|
import org.springframework.web.filter.CorsFilter;
|
||||||
import org.springframework.web.method.HandlerMethod;
|
|
||||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,11 +70,8 @@ public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure(HttpSecurity httpSecurity) throws Exception {
|
protected void configure(HttpSecurity httpSecurity) throws Exception {
|
||||||
// 搜寻匿名标记 url: @AnonymousAccess
|
|
||||||
RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) applicationContext.getBean("requestMappingHandlerMapping");
|
|
||||||
Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods();
|
|
||||||
// 获取匿名标记
|
// 获取匿名标记
|
||||||
Map<String, Set<String>> anonymousUrls = getAnonymousUrl(handlerMethodMap);
|
Map<String, Set<String>> anonymousUrls = AnonTagUtils.getAnonymousUrl(applicationContext);
|
||||||
httpSecurity
|
httpSecurity
|
||||||
// 禁用 CSRF
|
// 禁用 CSRF
|
||||||
.csrf().disable()
|
.csrf().disable()
|
||||||
@ -140,49 +133,4 @@ public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
private TokenConfigurer securityConfigurerAdapter() {
|
private TokenConfigurer securityConfigurerAdapter() {
|
||||||
return new TokenConfigurer(tokenProvider, properties, onlineUserService, userCacheManager);
|
return new TokenConfigurer(tokenProvider, properties, onlineUserService, userCacheManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Set<String>> getAnonymousUrl(Map<RequestMappingInfo, HandlerMethod> handlerMethodMap) {
|
|
||||||
Map<String, Set<String>> anonymousUrls = new HashMap<>(8);
|
|
||||||
Set<String> get = new HashSet<>();
|
|
||||||
Set<String> post = new HashSet<>();
|
|
||||||
Set<String> put = new HashSet<>();
|
|
||||||
Set<String> patch = new HashSet<>();
|
|
||||||
Set<String> delete = new HashSet<>();
|
|
||||||
Set<String> all = new HashSet<>();
|
|
||||||
for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {
|
|
||||||
HandlerMethod handlerMethod = infoEntry.getValue();
|
|
||||||
AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);
|
|
||||||
if (null != anonymousAccess) {
|
|
||||||
List<RequestMethod> requestMethods = new ArrayList<>(infoEntry.getKey().getMethodsCondition().getMethods());
|
|
||||||
RequestMethodEnum request = RequestMethodEnum.find(requestMethods.size() == 0 ? RequestMethodEnum.ALL.getType() : requestMethods.get(0).name());
|
|
||||||
switch (Objects.requireNonNull(request)) {
|
|
||||||
case GET:
|
|
||||||
get.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
|
|
||||||
break;
|
|
||||||
case POST:
|
|
||||||
post.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
|
|
||||||
break;
|
|
||||||
case PUT:
|
|
||||||
put.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
|
|
||||||
break;
|
|
||||||
case PATCH:
|
|
||||||
patch.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
|
|
||||||
break;
|
|
||||||
case DELETE:
|
|
||||||
delete.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
all.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
anonymousUrls.put(RequestMethodEnum.GET.getType(), get);
|
|
||||||
anonymousUrls.put(RequestMethodEnum.POST.getType(), post);
|
|
||||||
anonymousUrls.put(RequestMethodEnum.PUT.getType(), put);
|
|
||||||
anonymousUrls.put(RequestMethodEnum.PATCH.getType(), patch);
|
|
||||||
anonymousUrls.put(RequestMethodEnum.DELETE.getType(), delete);
|
|
||||||
anonymousUrls.put(RequestMethodEnum.ALL.getType(), all);
|
|
||||||
return anonymousUrls;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user