Spring Security:如果缺少 @PreAuthorize 注释,则拒绝访问控制器方法

Posted

技术标签:

【中文标题】Spring Security:如果缺少 @PreAuthorize 注释,则拒绝访问控制器方法【英文标题】:Spring Security: Deny access to controller methods, if @PreAuthorize annotation is missing 【发布时间】:2015-08-01 15:38:07 【问题描述】:

我有一个配置为以标准方式使用 Spring Security 3.2 的 Web 应用程序。

我正在使用@PreAuthorize 注释来保护Controllers 方法。 现在,我想拒绝访问每个控制器方法除非@PreAuthorize注释。

我尝试了以下方法:

超级控制器

每个控制器都从带有注释的超级控制器扩展而来:@PreAutorize("denyAll")。这种方法似乎不起作用,因为控制器的方法注释被忽略了。一切都是禁止的。

@PreAutorize("denyAll") 
public class SuperController 



public class MyController extends SuperController 

    @PreAuthorize("hasRole('SUPERHERO')")
    @RequestMapping(value = URL_PREFIX + "Add.do", method =  RequestMethod.GET)
    public String doStuff(Model model) 

        ...
    


aop

在全局方法安全标签中使用切入点表达式

<global-method-security pre-post-annotations="enabled">
    <protect-pointcut expression="execution(* com.acme.*Controller.*(..))" access="denyAll" />
 </global-method-security>

这种方法也失败了:没有注释的控制器方法仍然可以访问。

【问题讨论】:

【参考方案1】:

我在这里回答我自己的问题。

我已经使用HandlerInterceptorAdapter 解决了这个问题。

我不确定这是实现结果的最符合 Spring 的惯用方式,但对我来说已经足够了。

public class MvcPreAuthorizeAnnotationCheckerInterceptor extends HandlerInterceptorAdapter 
    final HandlerMethod hm;
    if (handler instanceof HandlerMethod) 
        hm = (HandlerMethod) handler;
        PreAuthorize annotation = hm.getMethodAnnotation(PreAuthorize.class);
        if (annotation == null) 
            // check if the class is annotated...
            annotation = hm.getMethod().getDeclaringClass().getAnnotation(PreAuthorize.class);
            if (annotation == null) 
                // add logging
                // or send a NON AUTHORIZED
                response.sendRedirect(request.getContextPath());
            
       
       return true;
    

在 Spring 配置中:

<mvc:interceptors>
    <beans:ref bean="mvcPreAuthorizeAnnotationCheckerInterceptor"/>
</mvc:interceptors>

<beans:bean id="mvcPreAuthorizeAnnotationCheckerInterceptor" class="com.acme.MvcPreAuthorizeAnnotationCheckerInterceptor"/>

【讨论】:

【参考方案2】:

我想出了一个类似的方法,但它不是对每个请求都执行,只是扩展了该方法的ConfigAttribute

一个小缺点可能是它不允许简单的日志记录,或者最大的好处是它遵循与其他不允许的端点相同的拒绝行为。

安全配置

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration 

    @Override
    protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() 
        return new CustomPermissionAllowedMethodSecurityMetadataSource();
    

元数据源

public class CustomPermissionAllowedMethodSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource 
    @Override
    protected Collection<ConfigAttribute> findAttributes(Class<?> clazz) 
        return null;
    

    @Override
    protected Collection<ConfigAttribute> findAttributes(Method method, Class<?> targetClass) 
        Annotation[] annotations = AnnotationUtils.getAnnotations(method);
        List<ConfigAttribute> attributes = new ArrayList<>();

        // if the class itself is annotated as a @Controller we should by default deny access to every method
        if (AnnotationUtils.findAnnotation(targetClass, Controller.class) != null) 
            attributes.add(DENY_ALL_ATTRIBUTE);
        

        if (annotations != null) 
            for (Annotation a : annotations) 
                // but not if the method has at least a PreAuthorize or PostAuthorize annotation
                if (a instanceof PreAuthorize || a instanceof PostAuthorize) 
                    return null;
                
            
        
        return attributes;
    

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() 
        return null;
    

我还写了一篇关于这个的小文章,还有一些背景:https://www.baeldung.com/spring-deny-access

【讨论】:

以上是关于Spring Security:如果缺少 @PreAuthorize 注释,则拒绝访问控制器方法的主要内容,如果未能解决你的问题,请参考以下文章

在 Grails 中使用 Pre/Post Spring-Security Annotations

如何将 Spring Security @Pre 和 @Post 注释与集合一起使用

如何让 Spring Security 使用 OAUTH2 响应 Pre-Flight CORS 请求

Spring Security pre-authentication - 给我一个新的会话,即使主体没有改变

Spring Security中的多个预授权过滤器?

使用 Spring Security 配置 Spring Boot 会导致构建失败,因为引用缺少依赖项