簡體   English   中英

如何處理 Spring Boot 應用中的多租戶問題?

[英]How to handle the multitenancy problem in Spring Boot applications?

假設我有一個具有以下要求的SpringBoot應用程序。

  1. 它有一個User類(實體)
  2. 每個用戶有零個或多個Workspaces (一對多實體關系)
  3. 每個Workspace有零個或多個WorkItems (一對多實體關系)

有一個 CRUD REST API 控制器來管理所有實體,即我們有

  1. UserController -> User實體的 CRUD 操作
  2. WorkspaceController -> Workspace實體的 CRUD 操作
  3. WorkItemContoller -> WorkItem實體的 CRUD 操作

現在有要求...

  1. User只能創建/編輯/刪除他自己的Workspace實體
  2. User只能在他自己的Workspaces創建/編輯/刪除WorkItem實體

此外,假設User實體與SpringSecurity集成,並且我們知道控制器和服務中的當前用戶。

那么問題來了...

實現用戶權限檢查的最優雅/干凈/可維護的方式是什么? 我們如何編寫代碼,該代碼在Service類中將檢查用戶是否有權對給定資源執行操作。

我現在這樣做的方式是有一個這樣的類,它檢查每個Service調用中的權限。

class PermissionManager {
   void checkUserAllowedToUseWorkspace(User u, Workspace w);
   void checkUserAlloweToUseWorkitem(User u, WorkItem)
}

正如您所看到的……隨着作用域資源的數量不斷增加……這個類將變得非常臃腫且難以維護。

有沒有人知道以干凈和可維護的方式進行此范圍資源訪問的更好方法?

最干凈和可維護的解決方案是利用Spring Security AOP 來完成任務。

您可以使用@PreAuthorize注釋,與您的PermissionManager服務配對,以利用Spring Expression Language的強大功能在Controller級別允許或拒絕訪問。

定義了一個Service構造型,用於檢查用戶對特定資源(示例中的工作區)的訪問權限:

@Service
public class PermissionManagerImpl implements PermissionManager {

    @Autowired
    private UserRepository userRepository;

   /**
   * @param authentication the current authenticated user following your authentication scheme
   * @param workspaceId the workspace (or other resource) identifier
   */
    @Override
    public boolean checkUserAllowedToUseWorkspace(Authentication authentication, Long workspaceId) {
        return authentication != null
                /* check that the `authentication` has access to the argument workspace: e.g. userRepository.findWorkspaceByUserNameAndWorkspaceId(authentication.getName(), workspaceId) != null */;
    }

}

您可以在Controller方法上定義基於表達式的控制策略,如下所示:

@RestController
public class WorkspaceController {

    // the DIed `permissionManagerImpl` service will be called prior to your endpoint invocation with the current `authentication` and workspace `id` injected
    @PreAuthorize("@permissionManagerImpl.checkUserAllowedToUseWorkspace(authentication, #id)")
    @RequestMapping("/workspaces/{id}")
    public List<Workspace> getWorkspaces(@PathVariable Long id) {
        // retrieve the user workspaces once authorized
    }
}

這將導致一個可讀且可重用的解決方案作用於頂級資源Controller

您可以在官方Spring文檔 中了解有關基於表達式的訪問控制的更多信息。

Workspace Entity 的一些數據庫查詢:

// DELETE
@Transactional
void deleteByIdAndUserId(String workspaceId, String userId);

userRepository.deleteByIdAndUserId(workspaceId, userId);


// UPDATE
Optional<Workspace> workspace = workspace.findByIdAndUserId(String workspaceId, String userId);

Workspace workspace = workspace.orElseThrow(() -> new RuntimeException("You don't have an workspace under user "))

workspace.setName("MyWorkspace2");

//CREATE
User user = userRepository.findById(SecurityContextHolder...getPriciple().getId())
              .orElseThrow(() -> new RuntimeException("User can not be found by given id"));
workspaceRepository.save(WorkspaceBuilder.builder().user(user).name("firstWorkspace").build());

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM