Spring Security可以在Spring控制器方法上使用@PreAuthorize吗?


Answers:


70

是的,它工作正常。

你需要<security:global-method-security pre-post-annotations="enabled" />...-servlet.xml。它还需要CGLIB代理,因此您的控制器不应该具有接口,或者您应该使用proxy-target-class = true


1
我把它放在我的Spring安全应用程序上下文中(实际上我已经拥有了),但是Spring对使用@Controller的控制器不做任何事情。为了使此功能超出您的所说,我是否需要做任何特殊的事情?在
egervari

13
我说过,global-method-security应该在DispatcherServlet的context(...-servlet.xml)中而不是在“ spring security application context”中。
axtavt 2010年

2
它们没有合并。DispatcherServlet的上下文是的上下文ContextLoaderListener。因此,它们具有不同的AOP配置,因此需要出现不同的<global-method-security>
axtavt 2010年

1
谢谢,axtavt。你救了我的日子。春季文档没有提到<security:global-method-security pre-post-annotations =“ enabled” />应该位于...- servlet.xml中。我也将其放在安全性应用程序上下文中,但无法正常工作。一旦移动到...- servlet.xml,它便开始工作。我还有一个问题,何时将<security:global-method-security>放在安全应用程序上下文中?
Georgie Porgie 2011年

1
@Georgie:应该将其放置在已声明要对其应用安全注释的bean的每个上下文中。
axtavt 2011年

26

请参阅Spring Security FAQ(重点是我的)。

在Spring Web应用程序中,保存用于调度程序Servlet的Spring MVC bean的应用程序上下文通常与主应用程序上下文分开。它通常在名为myapp-servlet.xml的文件中定义,其中“ myapp”是在web.xml中分配给Spring DispatcherServlet的名称。一个应用程序可以具有多个DispatcherServlet,每个都有自己的隔离的应用程序上下文。这些“子”上下文中的Bean对应用程序的其余部分不可见。“父”应用程序上下文由您在web.xml中定义的ContextLoaderListener加载,并且对所有子上下文可见。通常在此父上下文中定义安全配置(包括元素)。结果,将不会强制实施应用于这些Web Bean中的方法的任何安全性约束,因为无法从DispatcherServlet上下文中看到bean。您需要将声明移至Web上下文,或将要保护的bean移至主应用程序上下文。

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

如果将切入点应用于服务层,则只需<global-method-security>在应用程序的安全上下文中进行设置。


试图在控制器中使用@PreAuthorize,但没有用,一旦我移到服务层就可以使用。
MarCrazyness

17

如果您使用的是Spring 3.1,则可以执行一些非常酷的操作。看看https://github.com/mohchi/spring-security-request-mapping。这是一个示例项目,将@PreAuthorize与Spring MVC的RequestMappingHandlerMapping集成在一起,因此您可以执行以下操作:

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

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

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


10

这是两年多以来,这一问题被提出,但由于问题,我今天我宁愿反对使用@Secured@PreAuthorize等上@Controller秒。

对我不起作用的是@Validated@Secured控制器结合在一起的:

@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) {
    // ...
}

验证程序不会触发(Spring MVC 4.1.2,Spring Security 3.2.5),并且不执行任何检查。

类似的问题是由Spring使用的CGLIB代理引起的(当一个类没有实现任何接口时,Spring会创建CGLIB代理;如果该类实现了任何接口,则将生成JDK代理-文档在这里这里都有很好的解释)。

正如我在上面链接的答案中所提到的,最好在通常实现接口的服务层上使用Spring Security批注(因此使用JDK Proxies),因为这不会导致此类问题。

如果要保护Web控制器的安全,最好的方法是使用,<http>并将<intercept-url />其绑定到特定的URL,而不是绑定到控制器中的方法,并且效果很好。就我而言:

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

    ...

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

</http>

6

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

@EnableGlobalMethodSecurity(prePostEnabled=true)

1

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

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

检查具体角色。


0

首先,您需要在WebSecurityConfig中添加此批注以启用@Pre和@Post批注。

    @EnableGlobalMethodSecurity(prePostEnabled = true)

您还可以如下检查角色/权限

    @PreAuthorize("hasAuthority('ROLE_ADMIN')")

相当于

    @PreAuthorize("hasRole('ROLE_ADMIN')")

您还可以如下检查多个角色/权限

    @PreAuthorize("hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_USER') or ...")

您确定它是等效的吗?我认为表达式hasRole会自动将ROLE_前缀添加到提供的参数中。
zeratul021'4

0

步骤1:在SecurityConfig类中添加@EnableGlobalMethodSecurity(prePostEnabled = 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";  
    }
}

要么

@RestController    
public class AdminController {
   
   
   @PreAuthorize("hasRole('ADMIN')")
   @GetMapping("/admin")
   public String adminMethod() {
   }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.