Java Spring安全性可以在Spring控制器方法上使用@PreAuthorize吗?

Java Spring安全性可以在Spring控制器方法上使用@PreAuthorize吗?,java,spring-mvc,controller,spring-security,Java,Spring Mvc,Controller,Spring Security,Spring Security能否在Spring控制器方法上使用@PreAuthorize?是的,它工作正常 您需要中的..-servlet.xml。它还需要,因此您的控制器不应该有接口,或者您应该使用代理目标class=true请参见(我的重点) 在SpringWeb应用程序中,保存 DispatcherServlet的SpringMVCbean通常与 主应用程序上下文。它通常在一个名为 myapp-servlet.xml,其中“myapp”是分配给Spring的名称 web.xml中的Dis

Spring Security能否在Spring控制器方法上使用
@PreAuthorize

是的,它工作正常

您需要
中的
..-servlet.xml
。它还需要,因此您的控制器不应该有接口,或者您应该使用
代理目标class=true

请参见(我的重点)

在SpringWeb应用程序中,保存 DispatcherServlet的SpringMVCbean通常与 主应用程序上下文。它通常在一个名为 myapp-servlet.xml,其中“myapp”是分配给Spring的名称 web.xml中的DispatcherServlet。一个应用程序可以有多个 DispatcherServlets,每个都有自己的独立应用程序上下文。 这些“子”上下文中的bean对其余部分不可见 应用“父”应用程序上下文由 您在web.xml中定义的ContextLoaderListener对所有人都可见 孩子们在不同的环境中成长。此父上下文通常是您定义的位置 您的安全配置,包括 元素)。因此,应用于中的方法的任何安全约束 由于无法看到这些bean,因此不会强制执行这些Webbean 从DispatcherServlet上下文。您需要移动 声明到web上下文或移动 您希望在主应用程序上下文中保护的bean

通常,我们建议在服务中应用方法安全性 层而不是单个web控制器上。


如果您将切入点应用到服务层,您只需要在应用程序的安全上下文中设置

如果您使用的是Spring 3.1,您可以用它做一些非常酷的事情。看一看。这是一个示例项目,它将@PreAuthorize与Spring MVC的RequestMappingHandlerMapping集成在一起,以便您可以执行以下操作:

@RequestMapping("/")
@PreAuthorize("isAuthenticated()")
public String authenticatedHomePage() {
    return "authenticatedHomePage";
}

@RequestMapping("/")
public String homePage() {
    return "homePage";
}

如果用户经过身份验证,则对“/”的请求将调用authenticatedHomePage()。否则它将调用homePage()。

这个问题已经问了两年多了,但由于我今天遇到的问题,我不鼓励在
@Controller
上使用
@Secured
@PreAuthorize

对我来说不起作用的是
@已验证的
@安全的
控制器:

@Controller
@Secured("ROLE_ADMIN")
public class AdministrationController {

// @InitBinder here...

@RequestMapping(value = "/administration/add-product", method = RequestMethod.POST)
public String addProductPost(@ModelAttribute("product") @Validated ProductDto product, BindingResult bindingResult) {
    // ...
}
验证器根本不会启动(SpringMVC4.1.2,SpringSecurity 3.2.5),也不会执行任何检查

Spring使用的CGLIB代理也会导致类似的问题(当类没有实现接口时,Spring会创建CGLIB代理;如果类实现了任何接口,则会生成JDK代理-,和)

正如我在上面链接的答案中提到的,在通常实现接口的服务层上使用Spring安全注释(因此使用JDK代理)并不是更好,因为这不会导致此类问题

如果您想保护web控制器的安全,最好使用绑定到特定URL的
,而不是控制器中的方法,它们工作得很好。就我而言:

<http use-expressions="true" disable-url-rewriting="true">

    ...

    <intercept-url pattern="/administration/**" access="hasRole('ROLE_ADMIN')" />

</http>

...

要扩展Andy提供的答案,您可以使用:

@PreAuthorize("hasRole('foo')")

检查特定角色。

已经有一个关于如何通过更改xml配置使其工作的回复;但是,如果您使用的是基于代码的配置,则可以通过在
@configuration
类上放置以下注释来实现相同的效果:

@EnableGlobalMethodSecurity(prePostEnabled=true)

首先,您需要在WebSecurity配置中添加此注释,以启用@Pre和@Post注释

    @EnableGlobalMethodSecurity(prePostEnabled = true)
您还可以按如下方式检查角色/权限

    @PreAuthorize("hasAuthority('ROLE_ADMIN')")
    @PreAuthorize("hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_USER') or ...")
相当于

    @PreAuthorize("hasRole('ROLE_ADMIN')")
您还可以检查多个角色/权限,如下所示

    @PreAuthorize("hasAuthority('ROLE_ADMIN')")
    @PreAuthorize("hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_USER') or ...")
步骤1:在SecurityConfig类中添加@EnableGlobalMethodSecurity(prespenabled=true)注释。 像这样:

 @Configuration
 @EnableWebSecurity
 @EnableGlobalMethodSecurity(prePostEnabled = true)
 public class SecurityConfig extends WebSecurityConfigurerAdapter {
   .....
 }
步骤2:您可以在控制器、服务或存储库层中添加@PreAuthorize()注释。在方法或类级别。 例如:

@RestController
@PreAuthorize("isAuthenticated()")    
public class WebController {  
  
    @PreAuthorize("permitAll()")  
    @GetMapping("/")  
    public String home() {  
        return "Welcome home!";  
    }

    @GetMapping("/restricted")   
    public String restricted() {  
        return "restricted method";  
    }
}


我把它放在我的spring安全应用程序上下文中(实际上我已经有了它),但是spring没有使用@Controller对控制器做任何事情。我需要做什么特别的事情才能让这项工作超越你所说的吗?InI说,
全局方法安全性
应该在DispatcherServlet的上下文(
..-servlet.xml
)中,而不是在“spring安全应用程序上下文”中。它们不会合并
DispatcherServlet
的上下文是
ContextLoaderListener
的子上下文。因此,它们具有不同的AOP配置,因此需要不同的
。谢谢,axtavt。你救了我一天。spring文档没有提到应该在…-servlet.xml中。我也将它放在安全应用程序上下文中,但它不起作用。一旦移动到…-servlet.xml,它就开始工作了。我仍然有一个问题,什么时候应该放在安全应用程序上下文中?@Georgie:应该放在您声明要应用安全注释的bean的每个上下文中。我试图在控制器中使用@PreAuthorize,但没有工作,在我移到服务层后工作。您确定这是等效的吗?我认为表达式hasRole会自动向提供的参数添加ROLE\前缀。