Я пытаюсь выборочно скрыть определенные поля в ответе, в зависимости от роли запрашивающего его пользователя. Из того, что я смог понять, JsonView
из Jackson
может быть путем к go.
Мне нужно иметь возможность отображать все поля, ЕСЛИ они не были помечены с указанием c уровень доступа. Я создал следующую структуру для уровней доступа:
(Быстрое примечание: я оставил там базового пользователя, но это не должно иметь большого значения)
public class View {
public static final Map<Role, Class> MAPPING = new HashMap<>();
static {
MAPPING.put(Role.ROLE_ADMIN, Admin.class);
MAPPING.put(Role.ROLE_USER, AuthenticatedUser.class);
}
public interface User {}
public interface AuthenticatedUser extends User {}
public interface Admin extends AuthenticatedUser {}
}
И использовал их следующим образом:
@Entity
public class SomeEntity {
@Id
@GeneratedValue
private Integer id;
private String baseInfo;
@JsonView(View.AuthenticatedUser.class)
private String userInfo;
@JsonView(View.Admin.class)
private String secretInfo;
...
}
(PS: я удалил все несущественные аннотации и т. д. c.)
Теперь я ожидаю, что в зависимости от уровня доступа, Ответы следующие:
- Неаутентифицированный пользователь:
{
"id": 1,
"baseInfo": "Some basic info"
}
- Аутентифицированный пользователь:
{
"id": 1,
"baseInfo": "Some basic info",
"userInfo": "Info only the user should be able to see"
}
- Администратор:
{
"id": 1,
"baseInfo": "Some basic info",
"userInfo": "Info only the user should be able to see",
"secretInfo": "Info only the admin can see"
}
Я использовал код из этого учебника, чтобы интегрировать его в Spring Security и мою собственную структуру.
@RestControllerAdvice
class SecurityJsonViewControllerAdvice extends AbstractMappingJacksonResponseBodyAdvice {
@Override
protected void beforeBodyWriteInternal(MappingJacksonValue bodyContainer, MediaType contentType, MethodParameter returnType, ServerHttpRequest request, ServerHttpResponse response) {
if (SecurityContextHolder.getContext().getAuthentication() != null && SecurityContextHolder.getContext().getAuthentication().getAuthorities() != null) {
Collection<? extends GrantedAuthority> authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
List<Role> foundRoles = authorities.stream()
.map(GrantedAuthority::getAuthority)
.map(Role::get).collect(Collectors.toList());
if (foundRoles.contains(null)) {
System.err.println("User has no auth. Setting no serialization view");
return;
}
List<Class> jsonViews = foundRoles.stream().map(View.MAPPING::get)
.collect(Collectors.toList());
if (jsonViews.size() == 1) {
System.err.println("Setting " + jsonViews.get(0) + " as serialization view");
bodyContainer.setSerializationView(jsonViews.get(0));
return;
}
throw new IllegalArgumentException("Ambiguous @JsonView declaration for roles "
+ authorities.stream()
.map(GrantedAuthority::getAuthority).collect(Collectors.joining(",")));
}
System.err.println("No auth found");
}
}
(Простите за ужасный код, я пытался немного все ...)
На данный момент, я ожидаю, что результат будет таким, как я говорил выше, но я продолжаю получать все поля, без какой-либо фильтрации. Ни один тип аннотации не исключает сериализацию полей. Я знаю, что по умолчанию я могу установить, что все поля исключены, КРОМЕ тех, которые я аннотирую, но это будет означать аннотирование всех полей, и проект довольно большой.
Мое первоначальное предположение о JsonView
неверно , или я где-то ошибаюсь?
Заранее спасибо