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

Posted

技术标签:

【中文标题】Spring Security + MVC:相同的@RequestMapping,不同的@Secured【英文标题】:Spring Security + MVC : same @RequestMapping, different @Secured 【发布时间】:2013-08-02 11:25:02 【问题描述】:

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

【问题讨论】:

这种方法是不可能的,因为它是相同的 URL 映射。这将导致模棱两可的映射错误。尝试为每个用户构建不同的 URL 或接受这两个方法权限并在其中进行角色登录。您可以检索SecurityContextHolder上的权限 这可以使用自定义请求条件。该问题似乎与***.com/questions/10073695/… 重复 @Rob Winch 我不认为这是重复的,因为我询问了如何使用 @ Secured 注释进行操作,但感谢您的建议。 在这里查看接受的答案***.com/questions/10312177/…。尽管它在技术上并不能准确回答您的问题 - 使用预先存在的注释一起工作,它应该会有所帮助。 【参考方案1】:

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

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

在here 或here 也可以找到相关答案(虽然不是针对@Secured 注释,但机制相同)

【讨论】:

【参考方案2】:

我不认为你可以在 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 的公开和私人资料)

【讨论】:

你的建议是我的“备胎”。为了回答您的问题,在给定示例的后面,有一个 REST API。根据用户角色,返回的对象将包含实体的部分或全部数据。

以上是关于Spring Security + MVC:相同的@RequestMapping,不同的@Secured的主要内容,如果未能解决你的问题,请参考以下文章

spring (data, mvc, security) 依赖项:IncompatibleClassChangeError

Spring MVC 与 Spring Security 的集成测试

Spring 5 MVC - InternalResourceViewResolver 和 Spring Security

Spring MVC + Spring Security + LDAP

使用 Spring-Test-MVC 单元测试 Spring-Security - 集成 FilterChain / ServletFilter

如何使用 Spring Security / Spring MVC 处理表单登录