簡體   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