PreAuthorize不在Controller上工作

pre*_*oid 23 spring spring-security spring-boot spring-java-config

我正在尝试在方法级别定义访问规则,但它无法正常工作.

SecurityConfiguration

@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();
    }
}
Run Code Online (Sandbox Code Playgroud)

ExampleController

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

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

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

小智 27

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

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

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
Run Code Online (Sandbox Code Playgroud)

  • 确认这适用于Spring Boot v1.5.x. (4认同)
  • 同样根据之前的评论者,如果将 pre/post 放在未实现接口的控制器方法上,也会将注释属性 `proxyTargetClass = true` 添加到 `EnableGlobalMethodSecurity` (4认同)

Ser*_*sta 24

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

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

以下是我的意见:

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

  • 感谢您的回答。我已经尝试在`CrudRepository`接口上使用注释,并且工作正常。在我看来,为每个控制器提供接口确实很愚蠢,因为实际上并不需要接口。`proxy-target-class = true`没什么区别,注释仍然不能在控制器上工作,但是当注释在存储库接口中时(当设置为true时,它会导致崩溃(无法子类com)。 sun.proxy)。无论如何,我认为我将坚持安全配置中的规则,并且可能在某些存储库上使用PreAuth。 (2认同)
  • 我注意到的另一件事是,我看到了在“类”而不是“接口”中使用 @PreAuthorize 的例子,它应该可以工作..我想知道为什么它对他们有用而不对我有用。 (2认同)
  • 现在这已经改变了吗?因为 prePost 注释在我的控制器上工作得非常好,无需实现任何接口或允许目标类代理 (2认同)

sta*_*ail 15

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

像下面的例子:-

@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MvcConfiguration extends WebMvcConfigurerAdapter {
Run Code Online (Sandbox Code Playgroud)


Jon*_*ker 11

对于 2023 年及以后来到这里的人,您必须将@EnableMethodSecurity注释添加到您的配置类中。还值得注意的是,自 2023 年起,Spring Boot 还使用自动配置。下面包含一个安全配置示例。

@Configuration
@EnableWebSecurity
@EnableMethodSecurity // Add this
public class SecurityConfig {
    // Add your configuration Beans here
}
Run Code Online (Sandbox Code Playgroud)

你的控制器应该看起来像这样:

@RestController
@RequestMapping("/users")
public class UserController
{
    // Replace this with your service or other means to fetch resources
    private final UserRepository userRepository;

    public UserController(UserRepository userRepository)
    {
        this.userRepository = userRepository;
    }

    // Note: I am using a scope called "users.read" below, but you can use
    // ROLE_<role_name> if you are using roles instead.
    @GetMapping(value = "/list")
    @PreAuthorize("hasAuthority('users.read')")
    public List<UserDto> listUsers()
    {
        return userRepository.findAllBy();
    }
}
Run Code Online (Sandbox Code Playgroud)


Hor*_*ome 10

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

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

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


小智 6

有两种不同的使用方式,一种是前缀,一种不是。你也许更改@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);
}
Run Code Online (Sandbox Code Playgroud)