«1. Обзор

Spring Security обрабатывает для нас получение и анализ учетных данных для аутентификации.

В этом кратком руководстве мы рассмотрим, как получить информацию о SecurityContext из запроса в коде нашего обработчика.

2. Аннотация @CurrentSecurityContext

Мы могли бы использовать шаблонный код для чтения контекста безопасности:

SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();

Однако теперь есть аннотация @CurrentSecurityContext, которая поможет нам.

Кроме того, использование аннотаций делает код более декларативным и позволяет внедрять объект аутентификации. С помощью @CurrentSecurityContext мы также можем получить доступ к основной реализации текущего пользователя.

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

3. Зависимости Maven

Если у нас последняя версия Spring Boot, нам нужно только включить зависимость для spring-boot-starter-security:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

В противном случае мы можем обновить spring- security-core до минимальной версии 5.2.1.RELEASE:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-core</artifactId>
    <version>5.2.1.RELEASE</version>
</dependency>

4. Реализация с @CurrentSecurityContext

Мы можем использовать SpEL (язык выражений Spring) с @CurrentSecurityContext для внедрения объекта аутентификации или принципала. SpEL работает вместе с поиском типа. Проверка типа не применяется по умолчанию, но мы можем включить ее с помощью параметра errorOnInvalidType аннотации @CurrentSecurityContext.

4.1. Получение объекта аутентификации

Давайте прочитаем объект аутентификации, чтобы мы могли вернуть его детали:

@GetMapping("/authentication")
public Object getAuthentication(@CurrentSecurityContext(expression = "authentication") 
  Authentication authentication) {
    return authentication.getDetails();
}

Обратите внимание, что выражение SpEL относится к самому объекту аутентификации.

Давайте проверим это:

@Test
public void givenOAuth2Context_whenAccessingAuthentication_ThenRespondTokenDetails() {
    ClientCredentialsResourceDetails resourceDetails = 
      getClientCredentialsResourceDetails("baeldung", singletonList("read"));
    OAuth2RestTemplate restTemplate = getOAuth2RestTemplate(resourceDetails);

    String authentication = executeGetRequest(restTemplate, "/authentication");

    Pattern pattern = Pattern.compile("\\{\"remoteAddress\":\".*"
      + "\",\"sessionId\":null,\"tokenValue\":\".*"
      + "\",\"tokenType\":\"Bearer\",\"decodedDetails\":null}");
    assertTrue("authentication", pattern.matcher(authentication).matches());
}

Следует отметить, что в этом примере мы получаем все детали нашего соединения. Поскольку наш тестовый код не может предсказать значение remoteAddress или tokenValue, мы используем регулярное выражение для проверки полученного JSON.

4.2. Получение Принципала

Если нам нужен только Принципал из наших данных аутентификации, мы можем изменить выражение SpEL и внедряемый объект:

@GetMapping("/principal")
public String getPrincipal(@CurrentSecurityContext(expression = "authentication.principal") 
  Principal principal) { 
    return principal.getName(); 
}

В этом случае мы возвращаем только имя Принципала, используя метод getName .

Давайте проверим это:

@Test
public void givenOAuth2Context_whenAccessingPrincipal_ThenRespondBaeldung() {
    ClientCredentialsResourceDetails resourceDetails = 
       getClientCredentialsResourceDetails("baeldung", singletonList("read"));
    OAuth2RestTemplate restTemplate = getOAuth2RestTemplate(resourceDetails);

    String principal = executeGetRequest(restTemplate, "/principal");

    assertEquals("baeldung", principal);
}

Здесь мы видим, что имя baeldung, которое было добавлено к учетным данным клиента, было найдено и возвращено внутри объекта Principal, внедренного в обработчик.

5. Заключение

В этой статье мы увидели, как получить доступ к свойствам в текущем контексте безопасности и внедрить их в параметры наших методов-обработчиков.

Мы сделали это, воспользовавшись SpEL и аннотацией @CurrentSecurityContext.

Как всегда, полный исходный код примеров доступен на GitHub.