繁体   English   中英

用Jackson和Jersey进行条件属性序列化

[英]Conditional property serialization with Jackson and Jersey

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

这有可能吗?

泽西岛支持实体过滤 除了常规过滤,它还支持使用(javax.annotation.security)批注的基于角色的实体过滤

因此,您可以在域模型属性上使用@RolesAllowed@PermitAll@DenyAll批注

public static class Model {
    private String secured;

    @RolesAllowed({"ADMIN"})
    public String getSecured() { return this.secured; }
}

但是,要使此工作有效,您需要在请求过滤器内设置SecurityContext 泽西岛将查找SecurityContext来验证角色。 您可以在这篇文章中了解更多信息 (注意:实体过滤与该文章中提到的任何真实授权是分开的。但是该文章确实解释了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才能使其全部正常工作。

此要点中查看完整的测试用例

您可以注册自定义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)序列化:排除有关已登录用户角色的属性

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM