Запрос режима пароля/разбор oauth/токена для Spring Security Oauth2

Spring

предисловие

Текст был включен в мой репозиторий GitHUB, приветствую звезду: https: //github.com/bin392328206/six-finger
Лучшее время посадить дерево было десять лет назад, затем сейчас

болтовня

Я просто наткнулся на это, давайте разбираться в процессе.

Объем процесса сертификации, описанный в этом документе

В этой статье в основном описываются несколько ключевых моментов, которые проходят от запроса пользователя на получение токена (/oauth/token) до завершения запроса и возврата токена.

Связанные запросы, которые будут использоваться для аутентификации

Access_token Запрос на приобретение (/ OAuth / Token)

  • Параметры, необходимые для запроса: client_id, client_secret, grant_type, имя пользователя, пароль
http://localhost/oauth/token?client_id=demoClientId&client_secret=demoClientSecret&grant_type=password&username=demoUser&password=50575tyL86xp29O380t1

Проверьте, действителен ли заголовок для запроса (/oauth/check_token)

  • Требуемые параметры запроса: токен
http://localhost/oauth/check_token?token=f57ce129-2d4d-4bd7-1111-f31ccc69d4d1

Обновить запрос токена (/oauth/token)

Параметры, необходимые для запроса: grant_type, refresh_token, client_id, client_secret Где grant_type — это фиксированное значение: grant_type=refresh_token

http://localhost/oauth/token?grant_type=refresh_token&refresh_token=fbde81ee-f419-42b1-1234-9191f1f95be9&client_id=demoClientId&client_secret=demoClientSecret

Принцип работы

Обзор структуры

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

При инициализации Spring Security будет создан фильтр сервлета с именем SpringSecurityFilterChain, тип org.springframework.security.web.FilterChainProxy, который реализует javax.servlet.Filter, поэтому внешние запросы будут проходить через этот класс, следующий рисунок — Spring Схема структуры цепочки фильтров безопасности:

FilterChainProxy – это прокси. Что действительно работает, так это то, что каждый фильтр, содержащийся в SecurityFilterChain в FilterChainProxy. В то же время Spring управляет этими фильтрами как bean-компонентами. Они являются ядром Spring Security и имеют свои собственные обязанности, но напрямую не обрабатывают аутентификация пользователя. Он не обрабатывает авторизацию пользователей напрямую, а передает их для обработки AuthenticationManager и AccessDecisionManager. На следующем рисунке представлена ​​UML-диаграмма классов, связанных с FilterChainProxy.

Реализация функции пружинной безопасности в основном завершается серией цепочек фильтров, которые взаимодействуют друг с другом.

Далее представлены основные фильтры в цепочке фильтров и их функции.

  • SecurityContextPersistenceFilter Этот фильтр является входом и выходом всего процесса перехвата (т. е. первого и последнего перехватчика).Он получит SecurityContext из настроенного SecurityContextRepository в начале запроса, а затем установит его в SecurityContextHolder. После завершения запроса сохраните SecurityContext, хранящийся в SecurityContextHolder, в настроенном SecurityContextRepository, и очистите SecurityContext, хранящийся в securityContextHolder;
  • USERNAMESPASSWARDWORDAUTHENTALTIVELTER для обработки из представления формы аутентификации. Форма должна обеспечить соответствующее имя пользователя и пароль, а также его внутренний успех входа в систему или отказ лечения и для аутентификации аутентификации аутентификацииUCCESCHENCHANDLER, которые могут быть изменены в соответствии с соответствующими требованиями;
  • FilterseSurityivereCeptor используется для защиты веб-ресурсов, с использованием AccessDecisionManager текущий пользователь авторизован для доступа к передней поверхности подробно описана;
  • ExceptionTranslationFilter может перехватывать все исключения из FilterChain и обрабатывать их. Но он обрабатывает только два типа исключений: AuthenticationException и AccessDeniedException, другие исключения он будет продолжать генерировать.

Процесс сертификации

Рассмотрим подробнее процесс сертификации:

    1. Имя пользователя и пароль, отправленные пользователем, получаются фильтром UsernamePasswordAuthenticationFilter в SecurityFilterChain и инкапсулируются как аутентификация запроса, обычно класс реализации UsernamePasswordAuthenticationToken.
    1. Затем фильтр отправляет аутентификацию диспетчеру аутентификации для аутентификации.
    1. После успешной аутентификации Identity Identity Authenticanager возвращает экземпляр аутентификации, который заполнен информацией (включая вышеупомянутую информацию о разрешении, информацию, данные, детали, но пароль обычно удаляется).
    1. Контейнер контекста безопасности SecurityContextHolder заполняет аутентификацию информацией на шаге 3 и устанавливает ее с помощью метода SecurityContextHolder.getContext().setAuthentication(…). Можно видеть, что интерфейс AuthenticationManager (менеджер аутентификации) является основным интерфейсом, связанным с аутентификацией, и отправной точкой для инициирования аутентификации.Его класс реализации — ProviderManager. Spring Security поддерживает различные методы аутентификации, поэтому ProviderManager поддерживает список List, в котором хранятся различные методы аутентификации, а фактическая работа по аутентификации выполняется AuthenticationProvider. Мы знаем, что соответствующим классом реализации AuthenticationProvider веб-формы является DaoAuthenticationProvider, который внутренне поддерживает службу UserDetailsService, отвечающую за получение UserDetails. Наконец, AuthenticationProvider заполняет UserDetails для проверки подлинности. Общая взаимосвязь основных компонентов аутентификации выглядит следующим образом:

