First of all, the project springboot uses version 2.6.8. In the process of integrating security, a relatively strict custom strategy is used. Any request requires authentication and authorization to determine whether the user has the right to query and modify the interface. And it provides an interface to provide anonymous access in two ways: configuration or annotation.
The first is through configuration
The second uses custom annotations
Realize by yourself
AccessDecisionManager
and
FilterInvocationSecurityMetadataSource
Causes controllers that need to collect @Anonymous annotations.
So it’s like referring to the way spring starts scanning annotations, and then customizes
Referencespring scan
/**
* 参照spring scan
* @author: Barry.Yu
* @date: 2022/9/30
* @desc: 自定义匿名访问扫描类
**/
@Slf4j
public class AnonymousScanRegistrar implements EnvironmentCapable, ImportBeanDefinitionRegistrar {
private static final String anonymousBeanName = "anonymousUrlServiceImpl";
private Set<String> anonymousUrls = new HashSet<>();
static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
private String resourcePattern = DEFAULT_RESOURCE_PATTERN;
@Nullable
private Environment environment;
@Nullable
private ResourcePatternResolver resourcePatternResolver;
@Nullable
private MetadataReaderFactory metadataReaderFactory;
private final Map<String, Function<Method,String[]>> functionMap = new HashMap<>();
{
functionMap.put("org.springframework.web.bind.annotation.PostMapping",this::postFunction);
functionMap.put("org.springframework.web.bind.annotation.PutMapping",this::putFunction);
functionMap.put("org.springframework.web.bind.annotation.GetMapping",this::getFunction);
functionMap.put("org.springframework.web.bind.annotation.DeleteMapping",this::delFunction);
functionMap.put("org.springframework.web.bind.annotation.RequestMapping",this::requestFunction);
}
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry){
AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(annotationMetadata.getAnnotationAttributes(AnonymousScan.class.getName()));
String[] basePackages = annoAttrs.getStringArray("basePackage");
for (String basePackage : basePackages) {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
try {
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
for (Resource resource : resources) {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
createUrls(metadataReader.getClassMetadata().getClassName());
}
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
//beanDefinition的beanClass
beanDefinition.setBeanClass(AnonymousUrlServiceImpl.class);
ConstructorArgumentValues constructorArgumentValues = beanDefinition.getConstructorArgumentValues();
constructorArgumentValues.addIndexedArgumentValue(0, anonymousUrls);
registry.registerBeanDefinition(anonymousBeanName, beanDefinition);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 构建所需要的匿名路径
* @param beanClassName
*/
private void createUrls(String beanClassName){
try {
Class aClass = Class.forName(beanClassName);
RequestMapping requestMapping = (RequestMapping) aClass.getAnnotation(RequestMapping.class);
if(requestMapping!=null){
String[] pathParents = requestMapping.value();
String[] paths = null;
Method[] methods = aClass.getMethods();
for (Method method : methods) {
Anonymous anonymous = method.getAnnotation(Anonymous.class);
if(anonymous!=null){
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
Function<Method, String[]> methodFunction = functionMap.get(annotation.annotationType().getName());
if(methodFunction!=null){
paths = methodFunction.apply(method);
break;
}
}
if(paths!=null && paths.length>0){
for (String pathParent : pathParents) {
for (String path : paths) {
anonymousUrls.add( pathParent + path);
}
}
}
paths = null;
}
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private String[] postFunction(Method method){
return method.getAnnotation(PostMapping.class).value();
}
private String[] getFunction(Method method){
return method.getAnnotation(GetMapping.class).value();
}
private String[] putFunction(Method method){
return method.getAnnotation(PutMapping.class).value();
}
private String[] delFunction(Method method){
return method.getAnnotation(DeleteMapping.class).value();
}
private String[] requestFunction(Method method){
return method.getAnnotation(RequestMapping.class).value();
}
public final MetadataReaderFactory getMetadataReaderFactory() {
if (this.metadataReaderFactory == null) {
this.metadataReaderFactory = new CachingMetadataReaderFactory();
}
return this.metadataReaderFactory;
}
private ResourcePatternResolver getResourcePatternResolver() {
if (this.resourcePatternResolver == null) {
this.resourcePatternResolver = new PathMatchingResourcePatternResolver();
}
return this.resourcePatternResolver;
}
protected String resolveBasePackage(String basePackage) {
return ClassUtils.convertClassNameToResourcePath(getEnvironment().resolveRequiredPlaceholders(basePackage));
}
@Override
public Environment getEnvironment() {
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
return this.environment;
}
public Set<String> getAnonymousUrls(){
return anonymousUrls;
}
}
Add to the startup class