知識庫 / JSON / Jackson RSS 訂閱

基於 Spring Security 角色過濾 Jackson JSON 輸出

Jackson,Spring Security
HongKong
8
09:54 PM · Dec 05 ,2025

1. 概述

在本快速教程中,我們將演示如何根據 Spring Security 中定義的用户角色,過濾 JSON 序列化輸出。

2. 我們需要過濾的原因是什麼?

讓我們考慮一個簡單的但常見的用例,即我們有一個為不同角色提供服務的 Web 應用程序。例如,這些角色可以是 用户管理員

首先,讓我們定義一個要求:管理員 擁有通過公共 REST API 提供的對象內部狀態的完整訪問權限。相反,用户 只能看到對象預定義的屬性集。

我們將使用 Spring Security 框架來防止未經授權的 Web 應用程序資源訪問。

讓我們定義一個我們將作為 REST 響應負載返回的 對象:

class Item {
    private int id;
    private String name;
    private String ownerName;

    // getters
}

當然,我們也可以為應用程序中每個角色定義一個單獨的數據傳輸對象類。然而,這種方法會導致代碼庫中產生無用的重複或複雜的類層次結構。

另一方面,我們可以利用 Jackson 庫的 JSON 視圖功能。正如我們在下一部分所看到的,它使將 JSON 表示形式定製變得像添加註釋一樣簡單

3. <em @JsonView 註解

Jackson 庫支持通過標記希望包含在 JSON 表示中的字段,使用 <em @JsonView 註解來定義多個序列化/反序列化上下文。該註解具有一個 必需的 <em Class 類型參數,用於區分上下文。

當我們在類中標記字段時使用 <em @JsonView,應注意,默認情況下,序列化上下文包括所有未明確標記為屬於視圖的屬性。為了覆蓋此行為,可以禁用 <em DEFAULT_VIEW_INCLUSION 映射器功能。

首先,讓我們 定義一個 <em View 類,其中包含一些我們將用作 <em @JsonView 註解參數的內類:

class View {
    public static class User {}
    public static class Admin extends User {}
}

接下來,我們為我們的類添加了 @JsonView 註解,使得 ownerName 僅對管理員角色可見:

@JsonView(View.User.class)
private final int id;
@JsonView(View.User.class)
private final String name;
@JsonView(View.Admin.class)
private final String ownerName;

4. 如何將 @JsonView 註解與 Spring Security 集成

現在,讓我們添加一個枚舉,其中包含所有角色及其名稱。接下來,我們將介紹 JSON 視圖與安全角色之間的映射關係:

enum Role {
    ROLE_USER,
    ROLE_ADMIN
}

class View {

    public static final Map<Role, Class> MAPPING = new HashMap<>();

    static {
        MAPPING.put(Role.ADMIN, Admin.class);
        MAPPING.put(Role.USER, User.class);
    }

    //...
}

最後,我們終於來到了集成中的核心要點。為了將 JSON 視圖與 Spring Security 角色關聯起來,我們需要定義應用於應用程序中所有控制器方法的控制器建議,以完成 JSON 視圖與 Spring Security 角色關聯。

目前,我們唯一需要做的就是覆蓋 beforeBodyWriteInternal 方法 AbstractMappingJacksonResponseBodyAdvice

@RestControllerAdvice
class SecurityJsonViewControllerAdvice extends AbstractMappingJacksonResponseBodyAdvice {

    @Override
    protected void beforeBodyWriteInternal(
      MappingJacksonValue bodyContainer,
      MediaType contentType,
      MethodParameter returnType,
      ServerHttpRequest request,
      ServerHttpResponse response) {
        if (SecurityContextHolder.getContext().getAuthentication() != null
          && SecurityContextHolder.getContext().getAuthentication().getAuthorities() != null) {
            Collection<? extends GrantedAuthority> authorities
              = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
            List<Class> jsonViews = authorities.stream()
              .map(GrantedAuthority::getAuthority)
              .map(AppConfig.Role::valueOf)
              .map(View.MAPPING::get)
              .collect(Collectors.toList());
            if (jsonViews.size() == 1) {
                bodyContainer.setSerializationView(jsonViews.get(0));
                return;
            }
            throw new IllegalArgumentException("Ambiguous @JsonView declaration for roles "
              + authorities.stream()
              .map(GrantedAuthority::getAuthority).collect(Collectors.joining(",")));
        }
    }
}

這樣一來,每一條來自我們應用程序的響應都會經過此處的建議,並且它會根據我們已定義的角色映射查找適當的視圖表示形式。請注意,這種方法要求我們在處理具有多個角色的用户時要格外小心

5. 結論

在本簡短教程中,我們學習瞭如何在 Web 應用程序中根據 Spring Security 角色過濾 JSON 輸出。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.