12

假设我们有一个使用 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 的用户管理优先级?

4

2 回答 2

4

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

您需要覆盖 RequestMappingHandlerMapping 上的“getCustomMethodCondition”方法,并根据 Method 和 @Secured 注释的存在构造您的 RequestCondition 自定义实现。在将传入请求与方法匹配时,所有这些信息都会被考虑在内。

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

于 2013-08-19T12:36:48.833 回答
3

我认为您不能在 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;
    }
}

但是,我会更改您的设计,因为每个角色的响应不同,为什么不使用 URL 略有不同的 2 个单独的请求映射?如果在某个时候,您同时拥有角色 A 和 B 的用户,则不能让用户选择要获得的响应(例如,考虑 LinkedIn 的公开和私人资料)

于 2013-08-01T13:58:21.663 回答