AuthenticationProvider

Из предыдущего процесса аутентификации Spring Security мы знаем, что диспетчер аутентификации (AuthenticationManager) поручает AuthenticationProvider завершить работу по аутентификации. AuthenticationProvider — это интерфейс, определенный следующим образом

  public interface AuthenticationProvider { Authentication authenticate(Authentication authentication) throws AuthenticationException; boolean supports(Class<?> var1); }

Метод authentication() определяет процесс реализации аутентификации, его параметром является Authentication, который содержит имя пользователя и пароль, предоставленные вошедшим в систему пользователем. Возвращаемое значение также является аутентификацией, которая генерируется путем повторной сборки разрешений пользователя и другой информации после успешной аутентификации.

Список поддерживается в Spring Security, в котором хранятся несколько методов аутентификации, а разные методы аутентификации используют разные AuthenticationProviders. Существует много примеров, таких как использование AuthenticationProvider1 при входе в систему с именем пользователя и паролем и использование AuthenticationProvider2 при входе через SMS.

Каждый AuthenticationProvider должен реализовать метод supports() для указания поддерживаемых им методов аутентификации.Например, если мы используем аутентификацию формы, Spring Security будет генерировать UsernamePasswordAuthenticationToken при отправке запроса, который представляет собой аутентификацию, которая инкапсулирует отправленную информацию об имени пользователя и пароле. пользователем. . И соответственно, какой AuthenticationProvider его обрабатывает?

Мы нашли следующий код в базовом классе AbstractUserDetailsAuthenticationProvider DaoAuthenticationProvider:

public boolean supports(Class<?> authentication) { return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); }

То есть, когда веб-форма отправляет имя пользователя и пароль, Spring Security обрабатывается DaoAuthenticationProvider.

Наконец, давайте взглянем на структуру Authentication (информация об аутентификации), которая является интерфейсом, и UsernamePasswordAuthenticationToken, о котором мы упоминали ранее, является одной из его реализаций:

  public interface Authentication extends Principal, Serializable { (1) Collection<? extends GrantedAuthority> getAuthorities(); (2) Object getCredentials(); (3) Object getDetails(); (4) Object getPrincipal(); (5) boolean isAuthenticated(); void setAuthenticated(boolean var1) throws IllegalArgumentException; }
  • (1) Аутентификация — это интерфейс в пакете безопасности spring, напрямую унаследованный от класса Principal, который находится в пакете java.security. Он представляет собой абстрактный идентификатор субъекта, любой субъект имеет имя и, следовательно, содержит метод getName().

  • (2) getAuthorities(), список информации о полномочиях, по умолчанию это некоторые классы реализации интерфейса GrantedAuthority, обычно ряд строк, представляющих информацию о полномочиях.

  • (3) getCredentials(), учетная информация и строка пароля, введенная пользователем, обычно удаляются после аутентификации для обеспечения безопасности.

  • (4) getDetails(), подробная информация, интерфейс реализации в веб-приложениях обычно WebAuthenticationDetails, который записывает IP-адрес посетителя и значение sessionId.

  • (5) getPrincipal(), идентификационная информация. В большинстве случаев она возвращает класс реализации интерфейса UserDetails. UserDetails представляет подробную информацию о пользователе. UserDetails, извлеченные из Authentication, представляют собой текущую информацию о пользователе для входа в систему, которая также обычно используется в фреймворк, один из интерфейсов.

UserDetailsService

Понимание UserDetailsService

Теперь мы знаем, что DaoAuthenticationProvider обрабатывает логику аутентификации веб-формы.После успешной аутентификации получается Authentication (реализация UsernamePasswordAuthenticationToken), которая содержит идентификационную информацию (Principal). Эта идентификационная информация представляет собой Object , который в большинстве случаев может быть приведен к объекту UserDetails.

DaoAuthenticationProvider содержит экземпляр UserDetailsService, который отвечает за извлечение сведений о пользователе UserDetails (включая пароль) в соответствии с именем пользователя, а затем DaoAuthenticationProvider сравнивает, соответствует ли пароль пользователя, извлеченный UserDetailsService, паролю, предоставленному пользователем в качестве ключевой основы для успешного Пользовательская служба UserDetailsService, представленная как Spring bean для определения пользовательской аутентификации.

public interface UserDetailsService { UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; }

Многие путают обязанности DaoAuthenticationProvider и UserDetailsService, на самом деле UserDetailsService отвечает только за загрузку информации о пользователе из определенного места (обычно из базы данных), вот и все. DaoAuthenticationProvider несет большую ответственность, он завершает весь процесс аутентификации и в то же время заполняет UserDetails для аутентификации.

