Jackson和Jersey

时间:2017-02-28 22:03:22

标签: java spring jersey jackson

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

这是否可能?

2 个答案:

答案 0 :(得分:3)

泽西岛支持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

中查看完整的测试用例

答案 1 :(得分:0)

您可以注册自定义MessageBodyWriter Where to write to localStorage in a Redux app?

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

可以使用@JsonView作为@dnault建议完成。 https://jersey.java.net/documentation/latest/user-guide.html#d0e6951

您的MessageBodyWriter将保存一个jackson映射器,您将使用匹配的视图类应用writerWithView,如上面的链接所述。

编辑:看到这一个 - http://www.baeldung.com/jackson-json-view-annotation