预授权不适用于控制器

Posted

技术标签:

【中文标题】预授权不适用于控制器【英文标题】: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 规则,但我必须知道为什么它不适合我。

【问题讨论】:

【参考方案1】:

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

【讨论】:

【参考方案2】:

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

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

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

    使用 @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 不幸的是,这对我不起作用(请参阅***.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 注释在我的控制器上工作得非常好,无需实现任何接口或允许目标类代理

以上是关于预授权不适用于控制器的主要内容,如果未能解决你的问题,请参考以下文章

Spring MVC 预授权控制器操作未收到 POST 请求

Axios 发布请求适用于 Postman,但不适用于浏览器(它返回“错误 401-未授权”)

UINavigationController 不适用于 SearchDisplay 控制器

从 url 中删除控制器名称不适用于 cakephp 中的多个控制器

当前视图控制器不适用于 ios 9

Sails.js 政策不适用于单个控制器