【问题标题】:PreAuthorize not working on Controller预授权不适用于控制器
【发布时间】:2015-12-03 05:31:29
【问题描述】:

我正在尝试在方法级别定义访问规则,但它并没有像以前那样工作。

安全配置

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().
                withUser("user").password("user").roles("USER").and().
                withUser("admin").password("admin").roles("ADMIN");
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/v2/**").authenticated()
                .and()
                .httpBasic()
                .realmName("Secure api")
                .and()
                .csrf()
                .disable();
    }
}

示例控制器

@EnableAutoConfiguration
@RestController
@RequestMapping({"/v2/"})
public class ExampleController {
    @PreAuthorize("hasAuthority('ROLE_ADMIN')")
    @RequestMapping(value = "/home", method = RequestMethod.GET)
    String home() {
        return "Hello World";
    }
}

每当我尝试使用 user:user 访问 /v2/home 时,它​​执行得很好,它不应该因为“用户”没有 ROLE_ADMIN 而给我一个访问被拒绝错误吗?

我实际上正在考虑在方法级别放弃访问规则并坚持 http() ant 规则,但我必须知道为什么它不适合我。

【问题讨论】:

    标签: spring spring-security spring-boot spring-java-config


    【解决方案1】:

    我将控制器方法从私有更改为公共。它的工作。你可以试试。

    【讨论】:

      【解决方案2】:

      我在尝试授权用户的 AD 组时遇到了同样的问题 这些步骤对我有用

      1. @EnableGlobalMethodSecurity(prePostEnabled = true) 在使用 @EnableWebSecurity 注释的类上

      2. 创建了自定义(GroupUserDetails)UserDetails,它将具有用户名和权限,并从自定义 UserDetailsS​​ervice 返回 GroupUserDetails 的实例

      3. 使用 @PreAuthorize("hasAuthority('Group-Name')") 注释控制器方法

      【讨论】:

        【解决方案3】:

        我的 Controller 的方法是私有的,它们需要公开。

        【讨论】:

        • 我在过去一个月里一直在尝试这个,一切都是正确的,期待这个公开的..地狱般的学习。终于发现问题了。谢谢@georgi Peev
        【解决方案4】:

        您的请求方法默认受到保护。所以他们可以扫描它。公开!!!

        【讨论】:

          【解决方案5】:

          将@EnableGlobalMethodSecurity(prePostEnabled = true) 放入MvcConfig 类(扩展WebMvcConfigurerAdapter)而不是(扩展WebSecurityConfigurerAdapter)。

          如下例:-

          @EnableGlobalMethodSecurity(prePostEnabled = true)
          public class MvcConfiguration extends WebMvcConfigurerAdapter {
          

          【讨论】:

            【解决方案6】:

            如果您的安全 bean 有一个 xml 上下文文件,而您的 web/servlet 上下文有一个单独的文件,那么您还需要添加:

            <security:global-method-security pre-post-annotations="enabled"/>
            

            到您的 web-context.xml / servlet 上下文。仅将其添加到安全上下文 xml 中是不够的。

            它不会在子上下文中继承。

            HTH

            【讨论】:

            • OP 已经使用@EnableGlobalMethodSecurity(prePostEnabled = true)
            【解决方案7】:

            您必须在 WebSecurityConfig 中添加 @EnableGlobalMethodSecurity(prePostEnabled = true)

            你可以在这里找到它:http://www.baeldung.com/spring-security-expressions-basic

            @Configuration
            @EnableWebSecurity
            @EnableGlobalMethodSecurity(prePostEnabled = true)
            public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
            

            【讨论】:

            • 同样根据之前的评论者,如果将 pre/post 放在不实现接口的控制器方法上,还将注释属性 proxyTargetClass = true 添加到 EnableGlobalMethodSecurity
            • 不幸的是,这对我不起作用(请参阅stackoverflow.com/questions/53125388/…)。
            【解决方案8】:

            有两种不同的使用方式,一种是前缀,一种不是。 你也许把@PreAuthorize("hasAuthority('ROLE_ADMIN')")改成@PreAuthorize("hasAuthority('ADMIN')")就可以了。

            接下来是@PreAuthorize源代码。

            private String defaultRolePrefix = "ROLE_";
            public final boolean hasAuthority(String authority) {
                return hasAnyAuthority(authority);
            }
            
            public final boolean hasAnyAuthority(String... authorities) {
                return hasAnyAuthorityName(null, authorities);
            }
            
            public final boolean hasRole(String role) {
                return hasAnyRole(role);
            }
            
            public final boolean hasAnyRole(String... roles) {
                return hasAnyAuthorityName(defaultRolePrefix, roles);
            }
            

            【讨论】:

            • 并且这个源应该被添加到我的控制器在哪里以及如何访问它?
            • ExampleController的问题,只是把ROLE_ADMIN改成了ADMIN
            • 我按照您的建议进行了尝试,效果很好,但是实现hasRole 子句(如@PreAuthorize("hasRole('ADMIN')"))的正确方法是什么
            【解决方案9】:

            为了让它在控制器层上工作。 我不得不将@EnableAspectJAutoProxy 放在我的配置类中。 示例:

            @Configuration
            @EnableWebMvc
            @EnableAspectJAutoProxy
            @ComponentScan(basePackages = { "com.abc.fraud.ts.userservices.web.controller" })
            public class WebConfig extends WebMvcConfigurerAdapter{
            
            }
            

            【讨论】:

            • 我的工作没有这个@EnableAspectJAutoProxy 我只是使用了@PreAuthorize("hasAuthority('ADMIN')")
            • 这是为什么呢? @kripal kashyav
            【解决方案10】:

            我遇到了类似的问题,以下解决了它:

            1) 我必须公开我的方法(即公开你的方法 home())

            2) 我必须使用 hasRole 而不是 hasAuthority

            【讨论】:

            • 我遇到了同样的问题,公开方法解决了!
            • 公开控制器方法为我解决了这个问题。
            • 将方法从私有更改为公共对我有用。
            【解决方案11】:

            在控制器上使用 PrePost 注释的一个常见问题是 Spring 方法安全性基于 Spring AOP,默认情况下使用 JDK 代理实现。

            这意味着它在作为接口注入控制器层的服务层上可以正常工作,但在控制器层上它被忽略了,因为控制器通常不实现接口。

            以下只是我的看法:

            • 首选方式:将前置注解移到服务层
            • 如果您不能(或不想),请尝试让您的控制器实现一个包含所有注释方法的接口
            • 作为最后一种方式,使用 proxy-target-class=true

            【讨论】:

            • 感谢您的回答。我试过在CrudRepository 接口上使用注释,它工作得很好。在我看来,每个控制器都有一个接口有点愚蠢,因为接口并不是真正必要的。 proxy-target-class=true 没有区别,注释在控制器上仍然不起作用,但是当在存储库接口(不能子类 com.sun.proxy)中有注释时,它会导致崩溃(当设置为 true 时)。无论如何,我想我会坚持安全配置中的规则,并且可能在我的一些存储库上使用 PreAuth。
            • 我注意到的另一件事是,我看到了在 class 而不是 interface 中使用 @PreAuthorize 的示例,它应该可以工作。我想知道它为什么有效适合他们,但不适合我。
            • 在应用程序上下文中启用 Aop
            • 我在 Controller 上使用 @PreAuthorize 时遇到了奇怪的问题:一些应用程序运行良好,而一些应用程序则不行。
            • 现在已经改变了吗?因为 prePost 注释在我的控制器上工作得非常好,无需实现任何接口或允许目标类代理
            猜你喜欢
            • 2018-01-18
            • 2016-04-07
            • 1970-01-01
            • 2014-10-28
            • 2013-08-29
            • 1970-01-01
            • 2016-11-22
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多