предисловие
Мотивация для написания этой серии статей — продвигать и использовать Spring Security в китайском кругу. Поскольку Spring Security имеет отношение почти ко всем приложениям Spring, мы будем использовать Spring Security в качестве первой темы нашего руководства для первой части. В то же время мы также подготовили 10-минутные видео-объяснения каждое, надеясь компенсировать проблемы, причиненные читателям, используя только слова и изображения для описания технических знаний.
Наконец, во время написания этой серии мы использовали Spring Boot версии 1.5; Security версии 5. Если вы не можете работать нормально и получить ожидаемые результаты из-за различий в версиях, вы можете оставить отзыв через комментарии и личные сообщения. Благодарю.
Проблема 1. Быстрое добавление Spring Security в приложения Spring Boot
Список дел по этому вопросу
- Быстрая инициализация проекта Spring Boot
- Как добавить аутентификацию пользователя на основе памяти
- Как добавить логику управления доступом на основе ролей
1. Быстро инициализировать проект Spring Boot
Мы рекомендуем новичкам использовать инструмент инициализации проекта, официально предоставленный Spring, для их создания, если они не знакомы с написанием Maven pom.xml и различными зависимостями Spring Starter.start.spring.io/Наша цель — инициализировать веб-приложение на основе SpringBoot и включить компоненты, связанные с безопасностью. Поэтому в зависимой компонентной части веб-интерфейса инструмента вам необходимо по очереди ввести и выбрать три компонентные зависимости Web, Security и Thymeleaf. После нажатия кнопки «Создать» браузер автоматически загрузит архив проекта проекта.
После распаковки кода и его импорта через IDEA вы получите базовое приложение SpringBoot, которое уже включает Security. Запустите DemoApplication.java.После того, как приложение будет запущено на консоли, войдите в порт 127.0.0.1:8080 машины через браузер.Если вы видите диалоговое окно входа в систему, которое предлагает вам ввести имя пользователя и пароль, это означает, что Безопасность успешно загружена в приложение.
2. Добавьте функцию аутентификации пользователя на основе памяти
Различие между аутентификацией и контролем доступа
Наша вторая задача — настроить инфраструктуру безопасности, чтобы она могла правильно получать информацию о пользователе для проверки входа. Мы решили написать эту конфигурацию через класс JavaConfig, мы назвали имя класса WebSecurityConfig и ввели следующий код.
@EnableWebSecurity //配置注解
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//注入新的UserDetailsServiceBean
@Bean
public UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("user").password("password").roles("USER").build());
return manager;
}
}
Основная работа, которую мы делаем в коде, заключается в том, чтобы внедритьс компонент. Так что же
Шерстяная ткань?
UserDetailsService и UserDetails
UserDetails — это первая важная концепция, которую мы коснемся. С точки зрения Spring Security UserDetails похож на концепцию пользователей и учетных записей для нашей собственной системы дизайна. Он содержит имя пользователя, пароль и соответствующие предоставленные разрешения.
public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}
UserDetailsService — это служба, позволяющая получить информацию о пользователях инвентаризации в текущей системе.
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}}
Здесь мы можем просто подумать, что после того, как мы введем имя пользователя и пароль, фреймворк будет использовать класс реализации UserDetailsService, чтобы найти и проверить, верны ли имя пользователя и пароль, введенные во внешнем интерфейсе пользователя, и если они верны , вернитесь в UserDetails, чтобы завершить операцию входа. Режим безопасности предоставляет множество способов реализации служб управления пользовательской информацией, таких как базы данных и LDAP. В настоящее время мы используем InMemoryUserDetailsManager, простейшую реализацию управления пользователями на основе памяти.
@Bean
public UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("user").password("password").roles("USER").build());
return manager;
}
Если вы используете Spring Security 5, строка в части пароля будет
.password("{noop}password"). В противном случае может быть сгенерировано исключение.
После перезапуска приложения и повторного посещения тестового приложения по адресу http://127.0.0.1:8080/ после ввода имени пользователя и пароля появится сообщение об ошибке 404 о том, что страница, к которой обращается цель, не существует. Это как минимум доказывает, что логика входа выполнена, а вторую задачу можно выполнить, просто написав позже простой контроллер и шаблон страницы. Код контроллера MainController
@Controller
public class MainController {
@RequestMapping("/")
public String root() {
return "index";
}
Код шаблона страницы index.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
<title>Hello Spring</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
</head>
<body>
<h1>Hello Spring</h1>
</body>
</html>
После входа в систему вы можете увидеть страницу приветствия, которую мы ожидаем.
3. Как добавить логику управления доступом на основе ролей
Всего лишь заданием мы выполнили функцию аутентификации одной из двух основных забот Spring Security, и теперь приступаем к реализации простейшей логики управления доступом. Для начала сделаем простой дизайн для цели текущей задачи: Мы напишем две страницы пути в MainController: путь "", который не требует контроля доступа, и путь "\user", требующий контроля входа.
контроллер записи
Сначала дорабатываем код MainContoller согласно дизайну, добавляем новый url и соответствующий шаблон представления. user.html сначала напрямую скопируйте index.html, просто измените содержимое на «Добро пожаловать, пользователь».MainController .java
@Controller
public class MainController {
@RequestMapping("/")
public String root() {
return "index";
}
@RequestMapping("/user")
public String userIndex() {
return "user";
}
}
user.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
<title>Welcome User</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
</head>
<body>
<h1>Welcome User</h1>
</body>
</html>
Написать конфигурацию контроля доступа
Наш класс конфигурации WebSecurityConfig предоставляется инфраструктурой наследования., который имеет важную схему конфигурации, обращаем внимание на реализацию значения по умолчанию, предоставляемую фреймворком:
protected void configure(HttpSecurity http) throws Exception {
logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().and()
.httpBasic();
}
Этот фрагмент кода в основном отвечает за нашу конфигурацию HttpSecurity.Есть три основных момента:
- Управление доступом к путям в authorizeRequests();
- formLogin() управляет конфигурацией формы входа;
- Основан ли httpBasic() на конфигурации аутентификации Http. Последние два пункта не являются нашей целью, наша цель — настроить контроль доступа к пути, поэтому нам нужно переопределить этот метод в нашем собственном классе конфигурации:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
// inde.html对应的url允许所任人访问
.antMatchers("/").permitAll()
// user.html对应的url,则需要用户有USER的角色才可以访问
.antMatchers("/user").hasRole("USER")
.and()
.formLogin();
}
Мы использовали условие аутентификации на основе ролей hasRole(), позвольте мне просмотреть, какой код записи пользователя мы добавили в раздел аутентификации пользователя ранее?Добавленный нами пользователь user также содержит роль USER, и во время контроля доступа проверит, соответствует ли информация об авторизации роли. Доступно, если вы используете Spring Security 4 или ниже.
manager.createUser(User.withUsername("user").password("password").roles("USER").build());
Если вы используете версию выше 5, поскольку Spring Security может выполнять правильные операции шифрования паролей только путем настройки PasswordEncoderUser.withDefaultPasswordEncoder(), иначе фреймворк может сообщить об ошибке.
manager.createUser(
User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build());
User.withDefaultPasswordEncoder() — это метод, который можно использовать только в примере приложения, поскольку механизм генерации компонентов был скорректирован в Spring Security 5. Использование предыдущего кода для генерации информации о пользователе делает невозможным определение того, какой PasswordEncoder использовать. Конкретные детали будут объяснены в отдельной теме позже. Спасибо, Chaoge, за вопрос об отзыве о строке.
Перезапустите приложение, сначала введите /path, приложение не предлагает нам никакого диалога входа в систему, мы видим заголовок Hello Spring.
Затем мы снова вводим путь \user, поскольку контроль доступа проверяет, что мы не завершили операцию входа в систему, мы перенаправляемся на страницу входа для завершения операции входа. Наконец, когда мы закончили с именем пользователя и вводом, мы можем получить доступ к целевой/пользовательской странице, потому что роли пользователей настроены, как и ожидалось.
конец
В этом выпуске мы сделали простейшую реализацию и настройку двух важнейших функций Spring Security: аутентификации пользователей и контроля доступа. В следующем выпуске мы объясним конкретный процесс части аутентификации пользователя. Увидимся в следующий раз.