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