Статьи

Что такое SecurityContext и SecurityContextHolder в Spring Security?

SecurityContext и SecurityContextHolder являются двумя основными классами Spring Security. SecurityContext используется для хранения сведений о текущем аутентифицированном пользователе, также известном как принцип. Итак, если вам нужно получить имя пользователя или любые другие данные пользователя, вам нужно сначала получить этот SecurityContext . SecurityContextHolder является вспомогательным классом, который обеспечивает доступ к контексту безопасности. По умолчанию он использует объект ThreadLocal для хранения контекста безопасности, что означает, что контекст безопасности всегда доступен для методов в одном и том же потоке выполнения, даже если вы не передаете объект SecurityContext. Не беспокойтесь об утечке памяти ThreadLocal в веб-приложении, хотя Spring Security позаботится об очистке ThreadLocal.

Кстати, это не единственный способ, когда SecurityContextHolder может хранить текущий SecurityContext , его можно настроить с помощью стратегии при запуске, чтобы указать, каким образом вы хотите сохранить контекст. Например, вы можете использовать стратегию SecurityContextHolder.MODE_GLOBAL для автономного приложения.

Ключевым моментом, который необходимо изучить, является то, как вы получаете SecurityContext из SecurityContextHolder? а затем получить данные текущего пользователя из этого? Например, если вы хотите знать имя текущего пользователя, вошедшего в систему, то как вы получите его в Spring security?

Чтобы получить текущее имя пользователя, вам сначала необходим SecurityContext , полученный из SecurityContextHolder . Этот SecurityContext хранит данные пользователя в объекте аутентификации, который можно получить, вызвав getAuthentication() .

Как только вы получили объект аутентификации, вы можете либо привести его к UserDetails, либо использовать его как есть. Объект UserDetails используется Spring Security для хранения информации, связанной с пользователем.

Как получить текущий логин в Spring Security

Вот код для получения контекста безопасности в Spring Security и получения имени текущего пользователя, вошедшего в систему:

1
2
3
4
5
6
7
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
 
if (principal instanceof UserDetails) {
  String username = ((UserDetails)principal).getUsername();
} else {
  String username = principal.toString();
}

Объект, возвращаемый getContext() является экземпляром интерфейса SecurityContext . Это объект, который хранится в локальном потоке.

Метод getPrincipal() обычно возвращает объект UserDetails в Spring Security, который содержит все детали текущего пользователя, вошедшего в систему.

В любом случае, если вы посмотрите ближе, вы обнаружите, что это не очень хороший код, когда мы думаем о Spring и внедрении зависимостей . Поэтому, если вам когда-либо понадобится узнать текущие данные пользователя, вошедшего в систему, например, в контроллере Spring MVC, я предлагаю вам объявить зависимость и позволить Spring предоставить вам объект Principal , а не запрашивать их и создавать тесно связанную систему.

Вот пример этого

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
import java.security.Principal;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
 
@Controller
public class MVCController {
 
  @RequestMapping(value = "/username", method = RequestMethod.GET)
  @ResponseBody
  public String currentUserName(Principal principal) {
     return principal.getName();
  }
 
}

Кроме того, вы также можете запросить объект аутентификации вместо основного объекта, как показано ниже:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
 
@Controller
public class SpringMVCController {
 
  @RequestMapping(value = "/username", method = RequestMethod.GET)
  @ResponseBody
  public String currentUserName(Authentication authentication) {
     return authentication.getName();
  }
}

Если вы хотите узнать больше способов, вы также можете увидеть мой пост о трех способах получения текущего имени пользователя в Spring Security , где я рассмотрел еще несколько способов получения текущего имени пользователя в контроллере Spring MVC.

Это все о том, что такое контекст безопасности в безопасности Spring и как вы можете получить SecurityContext из класса SecurityContextHolder. Это некоторые из основных классов, поэтому вы должны быть знакомы с ними.

Часть хранения, т.е. SecurityContext хранится в ThreadLocal является необязательной, но также полезно знать подробности. Просто помните, что если вам когда-либо понадобятся данные пользователя, например, имя пользователя и т. Д., Вам лучше запросить принципал или объект аутентификации в контроллере Spring MVC, а не использовать SecurityContextHolder для их получения.

Спасибо за чтение этой статьи до сих пор. Если вам нравится этот учебник Spring Security, поделитесь им с друзьями и коллегами. Если у вас есть какие-либо вопросы или пожелания, напишите нам.

См. Оригинальную статью здесь: Что такое SecurityContext и SecurityContextHolder в Spring Security?

Мнения, высказанные участниками Java Code Geeks, являются их собственными.