spring是如何实现对HTTP请求进行安全检查和资源使用授权的?
实现过程由类AbstractSecurityInterceptor在beforeInvocation方法中完成,在beforeInvocation的实现中,
首先,需要读取IoC容器中Bean的配置,在这些属性配置中配置了对HTTP请求资源的安全需求,
比如,哪个角色的用户可以接入哪些URL请求资源,具体实现逻辑见:
#与Web环境的接口FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter

@PreAuthorize、@PostAuthorize注解实现逻辑
继承根节点:SecurityMetaSource

可以通过Spring注解声明,需要依赖类注入,实现权限灵活配置如:
@Component("securityMetadataSource")public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource
PrePostAnnotationSecurityMetadataSource类继承关系AbstractMethodSecurityMetadataSource类继承关系package org.springframework.security.access.prepost;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.method.AbstractMethodSecurityMetadataSource;
import org.springframework.util.ClassUtils;

public class PrePostAnnotationSecurityMetadataSource extends AbstractMethodSecurityMetadataSource {
    private final PrePostInvocationAttributeFactory attributeFactory;

    public PrePostAnnotationSecurityMetadataSource(PrePostInvocationAttributeFactory attributeFactory) {
        this.attributeFactory = attributeFactory;
    }

    public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
        if (method.getDeclaringClass() == Object.class) {
            return Collections.emptyList();
        } else {
            this.logger.trace("Looking for Pre/Post annotations for method '" + method.getName() + "' on target class '" + targetClass + "'");
            PreFilter preFilter = (PreFilter)this.findAnnotation(method, targetClass, PreFilter.class);
            PreAuthorize preAuthorize = (PreAuthorize)this.findAnnotation(method, targetClass, PreAuthorize.class);
            PostFilter postFilter = (PostFilter)this.findAnnotation(method, targetClass, PostFilter.class);
            PostAuthorize postAuthorize = (PostAuthorize)this.findAnnotation(method, targetClass, PostAuthorize.class);
            if (preFilter == null && preAuthorize == null && postFilter == null && postAuthorize == null) {
                this.logger.trace("No expression annotations found");
                return Collections.emptyList();
            } else {
                String preFilterAttribute = preFilter == null ? null : preFilter.value();
                String filterObject = preFilter == null ? null : preFilter.filterTarget();
                String preAuthorizeAttribute = preAuthorize == null ? null : preAuthorize.value();
                String postFilterAttribute = postFilter == null ? null : postFilter.value();
                String postAuthorizeAttribute = postAuthorize == null ? null : postAuthorize.value();
                ArrayList<ConfigAttribute> attrs = new ArrayList(2);
                PreInvocationAttribute pre = this.attributeFactory.createPreInvocationAttribute(preFilterAttribute, filterObject, preAuthorizeAttribute);
                if (pre != null) {
                    attrs.add(pre);
                }

                PostInvocationAttribute post = this.attributeFactory.createPostInvocationAttribute(postFilterAttribute, postAuthorizeAttribute);
                if (post != null) {
                    attrs.add(post);
                }

                attrs.trimToSize();
                return attrs;
            }
        }
    }

    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    private <A extends Annotation> A findAnnotation(Method method, Class<?> targetClass, Class<A> annotationClass) {
        Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
        A annotation = AnnotationUtils.findAnnotation(specificMethod, annotationClass);
        if (annotation != null) {
            this.logger.debug(annotation + " found on specific method: " + specificMethod);
            return annotation;
        } else {
            if (specificMethod != method) {
                annotation = AnnotationUtils.findAnnotation(method, annotationClass);
                if (annotation != null) {
                    this.logger.debug(annotation + " found on: " + method);
                    return annotation;
                }
            }

            annotation = AnnotationUtils.findAnnotation(specificMethod.getDeclaringClass(), annotationClass);
            if (annotation != null) {
                this.logger.debug(annotation + " found on: " + specificMethod.getDeclaringClass().getName());
                return annotation;
            } else {
                return null;
            }
        }
    }
}

//注解开启权限
@EnableResourceServer
@EnableGlobalMethodSecurity
SecurityContextHolder作为全局缓存,从上下文获取授权信息
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
上面权限列表初始化由具体实现类实现:
public class User implements UserDetails, CredentialsContainer {
    ...
    private final Set<GrantedAuthority> authorities;
    ...
    //authorities权限列表
    public User(String username, String password, Collection<? extends GrantedAuthority> authorities) {
        this(username, password, true, true, true, true, authorities);
    }
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