假设我们使用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的用户管理优先级?
答案 0 :(得分:4)
假设您正在使用Spring 3.1(或更高版本)以及RequestMappingHandlerMapping(和RequestMappingHandlerAdapter),您可以扩展请求映射机制。您可以通过创建自己的RequestCondition接口实现并扩展RequestMappingHandlerMapping来构建基于方法的@Secured注释来构建它。
您需要在RequestMappingHandlerMapping上覆盖'getCustomMethodCondition'方法,并基于Method和@Secured注释的存在构造您的RequestCondition的自定义实现。然后在将传入请求与方法匹配时考虑所有这些信息。
答案 1 :(得分: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;
}
}
但是,我会更改您的设计,因为每个角色的响应不同,为什么没有2个单独的请求映射与略有不同的URL?如果在某些时候您同时拥有角色A和B的用户,则不能让用户选择要获取的响应(例如,想想LinkedIn的公共和私人配置文件)