Spring Security + MVC:相同的@RequestMapping,不同的@Secured

假设我们有一个使用Spring MVC和Spring Security配置的API端点。 我们希望能够处理成对的@RequestMapping和@Secured注释,其中唯一的@Secured注释值因配对而异。 这样,我们就可以根据同一请求的安全规则返回不同的响应主体。

这可以通过避免直接检查方法体中的安全规则来允许我们的代码更易于维护。

有一个不成功的例子,我们想做的是:

@Controller @RequestMapping("/api") public class Controller { @Secured ({"ROLE_A"}) @RequestMapping(value="{uid}", method=RequestMethod.GET) @ResponseBody public Response getSomething(@PathVariable("uid") String uid) { // Returns something for users having ROLE_A } @Secured ({"ROLE_B"}) @RequestMapping(value="{uid}", method=RequestMethod.GET) @ResponseBody public Response getSomethingDifferent(@PathVariable("uid") String uid) { // Returns something different for users having ROLE_B } } 

我们怎样才能做到这一点? 如果可以这样做:如何为同时具有ROLE_A和ROLE_B的用户管理优先级?

假设您正在使用Spring 3.1(或更高版本)以及RequestMappingHandlerMapping(和RequestMappingHandlerAdapter),您可以扩展请求映射机制。 您可以通过创建自己的RequestCondition接口实现并扩展RequestMappingHandlerMapping来基于方法上的@Secured注释来构造它。

您需要覆盖RequestMappingHandlerMapping上的’getCustomMethodCondition’方法,并基于Method和@Secured注释的存在构造您的RequestCondition的自定义实现。 然后在将传入请求与方法匹配时考虑所有这些信息。

相关答案(虽然不是特定于@Secured注释但机制相同)也可以在这里或这里找到

我不认为你可以在spring-mvc中做到这一点,因为两个路由完全相同@RequestMapping@Secured )没有被spring-mvc的路由引擎考虑在内。 最简单的解决方案是:

 @Secured ({"ROLE_A", "ROLE_B"}) @RequestMapping(value="{uid}", method=RequestMethod.GET) @ResponseBody public Response getSomething(@PathVariable("uid") String uid, Principal p) { // Principal p gets injected by spring // and you need to cast it to check access roles. if (/* p.hasRole("ROLE_A") */) { return "responseForA"; } else if (/* p.hasRole("ROLE_B") */) { return "responseForB"; } else { // This is not really needed since @Secured guarantees that you don't get other role. return 403; } } 

但是,我会更改您的设计,因为每个角色的响应不同,为什么没有2个单独的请求映射与略有不同的URL? 如果在某些时候您同时拥有角色A和B的用户,则不能让用户选择要获取的响应(例如,想想LinkedIn的公共和私人配置文件)