Как настроить Spring-Data-Rest таким образом, чтобы он возвращал только данные, принадлежащие зарегистрированному пользователю - PullRequest
1 голос
/ 11 января 2020

Я работаю над приложением Spring Boot RESTful, которое будет предоставлять набор API для веб-приложения для выполнения операций CRUD над ресурсами.

Я использую spring-data-rest (наряду с spring-data-jpa конечно) для раскрытия сущностей / репозиториев с помощью Spring Magi c.

Несмотря на то, что я обеспечил (на основе ролей) конечные точки с помощью Spring-Security, это не полностью защищен.

Например: У меня есть User сущность с one-to-many отношениями с Car. Таким образом, конечная точка (автоматически выставляемая spring-data-rest) для получения машин пользователя - localhost: 8080 / users / {userId} / cars

Однако любой пользователь с необходимой ролью может просто передать userId другого пользователя и все равно получить доступ к конечной точке. Я хочу защитить эти конечные точки таким образом, чтобы, если я вошел в систему с идентификатором пользователя 1, тогда мы можем нажать только localhost: 8080 / users / 1 / cars . Любой другой запрос с любым другим userId должен заканчиваться 403 или чем-то еще.

Примечание: Я знаю, если напишу свои собственные контроллеры, тогда я смогу получить справиться с принципалом и делать то, что я хочу. Я просто хочу знать, есть ли способ или шаблон в spring-data-rest для достижения этого?

Ответы [ 3 ]

0 голосов
/ 11 января 2020

Вы используете spring security (отлично: D), поэтому лучше создать простой фильтр, зарегистрировать его, а затем просто выполнить пользовательскую авторизацию в этом фильтре.

Вкратце

  1. Создать пользовательский фильтр

    • Получить идентификатор пользователя из пути URL

    • Получение идентификатора пользователя из SecurityContextHolder (субъект аутентифицированного пользователя)

    • Сравнение выбранных идентификаторов пользователя

  2. Регистрация фильтра в конфигурации безопасности Spring (после BasicAuthenticationFilter)

1- Создание пользовательского фильтра (псевдокод)

public class CustomFilter extends GenericFilterBean {

@Override
public void doFilter(
        ServletRequest request,
        ServletResponse response,
        FilterChain chain) throws IOException, ServletException {

    //Fetch userId from path 
    HttpServletRequest req = (HttpServletRequest) request;
    String path = req.getContextPath();
    //..


    //Fetch userId from SecurityContextHolder (User Principal)
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    User user = (User) authentication.getPrincipal();
    Long userId = user.getId();


    //Compare userId (fethced from path) with authenticated userId (fetched from principal)
    //If comparison is ok
    chain.doFilter(request, response);


    //else
    //throw Unauthorize

}

2- Зарегистрируйте фильтр в конфигурации безопасности пружины (После BasicAuthenticationFilter.class)

@Configuration
public class Configuration extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.addFilterAfter(
            new CustomFilter(), BasicAuthenticationFilter.class);
}
}

С этой структурой, когда аутентифицированный пользователь отправляет запрос, запрос сначала проверяется (Сравнение идентификаторов пользователей), а затем отправляется.

Дополнительные сведения о создании фильтра в Spring Security:

Пользовательский фильтр в цепочке фильтров Spring Security

0 голосов
/ 12 января 2020

Поскольку вы уже защитили приложение с помощью Spring Security, вот еще один вариант с Выражениями безопасности метода

Пожалуйста, просмотрите аннотации @ Pre и @Post для Ваше требование.

  1. Вы можете сохранить идентификатор пользователя, вошедшего в систему, в объект аутентификации. Детали здесь .

  2. Защитите требуемый метод с помощью аннотации @PreAuthorize следующим образом

    @PreAuthorize("#user.userId == authentication.principal.userId")
    public List<Car> getCars(User user){..}
    

Не забудьте включить защиту метода

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {..}
0 голосов
/ 11 января 2020

Для этого вам нужно написать Interceptor. Он будет использоваться в следующих ситуациях:

  1. Перед отправкой запроса в контроллер

  2. Перед отправкой ответа клиенту

Перед написанием любого Interceptor он должен реализовать интерфейс HandlerInterceptor. Поддерживаются три метода Interceptor:

  1. preHandle() метод - выполнение операций перед отправкой запроса на controller. Этот метод должен возвращать true, чтобы вернуть ответ клиенту.
  2. postHandle() метод - используется для выполнения операций перед отправкой ответа клиенту.
  3. afterCompletion() метод - используется выполнять операции после завершения запроса и ответа.

Код:

    @Component
    public class MyInterceptor implements HandlerInterceptor {
       @Override
       public boolean preHandle(
          HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

       String pathVariablesMap = request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); 
      //From this pathVariablesMap  extract UserId and match with a loggedinUserId
       }
       @Override
       public void postHandle(
          HttpServletRequest request, HttpServletResponse response, Object handler, 
         ) throws Exception {}

       @Override
       public void afterCompletion(HttpServletRequest request, HttpServletResponse response, 
          Object handler, Exception exception) throws Exception {}
    }

Используя InterceptorRegistry, вы можете зарегистрировать Interceptors, как показано ниже:

@Component
public class MyRegistoryConfig extends WebMvcConfigurer{
   @Autowired
   MyInterceptor myInterceptor ;

   @Override
   public void addInterceptors(InterceptorRegistry registry) {
      registry.addInterceptor(myInterceptor );
   }
}

Для получения дополнительной информации перейдите по этой ссылке Перехватчики

РЕДАКТИРОВАТЬ: Как @ Rite sh предложил добавить эту точку.

...