【发布时间】:2020-03-31 17:45:34
【问题描述】:
我正在尝试选择性地隐藏响应中的某些字段,具体取决于请求它的用户的角色。据我所知,JsonView 来自Jackson 可能是要走的路。
我需要能够显示所有字段,除非它们被标记为特定的访问级别。我为访问级别创建了以下结构:
(快速说明:我已经将基本用户留在了那里,但这并不重要)
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:我已经剥离了所有非必要的注释等)
现在,我希望根据访问级别,响应如下:
- 未经身份验证的用户:
{ "id": 1, "baseInfo": "Some basic info" } - 经过身份验证的用户:
{ "id": 1, "baseInfo": "Some basic info", "userInfo": "Info only the user should be able to see" } - 管理员用户:
{ "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");
}
}
(请原谅糟糕的代码,我一直在尝试所有的东西......)
在这一点上,我希望结果与我上面所说的一样,但我继续获取所有字段,没有任何过滤。没有任何类型的注释可以避免字段被序列化。我知道我可以将默认设置为排除所有字段,但我注释的字段除外,但这意味着注释所有字段并且项目很大。
我对@987654330@ 的最初假设是错误的,还是我在某个地方犯了错误?
提前致谢
【问题讨论】:
-
我尝试了您的代码,但得到了不同的结果。我得到的不是所有字段,而是一个空的json消息
{}作为响应(如果角色是User)。如果角色匹配,则只有那些带有@JsonView注释的字段才会被序列化。也许您从示例代码中删除了一个重要的注释? -
你是绝对正确的。我刚刚创建了另一个项目,它按您所说的那样工作,这意味着没有返回任何字段。您需要将
spring.jackson.mapper.default_view_inclusion=true属性设置为具有所有字段。通过这个项目,我得到了预期的结果,所以我猜问题出在我的代码中的其他地方。感谢您的帮助!
标签: java spring-boot spring-security jackson