Spring 安全性可以在 Spring 控制器方法上使用 @PreAuthorize吗?
@PreAuthorize
是的,很好用。
你需要 ...-servlet.xml中的 <security:global-method-security pre-post-annotations="enabled" />。它还需要 CGLIB 代理,所以要么您的控制器不应该有接口,要么您应该使用 proxy-target-class = true。
...-servlet.xml
<security:global-method-security pre-post-annotations="enabled" />
proxy-target-class = true
参见 Spring 安全常见问题(强调我的)。
在 Springweb 应用程序中,包含 调度程序 servlet 的 Spring MVC bean 通常与 主应用程序上下文。它通常定义在一个名为 Myapp-servlet.xml,其中“ myapp”是分配给 Spring 的名称 一个应用程序可以有多个 DispatcherServlets,每个都有自己独立的应用程序上下文。 这些“子”上下文中的 bean 对于 “父”应用程序上下文由 在 web.xml 中定义的 ContextLoaderListener 对所有用户都是可见的 这个父上下文通常是你定义 您的安全配置,包括 元素中的方法应用的任何安全约束 这些 web bean 不会被强制执行,因为 bean 不能被看到 从 DispatcherServlet 上下文中移除 声明到网络上下文或移动 您希望保护到主应用程序上下文中的 bean。 通常,我们建议在服务中应用方法安全性 层而不是单独的 web 控制器
在 Springweb 应用程序中,包含 调度程序 servlet 的 Spring MVC bean 通常与 主应用程序上下文。它通常定义在一个名为 Myapp-servlet.xml,其中“ myapp”是分配给 Spring 的名称 一个应用程序可以有多个 DispatcherServlets,每个都有自己独立的应用程序上下文。 这些“子”上下文中的 bean 对于 “父”应用程序上下文由 在 web.xml 中定义的 ContextLoaderListener 对所有用户都是可见的 这个父上下文通常是你定义 您的安全配置,包括 元素中的方法应用的任何安全约束 这些 web bean 不会被强制执行,因为 bean 不能被看到 从 DispatcherServlet 上下文中移除 声明到网络上下文或移动 您希望保护到主应用程序上下文中的 bean。
通常,我们建议在服务中应用方法安全性 层而不是单独的 web 控制器
如果您将切入点应用到服务层,那么您只需要在应用程序的安全上下文中设置 <global-method-security>。
<global-method-security>
如果你使用的是 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"; }
如果用户通过了身份验证,那么对“/”的请求将调用 enticatedHomePage () ,否则将调用 homePage ()。
这个问题已经问了两年多了,但是由于我今天遇到的问题,我宁愿不鼓励在 @Controller上使用 @Secured、 @PreAuthorize等等。
@Controller
@Secured
@Validated和 @Secured控制器结合在一起对我不起作用:
@Validated
@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) { // ... }
验证器根本不会触发(SpringMVC 4.1.2,SpringSecurity 3.2.5) ,也不会执行任何检查。
类似的问题也是由 Spring 使用的 CGLIB 代理造成的(当没有类实现的接口时,Spring 会创建 CGLIB 代理; 如果类实现了任何接口,那么就会生成 JDK 代理—— 文件、 解释得很好和 给你)。
正如我在上面链接的答案中所提到的,在通常实现接口(因此使用 JDK 代理)的服务层上使用 Spring Security 注释并不会更好,因为这不会导致这样的问题。
如果你想保护 web 控制器,更好的办法是使用 <http>和 <intercept-url />,它们绑定到特定的 URL,而不是控制器中的方法,并且工作得很好。就我而言:
<http>
<intercept-url />
<http use-expressions="true" disable-url-rewriting="true"> ... <intercept-url pattern="/administration/**" access="hasRole('ROLE_ADMIN')" /> </http>
要扩展 Andy 提供的答案,可以使用:
@PreAuthorize("hasRole('foo')")
检查具体的角色。
关于如何通过更改 xml 配置使其工作,已经有了答复; 但是,如果您使用的是基于代码的配置,则可以通过在 @Configuration类上放置以下注释来实现同样的功能:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true)
首先,需要在 WebSecurityConfig 中添加这个注释,以启用@Pre 和@Post 注释。
@EnableGlobalMethodSecurity(prePostEnabled = true)
您还可以按照以下方式检查角色/权限
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
等同于
@PreAuthorize("hasRole('ROLE_ADMIN')")
您还可以检查多个角色/权限,如下所示
@PreAuthorize("hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_USER') or ...")
Step 1: 在 SecurityConfig 类中添加 @ EnableGlobalMethodSecurity (prePostEnable = true)注释。 像这样:
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { ..... }
步骤2: 您可以在控制器、服务或存储库层添加 @ 预先授权()注释。 例如:
@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() { } }