Spring Security в сочетании с репозиториями Spring для защиты и аутентификации различных частей веб-сайта.
Я искал конкретный, серьезный и полный пример того, как использовать безопасность Spring в приложении Spring Boot, которое использует хранилища данных Spring для доступа к базе данных и, следовательно, для запросов о зарегистрированных пользователях.
Я видел, что он легко защищает ряд веб-страниц с помощью Spring Spring, переопределяя configure
метод, например, со следующими параметрами:
http.authorizeRequests()
.antMatchers("/", "/css/**", "/js/**", "/vendor/**", "/templates/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
Этот код защищает пользователей, например, от доступа http://localhost:3000/home/users/
, но позволяет затем получить доступ http://localhost:3000/login
или просто http://localhost:3000
,
Я много читал о безопасности Spring, но не могу понять, как я могу защитить различные части приложения, например, когда пользователь зашел на сайт и запретил ему доступ из примера http://localhost:3000/home/users/another_user
и вообще контролировать доступ зарегистрированного пользователя ко всем частям сайта.
Я использую репозитории данных Spring, чтобы манипулировать данными базы данных через сущности.
Знаете ли вы о примере, который использует безопасность Spring в сочетании с репозиториями Spring (и, при необходимости, другими инструментами) для защиты (и аутентификации) различных частей веб-сайта? (Видео) учебник также может быть полезным.
Спасибо за любую помощь.
Примечание: я посмотрел на репозиторий саганского сайта, но довольно сложно понять, что происходит...
2 ответа
Как отмечалось выше, ACL являются одним из вариантов, однако альтернативным и, возможно, более простым решением может быть применение защиты на уровне метода.
Смотрите раздел 15.3.
https://docs.spring.io/spring-security/site/docs/3.0.x/reference/el-access.html
Итак, предположим, что у вас есть URL /users/123, где 123 - текущий пользователь, и который делегирует методу сервисного уровня для загрузки пользователя, тогда как я могу предотвратить вмешательство пользователя в URL и просмотр данных, возвращаемых, например, /users/456?,
Один из подходов заключается в применении безопасности на уровне метода с помощью аннотации @PostAuthorize:
@PostAuthorize("hasPermission(returnObject, null)")
public User findById(Long id) {
return repository.findOne(id);
}
Проверки безопасности делегируются реализации org.springframework.security.access.PermissionEvaluator.
Реализация может выглядеть следующим образом:
public class BasePermissionsEvaluator implements PermissionEvaluator {
public boolean hasPermission(Authentication authentication, Object domainObject) {
return hasPermission(authentication, domainObject, null);
}
@Override
public boolean hasPermission(Authentication authentication, Object domainObject, Object permission) {
boolean hasPermission = true;
//User is my custom class representing a logged in user
//UserEntity is my custom interface implemented by entities associated with specific user
//If user is an Admin allow access
//Otherwise allow access if logged in user 'owns' the DomainObject instance
User user = (User) authentication.getPrincipal();
if(! user.isAdmin()){
if (domainObject instanceof UserEntity) {
User owner = ((UserEntity) domainObject).getOwner();
hasPermission = user.equals(owner);
}
}
return hasPermission;
}
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType,
Object permission) {
return false;
}
}
Конфигурация PermissionEvaluator выглядит следующим образом в XML, поэтому вам необходимо преобразовать ее в конфигурацию Java:
<security:global-method-security
pre-post-annotations="enabled">
<security:expression-handler ref="expressionHandler"/>
</security:global-method-security>
<bean id="expressionHandler"
class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<property name="permissionEvaluator" ref="permissionEvaluator" />
</bean>
<bean id="permissionEvaluator" class="com.mycompany.BasePermissionsEvaluator" />
Ниже приведены схемы преобразования конфигурации XML в конфигурацию Java:
https://spring.io/blog/2013/07/04/spring-security-java-config-preview-method-security/
Таким образом, в вашем существующем классе конфигурации безопасности вы должны добавить:
@EnableGlobalMethodSecurity(prePostEnabled=true) //ADD THIS
public class MySecurityConfig{
@Override
protected MethodSecurityExpressionHandler expressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
//SET TO OUR CUSTOM PERMISSIONS HANDLER DETAILED ABOVE
expressionHandler.setPermissionEvaluator(new BasePermissionsEvaluator());
return expressionHandler;
}
}
Это называется Контроль доступа или "Безопасность объекта домена" в Spring Security.
http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/
Вам нужно много читать!
Возможно, вы захотите объединить его с Spring Data JPA, чтобы SDJ возвращал только те записи, которые он должен. Пример здесь:
https://github.com/spring-projects/spring-data-examples/tree/master/jpa/security
По сути, вы будете добавлять в таблицы некоторую информацию о владельце строк и заставлять SDJ и SS работать вместе для контроля доступа, например:
@Query("select o from BusinessObject o where o.owner.emailAddress like ?#{hasRole('ROLE_ADMIN') ? '%' : principal.emailAddress}")
List<BusinessObject> findBusinessObjectsForCurrentUser();
Альтернативный вариант - использовать сервер базы данных, который поддерживает Row Security, такой как PostgreSQL, и обрабатывать управление доступом прямо в БД.