Получение информации о пользователе - Spring Security в деталях

Зачастую при реализации какой-то функциональности в приложении требуется доступ к информации о текущем аутентифицированном пользователе. Spring Security предоставляет несколько способов получения информации о пользователе, предлагаю их рассмотреть в этой статье.

Видео с примерами способов получения информации об аутентифицированном пользователе

Универсальный способ

Универсальный для всех веб-приложений на основе Servlet API способ заключается в использовании метода HttpServletRequest.getUserPrincipal(). Данный метод возвращает экземпляр Principal, но в случае со Spring Security всегда будет возвращаться Authentication. Чтобы получить информацию о пользователе из Authentication достаточно вызвать метод getPrincipal() и привести результат к нужному типу.

В приложении на основе Spring Framework это всё будет выглядеть следующим образом:

class GreetingsRestController {

    String getGreetings(HttpServletRequest request) {
        // Получаем результат аутентификации
        var authentication = (Authentication) request.getUserPrincipal();
        // Получаем информацию о пользователе
        var userDetails = (UserDetails) authentication.getPrincipal();
        // Используем
        return "Hello %s!".formatted(userDetails.getUsername());
    }
}

Аналогичным способом можно получить доступ к информации о пользователе в функциональных обработчиках запросов:

class GetGreetingsHandlerFunction
    implements HandlerFunction<ServerResponse> {

    public ServerResponse handle(ServerRequest request) {
        // Получаем результат аутентификации
        var userDetails = request.getPrincipal()
            // Приводим к Authentication
            .map(Authentication.class::cast)
            // Получаем информацию о пользователе
            .map(Authentication::getPrincipal)
            // Приводим к UserDetails
            .map(UserDetails.class::cast)
            .orElseThrow();

        return ServerResponse.ok()
                .body("Hello %s!".formatted(userDetails.getUsername()));
    }
}

Использование контекста безопасности

Ничто не мешает вам в нужном классе обратиться к контексту безопасности. Сделать это можно как через стратегию, так и через класс SecurityContextHolder.

Использование стратегии:

class GreetingsRestController {

    SecurityContextHolderStrategy strategy =
            SecurityContextHolder.getContextHolderStrategy();

    String getGreetings() {
        // Получаем информацию о пользователе
        var userDetails = (UserDetails) this.strategy.getContext()
                .getAuthentication().getPrincipal();
        // Используем
        return "Hello %s!".formatted(userDetails.getUsername());
    }
}

Использование SecurityContextHolder:

class GreetingsRestController {

    String getGreetings() {
        // Получаем информацию о пользователе
        var userDetails = (UserDetails) SecurityContextHolder
                .getContext().getAuthentication().getPrincipal();
        // Используем
        return "Hello %s!".formatted(userDetails.getUsername());
    }
}

Интеграция со Spring Framework

В Spring Framework ожидаемо есть интеграция со Spring Security, благодаря чем информацию о пользователе можно получать в качестве аргументов методов аннотированных контроллеров.

Так любой метод аннотированного контроллера может получать в качестве одного из аргументов объект Principal:

class GreetingsRestController {

    String getGreetings(Principal principal) {
        // Получение результата аутентификации
        var authentication = (Authentication) principal;
        // Получаем информацию о пользователе
        var userDetails = (UserDetails) authentication.getPrincipal();
        // Используем
        return "Hello %s!".formatted(userDetails.getUsername());
    }
}

Но, поскольку при использовании Spring Security это всегда будет Authentication, можно получать аргумент этого типа:

class GreetingsRestController {

    String getGreetings(Authentication authentication) {
        // Получаем информацию о пользователе
        var userDetails = (UserDetails) authentication.getPrincipal();
        // Используем
        return "Hello %s!".formatted(userDetails.getUsername());
    }
}

Кроме этого Spring Framework позволяет получать в качестве одного из аргументов метода сразу информацию о пользователе, но этот аргумент должен быть отмечен аннотацией @AuthenticationPrincipal. В этом случае Spring Framework сам получит объект с информацией о пользователе из Authentication и попытается привести его к типу аргумента:

class GreetingsRestController {

    String getGreetings(@AuthenticationPrincipal UserDetails userDetails) {
        // Используем
        return "Hello %s!".formatted(userDetails.getUsername());
    }
}

Понравилась статья? Тогда поддержки проект и подкинь монетку:

Больше полезных статей и роликов:

44 views·3 shares