Выше было упомянуто, что UserDetails — это информация о пользователе, давайте посмотрим на ее истинные цвета:

public interface UserDetails extends Serializable { Collection<? extends GrantedAuthority> getAuthorities(); String getPassword(); String getUsername(); boolean isAccountNonExpired(); boolean isAccountNonLocked(); boolean isCredentialsNonExpired(); boolean isEnabled(); }

Он очень похож на интерфейс аутентификации, например, у них обоих есть имя пользователя и полномочия. Методы getCredentials() в Authentication и getPassword() в UserDetails должны обрабатываться по-разному. Первый — это учетные данные пароля, предоставленные пользователем, а второй — пароль, фактически сохраненный пользователем. Аутентификация — это фактически сравнение двух методов. getAuthorities() в Authentication фактически формируется путем передачи getAuthorities() из UserDetails. Помните метод getDetails() в интерфейсе аутентификации? Сведения о пользователе UserDetails заполняются после аутентификации AuthenticationProvider.

Внедрив UserDetailsService и UserDetails, мы можем завершить расширение методов сбора информации о пользователе и полей информации о пользователе.

InMemoryUserDetailsManager (аутентификация памяти) и JdbcUserDetailsManager (аутентификация jdbc), предоставляемые Spring Security, являются классами реализации UserDetailsService, Основное отличие состоит не более чем в загрузке пользователей из памяти или из базы данных.

Основной процесс получения токена

  • Пользователь инициирует запрос на получение токена.
  • Фильтр проверит, является ли путь аутентифицированным запросом /oauth/token, и если он окажется ложным, он вернется напрямую без последующих операций.
  • Фильтр создает объект аутентификации, запрашивая clientId.
  • Объект userdetails затем генерирует имя пользователя и объекты, создаваемые аутентификацией, и проверяет, присутствует ли пользователь.
  • Все вышеперечисленное вступит в адрес / Оат / токен, метод PostaccessToken в токенэнденде.
  • Scope проверяется в методе postAccessToken, а затем проверяется, является ли это запросом refreshToken и т. д.
  • Затем вызовите метод предоставления в AbstractTokenGranter.
  • В методе предоставления вызывается метод аутентификации класса AbstractUserDetailsAuthenticationProvider, чтобы узнать, существует ли пользователь с помощью объектов имени пользователя и аутентификации.
  • Затем получите объект OAuth2AccessToken из tokenStore через класс DefaultTokenServices.
  • Затем оберните объект OAuth2AccessToken в поток ответов и верните его.

Процесс сортировки скриншотов кода

  • Анализ учетных данных клиента, формат значения — Basic space + client_id: значение client_secret, зашифрованное с помощью Base64.
  • ①Более важный фильтр

  • ②Вот способ проверки подлинности в ①

  • ③Вот метод аутентификации, вызываемый в ②
  • ④ Вот метод аутентификации класса AbstractUserDetailsAuthenticationProvider, вызванный в ③

  • ⑤ Вот метод retrieveUser класса DaoAuthenticationProvider, вызванный в ④

  • ⑥ere - это метод LoadUserbyUsername для класса ClientDetailsUserDetailssservice вызывается в ⑤. После выполнения он возвращается для выполнения метода после ④

  • ⑦Вот дополнительный метод AuthenticationChecks класса DaoAuthenticationProvider, вызываемый в ④.После выполнения здесь выполняется основной фильтр, а метод сопоставления /oauth/token будет введен позже.

  • ⑧Введите здесь метод postAccessToken класса TokenEndpoint, сопоставленный с /oauth/token.

  • ⑨ Вот метод предоставления класса AbstractTokenGranter, вызванный в ⑧
  • ⑩Вот метод getOAuth2Authentication в классе ResourceOwnerPasswordTokenGranter, вызываемый в ⑨

Я воспроизвел его сам

  • ⑩① Вот метод аутентификации в пользовательском классе CustomUserAuthenticationProvider, вызванный в ⑩, здесь нужно проверить правильность пароля пользователя, после выполнения здесь вернитесь к ⑨ для выполнения последующего метода.
  • ⑩② Вот метод createAccessToken в DefaultTokenServices, вызываемый в ⑨
  • ⑩③Это метод getAccessToken в RedisTokenStore, вызываемый в 12. После выполнения здесь он всегда будет возвращаться к ⑧ для выполнения последующих методов.
  • ⑩④Вот операция обратного потока, которую необходимо упаковать после получения токена в ⑧

ежедневные комплименты

Хорошо всем, вышеизложенное является полным содержанием этой статьи. Люди, которые могут видеть это здесь, всенастоящий порошок.

Творить нелегко. Ваша поддержка и признание — самая большая мотивация для моего творчества. Увидимся в следующей статье.

Six Meridians Excalibur | Text [Original] Если в этом блоге есть какие-то ошибки, прошу покритиковать и посоветовать, буду очень признателен!