Spring Security,方法安全注释(@Secured)不起作用(java config)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31186826/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 10:46:12  来源:igfitidea点击:

Spring Security, Method Security annotation (@Secured ) is not working (java config)

javaspringsecurityspring-securityspring-boot

提问by silverhawk

I am trying to set up a method security annotation using @Secured("ADMIN") (without any XML, only java config, Spring Boot). But access via roles does not work.

我正在尝试使用 @Secured("ADMIN") (没有任何 XML,只有 java 配置,Spring Boot)设置方法安全注释。但是通过角色访问不起作用。

Security Config:

安全配置:

@Configuration
@EnableWebSecurity
public class AppSecurityConfiguration extends WebSecurityConfigurerAdapter{

.....

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/api/**").fullyAuthenticated().and()
                .addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }

.....

}

I want restrict access to the method of the controller:

我想限制对控制器方法的访问:

@RestController
@RequestMapping("/api/groups")
public class GroupController {

    @Autowired
    private GroupService groupService;

    @Secured("ADMIN")
    @RequestMapping
    public List<Group> list() {
        return groupService.findAll();
    }

}

Restrict access by the url is working, with:

通过 url 限制访问正在工作,具有:

.antMatchers("/api/**").hasAuthority("ADMIN")

Maybe I forgot to specify that I want restrict by roles?

也许我忘了指定我想按角色限制?

UPD:By the rules, At what layer must be @PreAuthorize("hasRole('ADMIN')")in Controller layer or in Service layer?

UPD:按照规则,@PreAuthorize("hasRole('ADMIN')")控制器层或服务层必须在哪一层?

采纳答案by silverhawk

This issue was solved.

这个问题解决了。

I add @EnableGlobalMethodSecurity(prePostEnabled = true)

我加 @EnableGlobalMethodSecurity(prePostEnabled = true)

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

And in controller i changed @Secured("ADMIN")to @PreAuthorize("hasRole('ADMIN')")

而在控制器我改变@Secured("ADMIN")@PreAuthorize("hasRole('ADMIN')")

回答by Mudassar

Kindly add this

请添加这个

@EnableGlobalMethodSecurity(securedEnabled = true)

This element is used to enable annotation-based security in your application (by setting the appropriate attributes on the element), and also to group together security pointcut declarations which will be applied across your entire application context specifically for @Secured. Hence your code should look like this

此元素用于在您的应用程序中启用基于注释的安全性(通过在元素上设置适当的属性),并将安全切入点声明组合在一起,这些声明将应用于整个应用程序上下文,专门针对@Secured. 因此你的代码应该是这样的

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class AppSecurityConfiguration extends WebSecurityConfigurerAdapter{..

回答by Serge Ballesta

There may be many reasons for which method security on a controller does not work.

控制器上的方法安全性不起作用的原因可能有很多。

First because it is never cited as example in Spring Security manual ... joking but it may be tricky to take Spring tools where they do not want to go.

首先是因为它从未在 Spring Security 手册中被引用为示例......开玩笑但将 Spring 工具带到他们不想去的地方可能会很棘手。

More seriously, you should enable method security as already said by @Mudassar. The manual says :

更严重的是,您应该启用@Mudassar 已经说过的方法安全性。手册上说:

We can enable annotation-based security using the @EnableGlobalMethodSecurityannotation on any @Configurationinstance. For example, the following would enable Spring Security's @Securedannotation.

我们可以@EnableGlobalMethodSecurity在任何@Configuration实例上使用注释来启用基于注释的安全性。例如,以下将启用 Spring Security 的@Secured注释。

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class MethodSecurityConfig {
   // ...
}

Note that Mudassar's answer is correct till here.

请注意,直到这里,Mudassar 的答案都是正确的。

But method security is based on AOP, which by default uses JDK proxying on interfaces. That's the reason why all examples applies method security on the service layer, because the service classes are normally injected in controllers as interfaces.

但是方法安全基于 AOP,默认情况下它在接口上使用 JDK 代理。这就是为什么所有示例都在服务层应用方法安全性的原因,因为服务类通常作为接口注入到控制器中。

You can of course use it on controller layer, but :

您当然可以在控制器层上使用它,但是:

  • either all your controllers implement interfaces for you all @Securedannotated methods
  • or you must switch to class proxying
  • 要么您的所有控制器都为您所有带@Secured注释的方法实现接口
  • 或者您必须切换到类代理

The rule that I try to follow is :

我尝试遵循的规则是:

  • if I want to secure an URL, I stick to HTTPSecurity
  • if I need to allow finer grained access, I add security at service layer
  • 如果我想保护一个 URL,我坚持使用 HTTPSecurity
  • 如果我需要允许更细粒度的访问,我会在服务层添加安全性

回答by digz6666

Maybe you should register your AppSecurityConfiguration to same context as WebMvcConfig (that extends WebMvcConfigurerAdapter).

也许您应该将 AppSecurityConfiguration 注册到与 WebMvcConfig 相同的上下文(扩展 WebMvcConfigurerAdapter)。

AnnotationConfigWebApplicationContext mvcContext = new AnnotationConfigWebApplicationContext();      
mvcContext.register(WebMvcConfig.class, SecurityConfig.class);

回答by user1210708

I know this thread is quite old and my answer alludes to portions of the answers by various people in this thread; but here is a list combined list of pitfalls and answers:

我知道这个线程已经很老了,我的回答暗示了这个线程中不同人的部分答案;但这里是一个列表组合列表的陷阱和答案:

  1. When using @Secured, and the role name is (e.g.) ADMIN; this means an annotation of @Secured("ROLE_ADMIN").
  2. WebSecurityConfigurerAdapter must have @EnableGlobalMethodSecurity(securedEnabled = true)
  3. As with most Spring related proxies, make sure that the class and the secured methods are not in any way final. For Kotlin this means "open" every method as well as the class.
  4. When the class and its methods are virtual ("open"), then there is no implied need for an interface.
  1. 使用@Secured时,角色名称为(例如)ADMIN;这意味着@Secured("ROLE_ADMIN") 的注释。
  2. WebSecurityConfigurerAdapter 必须有 @EnableGlobalMethodSecurity(securedEnabled = true)
  3. 与大多数与 Spring 相关的代理一样,请确保类和受保护的方法在任何情况下都不是最终的。对于 Kotlin 来说,这意味着“打开”每个方法以及类。
  4. 当类及其方法是虚拟的(“开放”)时,就不需要接口。

Here is part of a working Kotlin example:

这是一个工作 Kotlin 示例的一部分:

@RestController
@RequestMapping("api/v1")

    open class DiagnosticsController {
        @Autowired
        lateinit var systemDao : SystemDao

        @RequestMapping("ping", method = arrayOf(RequestMethod.GET))
        @Secured("ROLE_ADMIN")
        open fun ping(request : HttpServletRequest, response: HttpServletResponse) : String { ... 
    }

and

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
open class WebSecurityConfig : WebSecurityConfigurerAdapter() {

Regards

问候

回答by Sadiq Ali

You need to use @secured(ROLE_ADMIN) instead of @secured(ADMIN). You are required to write "ROLE_"infront of your role name. Please find the example mentioned below which is making sure only a user with Admin role can access list() method.

您需要使用@secured(ROLE_ADMIN) 而不是@secured(ADMIN)。您需要在角色名称前写上“ROLE_”。请找到下面提到的示例,该示例确保只有具有 Admin 角色的用户才能访问 list() 方法。

@RestController
@RequestMapping("/api/groups")
public class GroupController {

    @Autowired
    private GroupService groupService;

    @Secured("ROLE_ADMIN")
    @RequestMapping
    public List<Group> list() {
        return groupService.findAll();
    }

}

回答by Igor

I want to share my decision, may be it will be helpful.

我想分享我的决定,可能会有所帮助。

Used spring mvc+ spring security, version 4.2.9.RELEASE

使用spring mvc+ spring security, 版本4.2.9.RELEASE

For example, i have a Service with method annotated @Secured

例如,我有一个带有@Secured 方法注释的服务

@Secured("ACTION_USER_LIST_VIEW")
List<User> getUsersList();

But, it didn't work, because GlobalMethodSecurityConfigurationhas inside method.

但是,它没有用,因为GlobalMethodSecurityConfiguration有内部方法。

protected AccessDecisionManager accessDecisionManager()

in which initialized the new RoleVoter()with default rolePrefix = "ROLE_";(this makes it impossible to use beans to set your rolePrefix)that give to us not working annotations, because RoleVoterexpects annotation value which starts with 'ROLE_'

其中初始化了new RoleVoter()默认值rolePrefix = "ROLE_";(这使得无法使用 bean 来设置您的 rolePrefix),这会给我们不工作的注释,因为RoleVoter需要以“ROLE_”开头的注释值

For resolving this problem i override GlobalMethodSecurityConfigurationlike this

为了解决这个问题,我像这样覆盖了GlobalMethodSecurityConfiguration

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class AppMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
    @Override
    protected AccessDecisionManager accessDecisionManager() {
        List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList<>();
        ExpressionBasedPreInvocationAdvice expressionAdvice = new ExpressionBasedPreInvocationAdvice();
        expressionAdvice.setExpressionHandler(getExpressionHandler());
        decisionVoters.add(getRoleVoter());
        decisionVoters.add(new AuthenticatedVoter());
        return new AffirmativeBased(decisionVoters);
    }

    private RoleVoter getRoleVoter() {
        RoleVoter e = new RoleVoter();
        e.setRolePrefix("");
        return e;
    }
}