Springboot integrates security and customizes @Anonymous tags to achieve login-free and authentication-free

        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

 

Guess you like

Origin blog.csdn.net/evil_lrn/article/details/129066089