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



假设我们有一个使用SpringMVC和SpringSecurity配置的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"方法,并基于该方法和@Secured注释的存在来构造RequestCondition的自定义实现。然后,在将传入请求与方法进行匹配时,会考虑所有这些信息。

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

我认为在springmvc中无法做到这一点,因为springmvc的路由引擎没有考虑两个路由具有完全相同的@RequestMapping@Secured)。最简单的解决方案是这样做:

@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;
    }
}

但是,我会更改您的设计,因为每个角色的响应不同,为什么不使用两个略有不同的URL的单独请求映射呢?如果在某个时候,用户同时扮演角色A和B,则不能让用户选择要得到的响应(例如,想想LinkedIn的公共和私人档案)

最新更新