【问题标题】:Conditional property serialization with Jackson and JerseyJackson 和 Jersey 的条件属性序列化
【发布时间】:2017-02-28 22:03:21
【问题描述】:

我没有成功地尝试有条件地和动态地选择要序列化的属性以响应 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,但这是有条件的和动态的。到目前为止我发现的所有解决方案都是静态的。

这可能吗?

【问题讨论】:

  • 你看过@JsonView吗?

标签: java spring jersey jackson


【解决方案1】:

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查看完整的测试用例

【讨论】:

    【解决方案2】:

    您可以注册一个自定义 MessageBodyWriter https://jersey.java.net/documentation/latest/user-guide.html#d0e6951

    MessageBodyWriter 将使用您的自定义逻辑来决定要写什么。

    可以按照@dnault 的建议使用@JsonView 来完成。 http://www.baeldung.com/jackson-json-view-annotation

    您的 MessageBodyWriter 将持有一个杰克逊映射器,您将应用 writerWithView 和上面链接中描述的匹配视图类。

    编辑:看到这个 - Jackson Json serialization: exclude property respect to the role of the logged user

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-16
      • 2012-08-31
      • 1970-01-01
      • 2013-04-09
      • 2015-01-05
      • 2011-07-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多