PreAuthorize 不适用于控制器

PreAuthorize not working on Controller

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

安全配置

@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 时它执行得很好,它不应该因为 'user' 没有 ROLE_ADMIN 而给我一个拒绝访问错误?

我实际上正在考虑放弃方法级别的访问规则并坚持使用 http() 蚂蚁规则,但我必须知道为什么它对我不起作用。

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

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

以下仅代表个人意见:

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

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

1) 我必须制定我的方法 public(即让你的方法成为 home() public)

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

让它在控制器层工作。 我不得不在我的配置中添加 @EnableAspectJAutoProxy class。 示例:

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

}

有两种不同的使用方式,一种是加前缀,一种不是。 你也许把 @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);
}

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

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

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

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

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

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

中是不够的

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

HTH

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

像下面的例子:-

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

我的控制器的方法是私有的,它们需要 public。

您的请求方法默认受保护。这样他们就可以扫描它。设置它 public!!!

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

  1. @EnableGlobalMethodSecurity(prePostEnabled = true) on class 用@EnableWebSecurity

    注释
  2. 已创建自定义 (GroupUserDetails) UserDetails,它将具有用户名和权限以及 return 来自 custome UserDetailsS​​ervice

    的 GroupUserDetails 实例
  3. 用@PreAuthorize("hasAuthority('Group-Name')")注解控制器方法

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