《Spring Security》自定义权限验证@PreAuthorize

自定义安全表达式

/**
 * Base root object for use in Spring Security expression evaluations.
 *
 * @author Luke Taylor
 * @since 3.0
 */
public abstract class SecurityExpressionRoot implements SecurityExpressionOperations

SecurityExpressionRoot 是所有安全表达式的基类,我们需要做的就是:

  1. 继承 SecurityExpressionRoot,自定义 MethodSecurity 表达式
  2. 继承 DefaultMethodSecurityExpressionHandler,自定义方法级别的安全校验处理器
  3. 继承 GlobalMethodSecurityConfiguration,添加自定义的表达式处理器

一、MethodSecurityConfig

开启方法级别的安全校验,注入登录用户时加载 UserDetails 的DB服务对象,通过 createExpressionHandler 注入自定义的表达式处理器。

/**
 * 配置 MethodSecurity 表达式
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {

    private final LoginDetailService loginDetailService;

    public MethodSecurityConfig(LoginDetailService loginDetailService) {
        this.loginDetailService = loginDetailService;
    }

    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        return new ResourceMethodSecurityExpressionHandler(loginDetailService);
    }
}

二、ResourceMethodSecurityExpressionHandler

接收 UserDetailsService,并创建一个处理表达式的操作类

/**
 * 自定义方法级别的安全校验处理器
 */
public class ResourceMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {

    private final LoginDetailService loginDetailService;

    private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();

    public ResourceMethodSecurityExpressionHandler(LoginDetailService loginDetailService) {
        this.loginDetailService = loginDetailService;
    }

    @Override
    protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
        final ResourceMethodSecurityExpressionRoot root = new ResourceMethodSecurityExpressionRoot(authentication, loginDetailService);
        root.setPermissionEvaluator(getPermissionEvaluator());
        root.setTrustResolver(this.trustResolver);
        root.setRoleHierarchy(getRoleHierarchy());
        return root;
    }
}

三、ResourceMethodSecurityExpressionRoot

仿照 hasAuthority,编写一个自己的实现

/**
 * 自定义 MethodSecurity 表达式
 */
@Slf4j
public class ResourceMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {

    private LoginDetailService loginDetailService;

    private Object filterObject;
    private Object returnObject;
    private Object target;

    public ResourceMethodSecurityExpressionRoot(Authentication authentication, LoginDetailService loginDetailService) {
        super(authentication);
        this.loginDetailService = loginDetailService;
    }

    /**
     * 自定义接口,是否允许对该id的访问
     */
    public boolean canReadCourse(String courseId) {
        log.debug("method params courseId", courseId);
        log.debug("current principal {}", getPrincipal());
        return true;
    }

    public final boolean hasGlobalAuthority(String authority) {
        return hasAnyGlobalAuthority(authority);
    }

    public final boolean hasAnyGlobalAuthority(String... authorities) {
        return hasAnyGlobalAuthorityName(null, authorities);
    }

    private boolean hasAnyGlobalAuthorityName(String prefix, String... roles) {
        final String username = ((UserDetails) getPrincipal()).getUsername();
        final UserDetails details = loginDetailService.loadUserByUsername(username);

        if (details.getAuthorities() != null) {
            final Set<String> roleSet = details.getAuthorities().stream()
                    .map(GrantedAuthority::getAuthority).collect(Collectors.toSet());

            for (String role : roles) {
                String defaultedRole = getRoleWithDefaultPrefix(prefix, role);
                if (roleSet.contains(defaultedRole)) {
                    return true;
                }
            }
        }

        return false;
    }

    private static String getRoleWithDefaultPrefix(String defaultRolePrefix, String role) {
        if (role == null) {
            return role;
        }
        if (defaultRolePrefix == null || defaultRolePrefix.length() == 0) {
            return role;
        }
        if (role.startsWith(defaultRolePrefix)) {
            return role;
        }
        return defaultRolePrefix + role;
    }

    @Override
    public void setFilterObject(Object filterObject) {
        this.filterObject = filterObject;
    }

    @Override
    public Object getFilterObject() {
        return filterObject;
    }

    @Override
    public void setReturnObject(Object returnObject) {
        this.returnObject = returnObject;
    }

    @Override
    public Object getReturnObject() {
        return returnObject;
    }

    @Override
    public Object getThis() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }

    @Override
    public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
        super.setRoleHierarchy(roleHierarchy);
    }
}
文章作者: koral
文章链接: http://luokaiii.github.io/2019/09/05/读书笔记/《SpringSecurity》/23.自定义权限验证/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自