PreAuthorize 在控制器上不起作用

问题描述 投票:0回答:15

我试图在方法级别定义访问规则,但它不起作用。

安全配置

@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
15个回答
95
投票

您必须在 WebSecurityConfig 中添加

@EnableGlobalMethodSecurity(prePostEnabled = true)

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

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

39
投票

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

这意味着它在服务层上工作得很好,作为接口注入到控制器层中,但在控制器层上它被忽略,因为控制器通常不实现接口。

以下只是我的意见:

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

17
投票

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

就像下面的例子:-

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

15
投票

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

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

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


10
投票

对于 2023 年及以后来到这里的人,您必须将

@EnableMethodSecurity
注解添加到您的配置类中。还值得注意的是,自 2023 年起,Spring Boot 还使用自动配置。下面包含一个示例安全配置。

@Configuration
@EnableWebSecurity
@EnableMethodSecurity // Add this
public class SecurityConfig {
    // Add your configuration Beans here
}

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

@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();
    }
}

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);
}

4
投票

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

  1. @EnableGlobalMethodSecurity(prePostEnabled = true)
    标注有
    @EnableWebSecurity

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

  3. 注释控制器方法

    @PreAuthorize("hasAuthority('Group-Name')")


3
投票

我的控制器的方法是私有的,他们需要公开。


3
投票

使其在控制器层工作。 我必须将

@EnableAspectJAutoProxy
放在我的配置类上。 示例:

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

}

1
投票

如果您的安全 Bean 有一个 xml 上下文文件,并且有一个单独的 Web/Servlet 上下文文件,那么您还需要添加:

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

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

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

HTH


1
投票

我将控制器方法从

private
更改为
public
并且它正在工作。


1
投票

您的请求方式默认为

protected
。所以他们无法扫描它。设置一下
public


0
投票

2023 年 6 月: 对于那些仍在挣扎的人:
安全配置

 @Bean
   public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder){
           
           UserDetails user = User.withUsername("user")
                .password(passwordEncoder.encode("user123"))
                .roles("USER")
                .build();

           return new InMemoryUserDetailsManager(admin,user);
    }

你的控制器应该是这样的:

@GetMapping("/getAll")
    @PreAuthorize("hasAuthority('ROLE_USER')")
    public List<Student> findAllStudents() {
        return studentServiceI.findAll();
    }

0
投票

我在方法中有一个 static 关键字,通过删除它,@Preauthorize 起作用了。


0
投票

您应该在 HttpSecurity 对象的authorizeRequest 中添加

.anyRequest().authenticated

因为默认的 HttpBuilder 实现仍然处于活动状态,并且因为它在 Web 请求过滤器链期间进行评估,所以它具有优先权。

通过

authorizeRequest.anyRequest().authenticated
,您所做的是使用 SecurityConfig 类显式允许主端点上的所有请求,同时要求在所有其他端点上进行身份验证。这为您的应用程序设置了总体最低身份验证要求。您还重新启用了基于表单的身份验证。

© www.soinside.com 2019 - 2024. All rights reserved.