2015-11-25 2 views
6

Я использую Spring Data Rest для публикации репозитория. Я использую @PreAuthorize и @PostFilter, чтобы ограничить доступ к конечным точкам REST исключительно пользователям-администраторам и фильтровать результаты.Обеспечение исключительно доступа REST к хранилищу данных Spring Data

@PreAuthorize("hasRole('ROLE_ADMIN')") 
@PostFilter("hasPermission(filterObject, 'read') 
public interface SomeRepository extends CrudRepository<SomeEntity, Long> { 
} 

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

@Controller 
public class SomeController { 

@Autowired 
SomeRepository repository; 

@RequestMapping(value = "/test") 
public ResponseEntity test() { 
// Do something 
repository.findAll(); 
// Do something else 
} 
} 

Это не работает, так как пользователь, отправить запрос на «/ тест» не админ, так что не имеет доступа к хранилищу.

Вопрос в том, можно ли добавить защиту исключительно в REST-интерфейс репозитория, а не когда репозиторий используется внутри приложения?

Thanks

ответ

0

Несомненно. Просто измените расположение аннотации @PreAuthorize. Эта аннотация может быть помещена в классы или отдельные методы.

Например

@Controller 
public class SomeController { 

@Autowired 
SomeRepository repository; 

@RequestMapping(value = "/test") 
@PreAuthorize(....) 
public ResponseEntity test() { 
// Do something 
repository.findAll(); 
// Do something else 
} 
} 

вполне законны (обратите внимание на аннотацию на метод test().

+0

Хранилища конечные точки разоблачают автоматически Spring Data Rest, они не имеют какой-либо контроллер, куда поместить аннотацию. Это решение будет работать для моих пользовательских контроллеров, и я уже использую его. Проблема связана с конечной точкой, открытой хранилищем. Как ограничить эти конечные точки, не ограничивая доступ к репозиторию из других классов. Спасибо – Gerardo

+0

@ Gerardo ok, теперь у меня есть ваш вопрос. Извините, я пропустил эту фундаментальную деталь :-) Честно говоря, никогда не использовал Spring Data Rest самостоятельно. Я считаю, что обработчики событий Spring Data REST сделаны для вашей цели. Посмотрите здесь https://jaxenter.com/rest-api-spring-java-8-112289.html –

2

Одно решение было бы удалить @PreAuthorize аннотацию из вашего хранилища интерфейса, и в классе конфигурации, продолжите WebSecurityConfigAdaptor и переопределите метод configure(HttpSecurity security). Здесь вы можете использовать AntMatcher s для ограничения доступа к конечным точкам REST, например:

protected void configure(HttpSecurity http) throws Exception { 
    http.authorizeRequests().antMatchers("/someEntities/**").hasRole('ADMIN') 
    .anyRequest().permitAll(); 
} 

Для получения более подробной информации см. http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#jc-httpsecurity.

+0

Спасибо adam, это правильное решение для использования '@ PreAuthorize', но я смотрел, есть ли что-то еще потому что я использую '@ PostFilter'. Я обновлю свой вопрос – Gerardo

1

Я столкнулся с той же проблемой и придумал обходной путь, который не чувствует себя совершенно правильно, но делает свою работу на данный момент.

В основном я создал компонент utils для обеспечения безопасности, который можно использовать для проверки того, был ли метод вызван внутренне или внешне с использованием API данных Spring Data REST (замечание: мои репозитории имеют префикс /api/, если у вас есть другой префикс, вам нужно изменить regex соответственно).

@Component("securityUtils") 
public class SecurityUtils { 
    public boolean isRestRequest(){ 
     HttpServletRequest r = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); 
     return Pattern.matches("^/api/", UrlUtils.buildRequestUrl(r)); 
    } 
} 

Чтобы сделать эту работу, вам необходимо добавить следующую строку своим слушателям в Интернете.XML:

<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> 

И использовать этот метод в вашем выражении контроля доступа на основе типа так (где последняя строка в выражении позволяет использовать метод save от любых методов контроллера, которые сопоставляются с URL-адресами, которые не начинаются с /api/:

@Override 
@PreAuthorize("hasRole('ROLE_ADMINISTRATOR') " + 
     "or hasPermission(#user, 'WRITE') " + 
     "or [email protected]()") 
<S extends User> S save(@P("user") S user); 

Предостережения:

  1. вы не можете использовать это, если вы хотите, чтобы выставить пользовательские функции над /api маршрут, как это только простая проверка регулярных выражений против маршрута
  2. Проверка должна быть явно добавлена ​​к каждому хранилище или метод хранилища, для которого вы хотите пропустить проверку полномочий внутри (может быть преимуществом, а)
1

На мой взгляд, правильным решением было бы иметь два репозитория, один из которых называется EntityRepository и один SecuredEntityRepository.

Пример:

@RestResource(exported = false) 
public abstract interface CustomerRepository extends JpaRepository<Customer, Long> { 

} 

и обеспеченному версия:

@RestResource(exported = true) 
public abstract interface SecuredCustomerRepository extends CustomerRepository { 

    @Override 
    @PreAuthorize("#id == principal.customer.id or hasAuthority('ADMIN_CUSTOMER_ONE')") 
    public Customer findOne(@Param("id") Long id); 

    @Override 
    @Query("SELECT o FROM #{#entityName} o WHERE o.id = ?#{principal.customer.id} or 1 = ?#{ hasAuthority('ADMIN_CUSTOMER_LIST') ? 1 : 0 }") 
    public Page<Customer> findAll(Pageable pageable); 

    @Override 
    @SuppressWarnings("unchecked") 
    @PreAuthorize("#customer.id == principal.customer.id or hasAuthority('ADMIN_CUSTOMER_SAVE')") 
    public Customer save(@P("customer") Customer customer); 

    @Override 
    @PreAuthorize("hasAuthority('ADMIN_CUSTOMER_DELETE')") 
    public void delete(@Param("id") Long id); 

    @Override 
    @PreAuthorize("hasAuthority('ADMIN_CUSTOMER_DELETE')") 
    public void delete(Customer customer); 

} 

Это в настоящее время не представляется возможным из-за проблем с механизмом автоматического подключения в SD ОСТАЛЬНЫХ: https://jira.spring.io/browse/DATAREST-923

3

Пожалуйста оценить эти возможности:

  • проверки безопасности в REST обработчиков событий
  • Добавление пользовательских методов хранилища для внутреннего использования
  • Использование RunAsManager (временно или переключение SecurityContext для выполнения привилегированной операции)

Защита модифицирующих запросов с помощью обработчиков событий REST:

@Service 
@RepositoryEventHandler 
public class FooService { 

    /** 
    * Handles before-* events. 
    */ 
    @HandleBeforeCreate 
    @HandleBeforeSave 
    @HandleBeforeDelete 
    @HandleBeforeLinkSave 
    @HandleBeforeLinkDelete 
    @PreAuthorize("hasRole('ADMIN')") 
    public void onBeforeModify(final Foo entity){ 
    // noop 
    } 

} 

Защита стандартных методов CRUD при добавлении незащищенных пользовательские методы на хранилище для внутреннего использования:

public interface FooDao extends CrudRepository<Foo, Long> { 

@Override 
@PreAuthorize("hasRole('ADMIN')") 
<S extends Foo> S save(final S entity); 

    /** 
    * Saves entity without security checks. 
    */ 
    @Transactional 
    @Modifying 
    default <S extends Foo> S saveInternal(final S entity) { 
    return save(entity); 
    } 
} 
Смежные вопросы