Поддержка аудита аутентификации Spring Boot
1. обзор
В этой короткой статье мы рассмотрим модуль Spring Boot Actuator и поддержку публикации событий аутентификации и авторизации в сочетании с Spring Security.
2. Maven Зависимости
Во-первых, нам нужно добавитьspring-boot-starter-actuator к нашемуpom.xml:
org.springframework.boot
spring-boot-starter-actuator
2.1.7.RELEASE
Последняя версия доступна в репозиторииMaven Central.
3. Прослушивание событий аутентификации и авторизации
Чтобы регистрировать все попытки аутентификации и авторизации в приложении Spring Boot, мы можем просто определить компонент с помощью метода слушателя:
@Component
public class LoginAttemptsLogger {
@EventListener
public void auditEventHappened(
AuditApplicationEvent auditApplicationEvent) {
AuditEvent auditEvent = auditApplicationEvent.getAuditEvent();
System.out.println("Principal " + auditEvent.getPrincipal()
+ " - " + auditEvent.getType());
WebAuthenticationDetails details =
(WebAuthenticationDetails) auditEvent.getData().get("details");
System.out.println("Remote IP address: "
+ details.getRemoteAddress());
System.out.println(" Session Id: " + details.getSessionId());
}
}
Обратите внимание, что мы просто выводим некоторые вещи, доступные вAuditApplicationEvent, чтобы показать, какая информация доступна. В реальном приложении вы можете сохранить эту информацию в репозитории или кеше для дальнейшей обработки.
Обратите внимание, что любой Spring bean будет работать; Основы поддержки нового события Spring довольно просты:
-
аннотируйте метод@EventListener
-
добавьтеAuditApplicationEvent как единственный аргумент метода
Результат запуска приложения будет выглядеть примерно так:
Principal anonymousUser - AUTHORIZATION_FAILURE Remote IP address: 0:0:0:0:0:0:0:1 Session Id: null Principal user - AUTHENTICATION_FAILURE Remote IP address: 0:0:0:0:0:0:0:1 Session Id: BD41692232875A5A65C5E35E63D784F6 Principal user - AUTHENTICATION_SUCCESS Remote IP address: 0:0:0:0:0:0:0:1 Session Id: BD41692232875A5A65C5E35E63D784F6
В этом примере слушателем были получены триAuditApplicationEvents:
-
Без входа в систему был запрошен доступ к закрытой странице
-
При входе в систему использовался неверный пароль
-
Правильный пароль был использован во второй раз
4. Слушатель аудита аутентификации
Если информации, предоставляемой Spring BootAuthorizationAuditListener, недостаточно, вы можетеcreate your own bean to expose more information.
Давайте посмотрим на пример, где мы также показываем URL-адрес запроса, к которому обращались, когда авторизация не удалась:
@Component
public class ExposeAttemptedPathAuthorizationAuditListener
extends AbstractAuthorizationAuditListener {
public static final String AUTHORIZATION_FAILURE
= "AUTHORIZATION_FAILURE";
@Override
public void onApplicationEvent(AbstractAuthorizationEvent event) {
if (event instanceof AuthorizationFailureEvent) {
onAuthorizationFailureEvent((AuthorizationFailureEvent) event);
}
}
private void onAuthorizationFailureEvent(
AuthorizationFailureEvent event) {
Map data = new HashMap<>();
data.put(
"type", event.getAccessDeniedException().getClass().getName());
data.put("message", event.getAccessDeniedException().getMessage());
data.put(
"requestUrl", ((FilterInvocation)event.getSource()).getRequestUrl() );
if (event.getAuthentication().getDetails() != null) {
data.put("details",
event.getAuthentication().getDetails());
}
publish(new AuditEvent(event.getAuthentication().getName(),
AUTHORIZATION_FAILURE, data));
}
}
Теперь мы можем войти в URL запроса в нашем слушателе:
@Component
public class LoginAttemptsLogger {
@EventListener
public void auditEventHappened(
AuditApplicationEvent auditApplicationEvent) {
AuditEvent auditEvent = auditApplicationEvent.getAuditEvent();
System.out.println("Principal " + auditEvent.getPrincipal()
+ " - " + auditEvent.getType());
WebAuthenticationDetails details
= (WebAuthenticationDetails) auditEvent.getData().get("details");
System.out.println(" Remote IP address: "
+ details.getRemoteAddress());
System.out.println(" Session Id: " + details.getSessionId());
System.out.println(" Request URL: "
+ auditEvent.getData().get("requestUrl"));
}
}
В результате вывод теперь содержит запрошенный URL:
Principal anonymousUser - AUTHORIZATION_FAILURE Remote IP address: 0:0:0:0:0:0:0:1 Session Id: null Request URL: /hello
Обратите внимание, что в этом примере мы расширили абстрактныйAbstractAuthorizationAuditListener, поэтому мы можем использовать методpublish из этого базового класса в нашей реализации.
Если вы хотите проверить это, проверьте исходный код и запустите:
mvn clean spring-boot:run
После этого вы можете указать в своем браузереhttp://localhost:8080/
.
5. Хранение событий аудита
По умолчанию Spring Boot хранит события аудита вAuditEventRepository. Если вы не создаете bean-компонент с собственной реализацией, то для вас будет подключенInMemoryAuditEventRepository.
InMemoryAuditEventRepository - это своего рода кольцевой буфер, который хранит в памяти последние 4000 событий аудита. Затем к этим событиям можно будет получить доступ через конечную точку управленияhttp://localhost:8080/auditevents
.
Это возвращает JSON-представление событий аудита:
{
"events": [
{
"timestamp": "2017-03-09T19:21:59+0000",
"principal": "anonymousUser",
"type": "AUTHORIZATION_FAILURE",
"data": {
"requestUrl": "/auditevents",
"details": {
"remoteAddress": "0:0:0:0:0:0:0:1",
"sessionId": null
},
"type": "org.springframework.security.access.AccessDeniedException",
"message": "Access is denied"
}
},
{
"timestamp": "2017-03-09T19:22:00+0000",
"principal": "anonymousUser",
"type": "AUTHORIZATION_FAILURE",
"data": {
"requestUrl": "/favicon.ico",
"details": {
"remoteAddress": "0:0:0:0:0:0:0:1",
"sessionId": "18FA15865F80760521BBB736D3036901"
},
"type": "org.springframework.security.access.AccessDeniedException",
"message": "Access is denied"
}
},
{
"timestamp": "2017-03-09T19:22:03+0000",
"principal": "user",
"type": "AUTHENTICATION_SUCCESS",
"data": {
"details": {
"remoteAddress": "0:0:0:0:0:0:0:1",
"sessionId": "18FA15865F80760521BBB736D3036901"
}
}
}
]
}
6. Заключение
С поддержкой исполнительных механизмов в Spring Boot становится легко регистрировать попытки аутентификации и авторизации от пользователей. Читателю также предлагается обратиться кproduction ready auditing за дополнительной информацией.
Код из этой статьи можно найтиover on GitHub.