Настоящий бой! Spring Boot Security + вход в систему аутентификации с разделением внешней и внутренней архитектуры JWT, есть еще люди, которые этого не знают?
Настоящий бой! Spring Boot Security + вход в систему аутентификации с разделением внешней и внутренней архитектуры JWT, есть еще люди, которые этого не знают?

Идея разделения front-end и back-end аутентификации

Разделение клиентской и серверной части отличается от традиционных веб-сервисов, которые не могут использовать сеансы. Поэтому для генерации токенов мы используем механизм без сохранения состояния, такой как JWT. Общая идея заключается в следующем:

  1. Клиент вызывает интерфейс сервера Авторизоваться и вводит имя пользователя、пароль Авторизоваться,Авторизоваться Успешно возвращает дваtoken,следующее:
    1. accessToken:Клиент несет этоtokenДоступ к ресурсам сервера
    2. refreshToken:обновить токен,По истечении срока действия accessToken,Клиенту необходимо использоватьrefreToken, чтобы снова получить accessToken. Таким образом, срок действия RefreshToken обычно больше, чем у AccessToken.
  2. передается в заголовке запроса клиентаaccessTokenДоступ к ресурсам сервера,пара серверовaccessTokenПройти идентификацию(Проверка、Является ли оно недействительным….),Если этоaccessTokenЕсли нет проблем, отпусти ее.。
  3. accessTokenПосле истечения срока годности клиент должен иметь его с собой.refreshTokenвызовобновить токениз Интерфейс вновь получает новыйизaccessToken

Строительство проекта

Чен использует Spring Boot рамка,Демо-проект имеет два новых модуля,Они естьcommon-basesecurity-authentication-jwt

1. модуль общей базы

Это абстрактный общедоступный модуль. Этот модуль в основном содержит несколько общедоступных классов. Каталог выглядит следующим образом:

2. модуль безопасности-аутентификации-jwt

Некоторые классы, которые необходимо настроить, такие как класс глобальной конфигурации безопасности и класс конфигурации фильтра входа в систему Jwt, следующие:

3. Пять столов

Дизайн «Разрешения» часто имеет разные варианты дизайна в зависимости от потребностей бизнеса.,Используется ЧеномRBACспецификация,В основном включает в себя пять таблиц,Они естьПользовательская таблицалист персонажатаблица разрешенийпользователь<->лист персонажаРоль<->таблица разрешений,Как показано ниже:

SQL-код приведенных выше таблиц будет помещен в исходный код дела (поля этих таблиц не полностью предназначены для избежания хлопот, вы можете постепенно расширять их в соответствии с вашим бизнесом)

Фильтр аутентификации при входе

Существует множество способов написания логики интерфейса входа. Сегодня Чен представляет интерфейс входа, использующий определение фильтра.

Spring Securityформа по умолчанию Авторизоваться Сертифицированный фильтрUsernamePasswordAuthenticationFilter,Этот фильтр не применяется к Архитектуре по Разделению передней и задней части.,Итак, нам нужно настроить фильтр.

Логика очень проста,ссылкаUsernamePasswordAuthenticationFilterИзменить этот фильтр,Код выглядит следующим образом:

Обработчик успеха аутентификации

После успешной аутентификации вышеуказанного интерфейса фильтра,будет вызванAuthenticationSuccessHandlerПроцесс,Таким образом, мы можем настроить обработчик успешной аутентификации для выполнения нашей собственной бизнес-обработки.,Код выглядит следующим образом:

Чен только что вернулсяaccessTokenrefreshToken,Прочую обработку бизнес-логики можно улучшить самостоятельно.

Обработчик сбоя аутентификации

Такой же,один раз Авторизоватьсянеудача,Например, ошибки имени пользователя или пароля и т. д.,будет вызванAuthenticationFailureHandlerПроцесс,Поэтому нам нужно настроить процессор на случай сбоя аутентификации.,Возвращает определенное значение на основе информации об исключении.JSONДанные клиенту,Код выглядит следующим образом:

Логика очень проста,AuthenticationExceptionСуществуют разные классы реализации,Просто верните конкретную подсказку в соответствии с типом исключения.

Конфигурация аутентификацииEntryPoint

AuthenticationEntryPointЭтот интерфейс должен бытьПользователь не прошел аутентификацию для доступа к защищенным ресурсамчас,будет вызванcommence()метод Процесс,Например, токен, хранящийся у клиента, подделан.,Поэтому нам необходимо настроитьAuthenticationEntryPointВозврат конкретной подсказки,Код выглядит следующим образом:

AccessDeniedHandlerКонфигурация

AccessDeniedHandlerКогда этот процессор успешно аутентифицированизпользовательдоступзащищенныйизресурс,ноНедостаточно разрешений,войдет в этот процессор для обработки,Мы можем реализовать этот процессор для возврата клиенту конкретной оперативной информации.,Код выглядит следующим образом:

Конфигурация UserDetailsService

UserDetailsServiceЭтот класс используется для загрузкипользовательинформация,включатьимя пользователяпарольРазрешенияРольсобирать….Существует методследующее:

Язык кода:javascript
копировать
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;

В логике аутентификации Spring Security вызовет этот метод для загрузки подробной информации о пользователе на основе имени пользователя, переданного клиентом. Логика, которую необходимо выполнить с помощью этого метода, следующая:

  • пароль匹配
  • нагрузка Разрешения、Рольсобирать

Нам нужно реализовать этот интерфейс,отбаза данныхнагрузкапользовательинформация,Код выглядит следующим образом:

из которыхLoginServiceоснован наимя пользователяотбаза данных Запроситьпароль、Роль、Разрешения,Код выглядит следующим образом:

UserDetailsЭто тоже интерфейс,Определено несколько методов,все вокругимя пользователяпарольРазрешения+РольсобиратьЭти три свойства,Таким образом, мы можем реализовать расширение этих полей этого класса.,SecurityUserКод выглядит следующим образом:

расширятьUserDetailsServiceРеализация этого класса обычно включает в себя5Чжан Бяо,Они естьПользовательская таблицалист персонажатаблица разрешенийпользователь<->Роль Таблица соответствияРоль<->Разрешения Таблица соответствия,Внедрения на предприятии должны следоватьRBACправила дизайна。Чен подробно представит это правило позже.。

Фильтр проверки токена

Заголовок запроса клиента содержит токен, и сервер должен анализировать и проверять токен для каждого запроса, поэтому необходимо определить фильтр токенов. Основная логика этого фильтра следующая:

  • от Получено из заголовка запросаaccessToken
  • верноaccessTokenанализировать、Проверка、Проверьте срок годности
  • Если проверка прошла успешно, аутентификация будет сохранена в ThreadLocal, что облегчит последующее прямое получение данных пользователя.

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

Код для проверки фильтра выглядит следующим образом:

Обновить интерфейс токена

accessTokenодин раз Истекший,Клиент должен нестиrefreshTokenПолучить токен,Традиционные веб-сервисы размещаются в файлах cookie.,Только сервер должен завершить обновление,Совершенно неосведомленное обновление токена,но Разделение передней и задней части Архитектурадолжен находиться у клиентаrefreshTokenОбновление интерфейса вручную。

Код выглядит следующим образом:

Основная логика очень проста и заключается в следующем:

  • проверятьrefreshToken
  • РегенерироватьaccessTokenrefreshTokenВернуться к клиенту。

Уведомление:В реальном производствеrefreshTokenКак генерируются токены、шифрование Алгоритм можно комбинировать сaccessTokenдругой。

Фильтр аутентификации при входеинтерфейс Конфигурация

Вышеупомянутое определяет фильтр аутентификации.JwtAuthenticationLoginFilter,Это фильтр для Авторизоваться,ноне вводится вSpring В цепочке фильтров Безопасности необходимо определить конфигурацию, Код выглядит следующим образом:

Язык кода:javascript
копировать
/**
 * @author Публичный аккаунт: Колонка технологий Code Ape
 * Класс конфигурации для фильтра Авторизоваться
 */
@Configuration
public class JwtAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {

    /**
     * userDetailService
     */
    @Qualifier("jwtTokenUserDetailsService")
    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * Авторизоваться процессор успеха
     */
    @Autowired
    private LoginAuthenticationSuccessHandler loginAuthenticationSuccessHandler;

    /**
     * Авторизоваться обработчик ошибок
     */
    @Autowired
    private LoginAuthenticationFailureHandler loginAuthenticationFailureHandler;

    /**
     * шифрование
     */
    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * Настройте фильтр интерфейса Авторизоваться в цепочку фильтров.
     * 1. Настроить Авторизоваться обработчики успеха и неудачи
     * 2. Настройте пользовательский userDetailService (из базы Получить данные пользователя в data)
     * 3. Настройте пользовательские фильтры для весны В цепочке фильтров безопасности настройте его перед UsernamePasswordAuthenticationFilter.
     * @param http
     */
    @Override
    public void configure(HttpSecurity http) {
        JwtAuthenticationLoginFilter filter = new JwtAuthenticationLoginFilter();
        filter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
        //Обработчик успешной аутентификации
        filter.setAuthenticationSuccessHandler(loginAuthenticationSuccessHandler);
        //Обработчик ошибки аутентификации
        filter.setAuthenticationFailureHandler(loginAuthenticationFailureHandler);
        //Используем DaoAuthenticationProvider напрямую
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        //Устанавливаем userDetailService
        provider.setUserDetailsService(userDetailsService);
        //Устанавливаем алгоритм шифрования
        provider.setPasswordEncoder(passwordEncoder);
        http.authenticationProvider(provider);
        //Добавьте этот фильтр в UsernamePasswordAuthenticationFilter перед выполнением
        http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class);
    }
}

Вся логика естьpublic void configure(HttpSecurity http)В этом методе,следующее:

  • Установить обработчик успешной аутентификацииloginAuthenticationSuccessHandler
  • настраивать СертификациянеудачапроцессорloginAuthenticationFailureHandler
  • настраиватьuserDetailServiceкласс реализацииJwtTokenUserDetailsService
  • Установить алгоритм шифрования пароляEncoder
  • ВоляJwtAuthenticationLoginFilterЭтот фильтр добавляется в цепочку фильтров.,Присоединяйтесь напрямую кUsernamePasswordAuthenticationFilterдо этого фильтра。

Глобальная конфигурация Spring Security

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

  • Настройка применения фильтра Авторизоваться
  • Разрешить интерфейс Авторизации и интерфейс обновления токена без перехвата
  • КонфигурацияAuthenticationEntryPointAccessDeniedHandler
  • Запрещатьsession,Разделение передней и задней части+JWTМетод не обязателенsession
  • ВоляtokenпроверятьфильтрTokenAuthenticationFilterДобавить в цепочку фильтров,надеватьUsernamePasswordAuthenticationFilterДо。

Полная конфигурация выглядит следующим образом:

Язык кода:javascript
копировать
/**
 * @author Публичный аккаунт: Колонка технологий Code Ape
 * @EnableGlobalMethodSecurity Включите аннотацию для проверки Разрешения
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private JwtAuthenticationSecurityConfig jwtAuthenticationSecurityConfig;
    @Autowired
    private EntryPointUnauthorizedHandler entryPointUnauthorizedHandler;
    @Autowired
    private RequestAccessDeniedHandler requestAccessDeniedHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                //Запрещатьформа Авторизоваться,Разделение передней и задней часть бесполезна
                .disable()
                //Применяем настройку фильтра Авторизоваться, настраиваем разделение
                .apply(jwtAuthenticationSecurityConfig)

                .and()
                // Установить авторизацию для URL
                .authorizeRequests()
                // Здесь нужно разрешить странице Авторизоваться, PermitAll() означает отсутствие перехвата, /login Авторизоватьсяизurl,/refreshTokenобновитьtokenизurl                //TODO Здесь есть много URL-адресов, выпущенных в обычных проектах, таких как URL-адреса, связанные с чванством, URL-адреса серверной части друида и некоторые статические ресурсы.
                .antMatchers(   "/login","/refreshToken")
                .permitAll()
                //hasRole() указывает, что для доступа к ресурсу необходима указанная Роль
                .antMatchers("/hello").hasRole("ADMIN")
                // anyRequest() Все запросы   authenticated() должен быть аутентифицирован
                .anyRequest()
                .authenticated()

                //Обработка исключений: сбой аутентификации и недостаточное разрешение
                .and()
                .exceptionHandling()
                //Аутентификация не удалась, доступ к обработчику исключений запрещен
                .authenticationEntryPoint(entryPointUnauthorizedHandler)
                //Сертификация пройдена, но процессора Разрешения нет
                .accessDeniedHandler(requestAccessDeniedHandler)

                .and()
                //Отключаем сеанс, проверка JWT не требует сеанса
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)

                .and()
                //Настройте фильтр проверки TOKEN в цепочке фильтров, иначе он не вступит в силу и будет помещен перед UsernamePasswordAuthenticationFilter.
                .addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class)
                // закрыть csrf
                .csrf().disable();
    }

    // Пользовательский JWT Фильтр проверки токена
    @Bean
    public TokenAuthenticationFilter authenticationTokenFilterBean()  {
        return new TokenAuthenticationFilter();
    }

    /**
     * шифрованиеалгоритм
     * @return
     */
    @Bean
    public PasswordEncoder getPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

Аннотации очень подробные. Если вы не поняли, пожалуйста, прочтите внимательно.

Исходный код кейса загружен на GitHub, обратите внимание на Официальный аккаунт:Колонка технологий Code Ape,Ключевые слова ответа:9529 Возьми!

тест

1. Сначала тест Авторизовать интерфейс,postmanдоступhttp://localhost:2001/security-jwt/login следующим образом:

Как видите, два токена были успешно возвращены.

2. Заголовок запроса не содержит токена.,прямой запросhttp://localhost:2001/security-jwt/hello, следующим образом:

можно увидеть,Введено напрямуюEntryPointUnauthorizedHandlerэтот процессор。

3、нестиtokenдоступhttp://localhost:2001/security-jwt/hello, следующим образом:

После успешного доступа токен действителен.

4、Обновить интерфейс токенатест,нести一个Истекшийизжетондоступследующее:

5、Обновить интерфейс токенатест,Проведение токена с истекшим сроком действия,следующее:

Как видите, два новых токена были успешно возвращены.

Отслеживание исходного кода

Вышеупомянутая серияиз Конфигурация ПолностьюссылкаUsernamePasswordAuthenticationFilterэтот фильтр,Это способ формы веб-сервиса Авторизоваться.

Принцип Spring Security состоит из серии фильтров.,То же самое касается процесса Авторизации.,сначала вorg.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter#doFilter()метод,Выполнить сопоставление аутентификации,следующее:

attemptAuthentication()этотметод Основная функция – получение клиентской доставки.изusername、password,упакованный вUsernamePasswordAuthenticationTokenсдаватьProviderManagerиз进行Сертификация,Исходный кодследующее:

ProviderManagerОсновной процесс — вызов абстрактного классаAbstractUserDetailsAuthenticationProvider#authenticate()метод,Как показано ниже:

retrieveUser()метод就是вызовuserDetailServiceЗапроспользовательинформация。Затем аутентифицируйте,После успешной или неудачной аутентификации,Для обработки будут вызваны соответствующие обработчики ошибок и успехов.

Подвести итог

Хотя Spring Security относительно тяжелый, его действительно легко использовать, особенно реализацию спецификации Oauth2.0, которая очень проста и удобна.

Исходный код кейса загружен на GitHub, обратите внимание на Официальный аккаунт:Колонка технологий Code Ape,Ключевые слова ответа:9529 Возьми!

boy illustration
IDEA Maven может упаковать все импортное полностью красное решение — универсальное решение.
boy illustration
Последний выпуск 2023 года, самое полное руководство по обучению Spring Boot во всей сети (с интеллект-картой).
boy illustration
[Решено — Практическая работа] SaTokenException: запрос не может быть получен в контексте, отличном от Интернета. Решение проблем — Практическая работа.
boy illustration
HikariPool-1 - Connection is not available, request timed out after 30000ms
boy illustration
Power Query: автоматическое суммирование ежемесячных данных с обновлением одним щелчком мыши.
boy illustration
установка Ubuntu в среде npm
boy illustration
3 Бесплатные системы управления складом (WMS) .NET с открытым исходным кодом
boy illustration
Глубокое погружение в библиотеку Python Lassie: мощный инструмент для автоматизации извлечения метаданных
boy illustration
Объяснение прослушивателя серии Activiti7 последней версии 2023 года
boy illustration
API-интерфейс Jitu Express для электронных счетов-Express Bird [просто для понимания]
boy illustration
Каковы архитектуры микросервисов Java. Серверная часть плавающей области обслуживания
boy illustration
Описание трех режимов жизненного цикла службы внедрения зависимостей Asp.net Core.
boy illustration
Java реализует пользовательские аннотации для доступа к интерфейсу без проверки токена.
boy illustration
Серверная часть Unity добавляет поддержку .net 8. Я еще думал об этом два дня назад, и это сбылось.
boy illustration
Проект с открытым исходным кодом | Самый элегантный метод подписки на публичные аккаунты WeChat на данный момент
boy illustration
Разрешения роли пользователя Gitlab Гость, Репортер, Разработчик, Мастер, Владелец
boy illustration
Spring Security 6.x подробно объясняет механизм управления аутентификацией сеанса в этой статье.
boy illustration
[Основные знания ASP.NET] — Аутентификация и авторизация — Использование удостоверений для аутентификации.
boy illustration
Соединение JDBC с базой данных MySQL в jsp [легко понять]
boy illustration
[Уровень няни] Полный процесс развертывания проекта Python (веб-страницы Flask) в Docker.
boy illustration
6 способов чтения файлов свойств, рекомендуем собрать!
boy illustration
Графическое объяснение этапа строительства проекта IDEA 2021 Spring Cloud (базовая версия)
boy illustration
Подробное объяснение технологии междоменного запроса данных JSONP.
boy illustration
Учебное пособие по SpringBoot (14) | SpringBoot интегрирует Redis (наиболее полный во всей сети)
boy illustration
Подробное объяснение механизма подтверждения выпуска сообщений RabbitMQ.
boy illustration
На этот раз полностью поймите протокол ZooKeeper.
boy illustration
Реализуйте загрузку файлов с использованием минимального WEB API.
boy illustration
Демо1 Laravel5.2 — генерация и хранение URL-адресов
boy illustration
Spring boot интегрирует Kafka и реализует отправку и потребление информации (действительно при личном тестировании)
boy illustration
Мысли о решениях по внутренней реализации сортировки методом перетаскивания