gpt4 book ai didi

java - 使用 JsonView 有选择地隐藏字段

转载 作者:行者123 更新时间:2023-12-02 08:48:02 25 4
gpt4 key购买 nike

我试图根据请求用户的角色有选择地隐藏响应中的某些字段。据我所知,来自 JacksonJsonView 可能是正确的选择。

我需要能够显示所有字段,除非它们已标记有特定的访问级别。我为访问级别创建了以下结构:

(快速说明:我已将基本用户留在那里,但这并不重要)

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

static {
MAPPING.put(Role.ROLE_ADMIN, Admin.class);
MAPPING.put(Role.ROLE_USER, AuthenticatedUser.class);
}

public interface User {}
public interface AuthenticatedUser extends User {}
public interface Admin extends AuthenticatedUser {}
}

并按如下方式使用它们:

@Entity
public class SomeEntity {
@Id
@GeneratedValue
private Integer id;

private String baseInfo;

@JsonView(View.AuthenticatedUser.class)
private String userInfo;

@JsonView(View.Admin.class)
private String secretInfo;

...
}

(PS:我已经去掉了所有非必要的注释等)

现在,我预计根据访问级别,响应如下:

  1. 未经身份验证的用户:
    {
    "id": 1,
    "baseInfo": "Some basic info"
    }
  2. 经过身份验证的用户:
    {
    "id": 1,
    "baseInfo": "Some basic info",
    "userInfo": "Info only the user should be able to see"
    }
  3. 管理员用户:
    {
    "id": 1,
    "baseInfo": "Some basic info",
    "userInfo": "Info only the user should be able to see",
    "secretInfo": "Info only the admin can see"
    }

我使用了 this 中的代码将其集成到 spring security 和我自己的结构中的教程。

@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<Role> foundRoles = authorities.stream()
.map(GrantedAuthority::getAuthority)
.map(Role::get).collect(Collectors.toList());

if (foundRoles.contains(null)) {
System.err.println("User has no auth. Setting no serialization view");
return;
}

List<Class> jsonViews = foundRoles.stream().map(View.MAPPING::get)
.collect(Collectors.toList());
if (jsonViews.size() == 1) {
System.err.println("Setting " + jsonViews.get(0) + " as serialization view");
bodyContainer.setSerializationView(jsonViews.get(0));
return;
}
throw new IllegalArgumentException("Ambiguous @JsonView declaration for roles "
+ authorities.stream()
.map(GrantedAuthority::getAuthority).collect(Collectors.joining(",")));
}
System.err.println("No auth found");
}
}

(请原谅糟糕的代码,我一直在尝试一切......)

此时,我希望结果与我上面所说的一样,但我继续获取所有字段,而不进行任何类型的过滤。任何类型的注释都不能避免字段被序列化。我知道我可以将默认值设置为排除除我注释的字段之外的所有字段,但这意味着注释所有字段并且项目相当大。

我对 JsonView 的最初假设是错误的,还是我在某个地方犯了错误?

提前致谢

最佳答案

感谢@second的评论,我已经能够解决这个问题了。事实证明我犯了两个小错误:

1。设置 Jackson 默认包含所有属性

第一个更改是在 application.properties 文件中将 spring.jackson.mapper.default_view_inclusion 设置为 true。通过这样做,Jackson 将默认包含所有属性,从而消除有效负载为空的问题

2。使用“基本”用户

每当未经身份验证的用户尝试访问系统时,我们都需要将序列化 View 设置为基本用户。在我上面的帖子中,我有 User View ,但我从未使用过它。将其设置为默认序列化 View (在上面的拦截器中)解决了问题,结果就是我上面所说的。

编辑

我上传了一个示例here 。它非常简单,但它显示了如何排除不同的字段。像这样使用:

  • http://localhost:8080/test
    {
    "id":1,
    "baseInfo":"This is the base info"
    }
  • http://localhost:8080/test?view=user
    {
    "id":1,
    "baseInfo":"This is the base info",
    "userInfo":"This is the user info"
    }
  • http://localhost:8080/test?view=admin
    {
    "id":1,
    "baseInfo":"This is the base info",
    "userInfo": "This is the user info",
    "secretInfo":"This is the secret info"
    }

希望这有帮助!

关于java - 使用 JsonView 有选择地隐藏字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60956757/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com