我未能成功尝试有条件地和动态地选择要序列化的属性以响应 Jersey(使用 Jackson)的每个请求。这背后的想法是在 REST API 中安全地访问对象的属性。
我在 API 调用中返回了几个对象,这些对象应该根据经过身份验证的用户显示/隐藏字段。
例如,假设我有一个对象 Car
public class Car implements Serializable {
private Long id;
private String VIN;
private String color;
...
}
假设如果具有 ROLE_ADMIN
的用户通过身份验证,则应返回所有属性,但如果没有登录用户,则只需显示前两个。
我正在考虑构建一些基于注释的东西。像这样的东西:
public class Car implements Serializable {
private Long id;
private String VIN;
@Secured({AccessRole.ROLE_ADMIN})
private String color;
...
}
在这种情况下,只有当请求用户的访问角色与通过注释传递的访问角色匹配时,才应返回 color
属性。
但是我不知道应该在哪里实现这个逻辑。
我要实现的是一种 @JsonIgnore
但这是有条件的和动态的。到目前为止我找到的所有解决方案都是静态的。
这有可能吗?
最佳答案
Jersey 支持 Entity Filtering .除了一般过滤,它还支持Role-based Entity Filtering using (javax.annotation.security) annotations .
因此您可以在域模型属性上使用@RolesAllowed
、@PermitAll
和@DenyAll
注释
public static class Model {
private String secured;
@RolesAllowed({"ADMIN"})
public String getSecured() { return this.secured; }
}
不过,要使其正常工作,您需要在请求过滤器中设置 SecurityContext
。 Jersey 将查找 SecurityContext
来验证角色。您可以在 this post 中阅读更多相关信息(注意:实体过滤与该帖子中提到的任何实际授权是分开的。但该帖子确实解释了 SecurityContext)。
基本上你会有类似的东西(注意你设置 SecurityContext 的最后一行)。
@PreMatching
public static class SimpleAuthFilter implements ContainerRequestFilter {
private static final Map<String, User> userStore = new ConcurrentHashMap<>();
static {
userStore.put("peeskillet", new User("peeskillet", Arrays.asList("ADMIN", "USER")));
userStore.put("paulski", new User("paulski", Arrays.asList("USER")));
}
@Override
public void filter(ContainerRequestContext request) throws IOException {
final String authHeader = request.getHeaderString("Authorization");
final String username = authHeader.split("=")[1];
final User user = userStore.get(username);
if (user == null) {
throw new NotAuthorizedException("No good.");
}
request.setSecurityContext(new SimpleSecurityContext(user));
}
}
其中 SimpleSecurityContext
只是您自己的一个类,您需要在其中覆盖 isUserInRole
方法并检查用户是否具有该角色
private static class SimpleSecurityContext implements SecurityContext {
private final User user;
SimpleSecurityContext(User user) {
this.user = user;
}
@Override
public Principal getUserPrincipal() {
return new Principal() {
@Override
public String getName() {
return user.getUsername();
}
};
}
@Override
public boolean isUserInRole(String role) {
return user.getRoles().contains(role);
}
@Override
public boolean isSecure() {
return false;
}
@Override
public String getAuthenticationScheme() {
return "simple";
}
}
差不多就这些了。您还需要向应用程序注册 SecurityEntityFilteringFeature
以使其全部正常工作。
请参阅 this Gist 中的完整测试用例
关于java - Jackson 和 Jersey 的条件属性序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42519571/