繁体   English   中英

如何仅对用户自己的端点启用请求

[英]How can I enable request only for user's own endpoint

我有一个这样的休息端点:/ users / {userId} / something

我使用oauth2实现了身份验证。 我的WebSecurityConfig看起来像这样:

protected void configure(HttpSecurity http) throws Exception {
    http
    .authorizeRequests()
    .anyRequest().authenticated()
    .and()
    .formLogin()
    .loginPage("/login").permitAll();
}

如何仅允许用户访问自己的终结点(例如,ID为100的用户只能访问/users/100/something )而无法看到另一个终结点(例如/users/200/something )?

这可能吗?

有很多方法可以解决此问题,但我已经提出了三种解决该问题的方法。

自定义安全性表达

我建议使用基于自定义安全性的注释方法。 这将涉及实现自定义安全性表达式,相关的表达式处理程序和方法安全性配置。 如果这对您来说太多了,那么下一个方法会更简单一些。

public class UserIdentityMethodSecurityExpressionRoot 
    extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {

    public UserIdentityMethodSecurityExpressionRoot(Authentication authentication) {
        super(authentication);
    }

    public boolean userIdentity(Long userId) {
        User user = ((UserPrincipal) this.getPrincipal()).getUser();
        return user.getId() == userId;
    }
}

然后,可以使用新创建的安全性表达式对其余端点或服务方法进行注释:

@PreAuthorize("userIdentity(#userId)")
@GetMapping
@ResponseBody
public Resource fineOne(@PathVariable Long userId) {
    return resourceService.findOne(id);
}

请注意,必须在某处@PathVariable@RequestParam形式提供userId 然后,Spring Security将检查当前用户是否与提供的userId匹配,否则返回403

完整的示例在此处可用并且已针对您的目的在此问题中进行了调整。

规划环境地政司

您还可以使用SpEL,这有点简单:

@PreAuthorize("#userId == principal.getId()")
@GetMapping
@ResponseBody
public Resource fineOne(@PathVariable Long userId) {
    return resourceService.findOne(id);
}

其他注意事项

您也可以自己完成所有工作,并获得更快的结果,而无需使用SecurityContextHolder定义自定义表达式。

public static void checkUserIdentity(Long userId) {
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    // user did not provide a token
    if(auth == null) {
        throw new AccessDeniedException(); 
    }      
    UserDetails details = (UserDetails) auth.getPrincipal();
    if(userId != details.getId()) {
        throw new AccessDeniedException(); 
    }
} 

并像这样使用它:

@GetMapping
@ResponseBody
public Resource fineOne(@PathVariable Long userId) {
    SecurityUtils.checkUserIdentity(userId)
    return resourceService.findOne(id);
}

为什么这样做? 如果您已经正确设置了Spring安全性,那么SecurityContextHolder将注入当前的主体。 默认情况下,身份验证绑定到当前的执行线程,如果请求已处理或遇到异常,则将重置身份验证。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM