Во-первых, я должен сказать, что уроки, которые Сон Гэ недавно написал, все в серии, и писать некоторые повторяющиеся вещи скучно, поэтому в каждой статье предполагается, что все поняли предыдущее содержание, поэтому ниже есть любые вопросы. не понимаю, я предлагаю вам сначала прочитать соответствующую серию:
Весенняя серия безопасности:
- Выкопайте большую яму и позвольте Spring Security сделать это!
- Song Ge поможет вам начать работу с Spring Security, не спрашивайте, как снова расшифровать пароль.
- Научите, как настроить вход в форму в Spring Security
- Spring Security разделяет внешний и внутренний интерфейсы, давайте не будем переходить по страницам! Все взаимодействия JSON
- Операции авторизации в Spring Security оказались такими простыми
- Как Spring Security хранит пользовательские данные в базе данных?
- Spring Security+Spring Data Jpa объединяют усилия, управление безопасностью становится еще проще!
Серия OAuth2:
- Чтобы сделать OAuth2, который нельзя обойти микросервисами, Сонг Гэ также пришел поговорить с вами об этом.
- Этот случай написан, и вы боитесь, что не сможете понять процесс входа в систему OAuth2 с интервьюером?
- Я умираю от OAuth2, я хочу изучить полный набор тренеров!
- Можно ли хранить токены OAuth2 в Redis? Играйте больше и больше!
- Хотите весело провести время, играя вместе с OAuth2 и JWT? Пожалуйста, посмотрите выступление Сон Гэ
- Поделитесь с вами некоторыми идеями по управлению безопасностью в микросервисной архитектуре.
Хорошо, давайте начнем сегодняшний текст.
Единый вход — это обычное требование в распределенных системах.
Распределенная система состоит из множества разных подсистем, и когда мы используем систему, нам нужно войти в систему только один раз, чтобы другие системы думали, что пользователь уже вошел в систему, и нет необходимости входить снова. Ранее я поделился с друзьями методом входа в систему OAuth2+JWT. Этот вход без сохранения состояния фактически соответствует потребностям единого входа. Вы можете обратиться к:Хотите весело провести время, играя вместе с OAuth2 и JWT? Пожалуйста, посмотрите выступление Сон Гэ.
Конечно, все знают, что вход без сохранения состояния имеет и недостатки.
Итак, сегодня Сонг Гэ хочет поговорить с вами о Spring Boot+OAuth2 для единого входа и использовать аннотацию @EnableOAuth2Sso для быстрой реализации функции единого входа.
Сонг Гэ по-прежнему рекомендует при чтении этой статьи сначала прочитать предыдущие статьи из этой серии, которые помогут вам лучше понять эту статью.
1. Создание проекта
В предыдущем случае Сонг Гэ всегда создавал сервер авторизации и сервер ресурсов отдельно, а в сегодняшнем случае, чтобы избежать проблем, я создал сервер авторизации и сервер ресурсов вместе (но я считаю, что после прочтения предыдущей статьи, вы должны быть в состоянии сделать это самостоятельно. разделить два сервера).
Итак, сегодня нам нужны всего три сервиса:
проект | порт | описывать |
---|---|---|
auth-server | 1111 | Сервер авторизации + сервер ресурсов |
client1 | 1112 | Подсистема 1 |
client2 | 1113 | Подсистема 2 |
auth-server используется для игры в роли сервера авторизации + сервера ресурсов, а client1 и client2 играют роль подсистемы соответственно.В будущем, после того, как client1 успешно войдет в систему, мы также сможем получить доступ к client2, так что мы можем увидеть эффект единого входа.
Мы можем создать проект Maven с именем oauth2-sso в качестве родительского проекта.
2. Единый удостоверяющий центр
Далее построим единый удостоверяющий центр.
Сначала мы создаем модуль с именем auth-server и при создании добавляем следующие зависимости:
После того, как проект будет успешно создан, этот модуль будет играть роль сервера авторизации + сервера ресурсов, поэтому мы сначала добавляем в класс запуска этого проекта аннотацию @EnableResourceServer, указывающую, что это сервер ресурсов:
@SpringBootApplication
@EnableResourceServer
public class AuthServerApplication {
public static void main(String[] args) {
SpringApplication.run(AuthServerApplication.class, args);
}
}
Далее настраиваем сервер авторизации.Поскольку сервер ресурсов и сервер авторизации объединены воедино, настройка сервера авторизации избавит от многих хлопот:
@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
PasswordEncoder passwordEncoder;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("javaboy")
.secret(passwordEncoder.encode("123"))
.autoApprove(true)
.redirectUris("http://localhost:1112/login", "http://localhost:1113/login")
.scopes("user")
.accessTokenValiditySeconds(7200)
.authorizedGrantTypes("authorization_code");
}
}
Здесь нам нужно только просто настроить информацию клиента.Настройка здесь очень проста.В предыдущих статьях тоже об этом говорилось.Если вы не поняли,то можете обратиться к предыдущим статьям из этой серии:Этот случай написан, и вы боитесь, что не сможете понять процесс входа в систему OAuth2 с интервьюером?.
Конечно, для простоты информационная конфигурация клиента основана на памяти.Если вы хотите хранить информацию о клиенте в базе данных, это также возможно.Можно ли хранить токены OAuth2 в Redis? Играйте больше и больше!
Далее настроим Spring Security:
@Configuration
@Order(1)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/login.html", "/css/**", "/js/**", "/images/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/login")
.antMatchers("/oauth/authorize")
.and()
.authorizeRequests().anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/login")
.permitAll()
.and()
.csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("sang")
.password(passwordEncoder().encode("123"))
.roles("admin");
}
}
Что касается конфигурации Spring Security, если вы этого не понимаете, вы можете взглянуть на серию Spring Security, которую Song Ge недавно сериализует.
Я дам грубый обзор здесь:
- Сначала предоставьте экземпляр BCryptPasswordEncoder для шифрования и расшифровки пароля.
- Поскольку я настроил страницу входа, эти статические ресурсы в WebSecurity возложены на квадрат.
- В HttpSecurity мы выпускаем конечные точки, связанные с аутентификацией, и одновременно настраиваем страницу входа и интерфейс входа.
- В AuthenticationManagerBuilder предусмотрен пользователь на основе памяти (его можно настроить на загрузку из базы данных согласно седьмой статье серии Spring Security).
- Есть еще один ключевой момент, поскольку сервер ресурсов и сервер авторизации находятся вместе, поэтому нам нужна аннотация @Order для повышения приоритета конфигурации Spring Security.
И SecurityConfig, и AuthServerConfig — это вещи, которые должен предоставить сервер авторизации (если вы хотите разделить сервер авторизации и сервер ресурсов, обратите внимание на это предложение), затем нам также необходимо предоставить интерфейс, который предоставляет информацию о пользователе (если сервер авторизации и сервер ресурсов разделены, обратите внимание на это предложение) Сервер и сервер ресурсов разделены, этот интерфейс будет предоставлен сервером ресурсов):
@RestController
public class UserController {
@GetMapping("/user")
public Principal getCurrentUser(Principal principal) {
return principal;
}
}
Наконец, мы настраиваем порт проекта в application.properties:
server.port=1111
Кроме того, сам Сон Гэ заранее подготовил страницу входа в систему следующим образом:
Скопируйте html, css, js и т. д., относящиеся к странице входа, в каталог resources/static:
Эта страница очень проста, просто форма входа, я перечисляю основные части:
<form action="/login" method="post">
<div class="input">
<label for="name">用户名</label>
<input type="text" name="username" id="name">
<span class="spin"></span>
</div>
<div class="input">
<label for="pass">密码</label>
<input type="password" name="password" id="pass">
<span class="spin"></span>
</div>
<div class="button login">
<button type="submit">
<span>登录</span>
<i class="fa fa-check"></i>
</button>
</div>
</form>
Обратите внимание, что адрес отправки действия не является неправильным.
Исходный код можно скачать в конце статьи.
После этого наша унифицированная платформа входа в систему аутентификации в порядке.
3. Создание клиента
Затем давайте создадим клиентский проект, создадим проект Spring Boot с именем client1 и добавим следующие зависимости:
После успешного создания проекта давайте настроим Spring Security:
@Configuration
@EnableOAuth2Sso
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().csrf().disable();
}
}
Эта конфигурация очень проста, то есть все интерфейсы в нашем client1 должны быть аутентифицированы, прежде чем к ним можно будет получить доступ, и добавлена аннотация @EnableOAuth2Sso для включения функции единого входа.
Далее мы предоставляем тестовый интерфейс в client1:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return authentication.getName() + Arrays.toString(authentication.getAuthorities().toArray());
}
}
Этот тестовый интерфейс возвращает информацию об имени и роли текущего пользователя, вошедшего в систему.
Далее нам нужно настроить информацию, связанную с oauth2, в application.properties client1:
security.oauth2.client.client-secret=123
security.oauth2.client.client-id=javaboy
security.oauth2.client.user-authorization-uri=http://localhost:1111/oauth/authorize
security.oauth2.client.access-token-uri=http://localhost:1111/oauth/token
security.oauth2.resource.user-info-uri=http://localhost:1111/user
server.port=1112
server.servlet.session.cookie.name=s1
Конфигурация тут тоже знакомая, давайте посмотрим:
- client-secret — это секрет клиента.
- client-id — это идентификатор клиента.
- user-authorization-uri — это конечная точка авторизации пользователя.
- access-token-uri — это конечная точка для получения токена.
- user-info-uri — это интерфейс для получения информации о пользователе (полученной с сервера ресурсов).
- Наконец, настройте порт и дайте файлу cookie имя.
После этого наш client1 даже настроен.
Таким же образом снова настроим клиент 2. Клиент 2 и клиент 1 точно такие же, то есть имена куки разные (их можно выбрать по желанию, они могут быть разными).
4. Тест
Далее запускаем auth-server, client1 и client2 соответственно.Сначала пытаемся зайти на hello интерфейс в client1.В это время он автоматически перейдет к единому центру аутентификации:
Затем введите имя пользователя и пароль для входа.
После успешного входа он автоматически вернется к приветственному интерфейсу client1 следующим образом:
В этот момент мы снова заходим в client2 и обнаруживаем, что нам не нужно входить в систему, мы можем получить к нему прямой доступ:
Хорошо, после этого наш единый вход прошел успешно.
5. Анализ процесса
Наконец, позвольте мне и моим друзьям взглянуть на процесс выполнения приведенного выше кода:
- Сначала мы переходим на интерфейс /hello клиента1, но доступ к этому интерфейсу возможен только при входе в систему, поэтому наш запрос перехватывается, после перехвата система перенаправляет нас на интерфейс /login клиента1, что позволяет нам войти Войти.
- Когда мы обращаемся к интерфейсу входа в систему client1, поскольку мы настроили аннотацию @EnableOAuth2Sso, эта операция будет снова перехвачена, и перехватчик единого входа автоматически инициирует запрос на получение кода авторизации в соответствии с нашей конфигурацией в application.properties:
- Запрос, отправленный на втором этапе, — это запрос чего-либо на службе auth-server.Конечно, этот запрос не может избежать необходимости сначала войти в систему, поэтому он перенаправляется на страницу входа в систему auth-server, которая является унифицированной центр аутентификации, который видят все.
- В едином серьезном центре мы выполнили функцию входа в систему.После завершения входа в систему мы продолжим выполнение запроса на втором этапе.На данный момент мы можем успешно получить код авторизации.
- После получения кода авторизации он будет перенаправлен на страницу входа нашего клиента1 в это время, но на самом деле у нашего клиента1 нет страницы входа, поэтому эта операция все равно будет перехвачена.В это время перехваченный адрес содержит код авторизации.С кодом авторизации сделайте запрос к auth-серверу в классе OAuth2ClientAuthenticationProcessingFilter, и вы сможете получить access_token (см.:Этот случай написан, и вы боитесь, что не сможете понять процесс входа в систему OAuth2 с интервьюером?).
- После получения access_token на пятом шаге отправьте запрос на адрес user-info-uri, который мы настроили для получения информации о пользователе для входа, и после получения информации о пользователе снова выполните процесс входа в Spring Security на client1, который OK.
Хорошо, в этой статье говорилось о некоторых проблемах с единым входом SpringBoot + OAuth2 с моими друзьями Полный адрес загрузки случая:GitHub.com/Len VE/OAuth…
Если ваши друзья сочтут это полезным, не забудьте нажать и поддержать Songge.