Каталог статей
1. Авторизация
Так называемая авторизация означает, что если пользователь хочет получить доступ к определенному ресурсу, мы должны проверить, есть ли у пользователя такое разрешение, если оно есть, то ему разрешен доступ, если нет, то он не разрешен.
Во-вторых, подготовьтесь к тестированию пользователей.
Поскольку мы еще не подключились к базе данных, тестовый пользователь все еще настраивается на основе памяти.
Основываясь на тестах конфигурации памяти, у нас есть два метода, первый из которых - метод конфигурации, который мы использовали в предыдущих статьях этой серии, а именно:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在内存中进行配置
auth.inMemoryAuthentication()
.withUser("yolo")
.password("123").roles("admin")
.and()
.withUser("nlcs")
.password("123")
.roles("user");
}
Это метод настройки.
Поскольку Spring Security поддерживает множество источников данных, таких как память, базы данных, LDAP и т. Д., Эти различные источники данных инкапсулируются в общий UserDetailService
интерфейс, любой объект, реализующий этот интерфейс, может использоваться в качестве источника данных аутентификации.
Таким образом , мы можем переписать WebSecurityConfigurerAdapter
в userDetailsService
обеспечении способа для UserDetailService
примера дополнительно выполнен с множеством пользователей:
@Override
@Bean
protected UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("yolo").password("123").roles("admin").build());
manager.createUser(User.withUsername("nlcs").password("123").roles("user").build());
return manager;
}
В-третьих, подготовьтесь к тестированию интерфейса.
Тестовый пользователь готов, а затем мы готовим три тестовых интерфейса. следующим образом:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
@GetMapping("/admin/hello")
public String admin() {
return "admin";
}
@GetMapping("/user/hello")
public String user() {
return "user";
}
}
Для этих трех тестовых интерфейсов наш план такой:
(1) Это
/hello
интерфейс, к которому может получить доступ любой
(2) Это/admin/hello
интерфейс, к которому может получить доступ только человек с идентификационной информацией администратора
(3)/user/hello
Интерфейс, к которому может получить доступ лицо с идентификационной информацией пользователя
(4) Все пользователи могут получить доступ к ресурсам, администратор может доступ
Обратите внимание, что четвертая спецификация означает, что все люди с идентификатором администратора автоматически получают идентификатор пользователя.
Четыре, конфигурация
Затем мы настраиваем разрешения правил блокировки, в configure(HttpSecurity http)
методе Spring Security код выглядит следующим образом:
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasRole("user")
.anyRequest().authenticated()
.and()
...
...
Для правил сопоставления здесь мы используем символы сопоставления путей в стиле Ant. Символы сопоставления путей в стиле Ant широко используются в семействе Spring, и их правила сопоставления также очень просты:
Смысл приведенной выше конфигурации:
(1) Если запрос соответствует
/admin/**
формату пути , пользователь должен иметь роль администратора.
(2) выполнено, если запрос представляет собой/user/**
формат пути , пользователь должен иметь роль пользователя.
(3) Остальные пути запроса в других форматах доступны только после аутентификации (входа в систему).
Обратите внимание, что порядок трех правил, настроенных в коде, очень важен. Подобно Shiro, Spring Security также сопоставляется сверху вниз при сопоставлении. После сопоставления он не будет продолжать сопоставление.Так что порядок правил перехвата не может быть неправильным
С другой стороны, если вы принудительно поместите anyRequest перед antMatchers, например:
http.authorizeRequests()
.anyRequest().authenticated()
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasRole("user")
.and()
На этом этапе, когда проект будет запущен, будет сообщено об ошибке, и будет предложено, что antMatchers не могут быть добавлены после anyRequest:
Это семантически хорошо понятно, anyRequest
другие запросы уже включены, и это не имеет никакого смысла, если после него настраиваются другие запросы.
С семантической точки зрения anyRequest
он должен быть помещен в конец, указывая, как обрабатывать оставшиеся запросы в дополнение к предыдущим правилам перехвата.
В правилах блокировки классов конфигурации AbstractRequestMatcherRegistry
мы можем увидеть следующий код (раздел Source):
public abstract class AbstractRequestMatcherRegistry<C> {
private boolean anyRequestConfigured = false;
public C anyRequest() {
Assert.state(!this.anyRequestConfigured, "Can't configure anyRequest after itself");
this.anyRequestConfigured = true;
return configurer;
}
public C antMatchers(HttpMethod method, String... antPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure antMatchers after anyRequest");
return chainRequestMatchers(RequestMatchers.antMatchers(method, antPatterns));
}
public C antMatchers(String... antPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure antMatchers after anyRequest");
return chainRequestMatchers(RequestMatchers.antMatchers(antPatterns));
}
protected final List<MvcRequestMatcher> createMvcMatchers(HttpMethod method,
String... mvcPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure mvcMatchers after anyRequest");
return matchers;
}
public C regexMatchers(HttpMethod method, String... regexPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure regexMatchers after anyRequest");
return chainRequestMatchers(RequestMatchers.regexMatchers(method, regexPatterns));
}
public C regexMatchers(String... regexPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure regexMatchers after anyRequest");
return chainRequestMatchers(RequestMatchers.regexMatchers(regexPatterns));
}
public C requestMatchers(RequestMatcher... requestMatchers) {
Assert.state(!this.anyRequestConfigured, "Can't configure requestMatchers after anyRequest");
return chainRequestMatchers(Arrays.asList(requestMatchers));
}
}
Из этого исходного кода мы видим, что перед любыми правилами перехвата (включая сам anyRequest) он сначала определяет, настроен ли anyRequest. Если он настроен, будет выброшено исключение и система не запустится.
Так что все понимают, почему anyRequest нужно ставить последним
Пять, начни тест
Далее запускаем проект на тестирование.
После успешного запуска проекта мы сначала авторизуемся как yolo:
После успешного входа в систему посетите три интерфейса / hello, / admin / hello и / user / hello соответственно, среди которых:
(1)
/hello
Поскольку вы можете получить доступ после входа в систему, этот интерфейс успешно доступен.
(2)/admin/hello
Требуется учетная запись администратора, поэтому доступ не выполняется.
(3)/user/hello
Требуется идентификация пользователя, поэтому доступ успешен.
Таким же образом войдите в nlcs.
Шесть, наследование ролей
Как упоминалось ранее, администратор может получить доступ ко всем ресурсам, к которым имеет доступ пользователь.Очевидно, что в нашем текущем коде такой функции пока нет.
Чтобы реализовать все ресурсы, к которым пользователь может получить доступ, администратор может получить к ним доступ. Это включает в себя еще одну точку знаний, называемуюНаследование ролей
Это очень полезно в реальной разработке.
Верхний уровень может иметь все разрешения нижнего уровня. Если используется наследование ролей, эту функцию очень легко реализовать. Нам нужно только добавить следующий код в SecurityConfig, чтобы настроить отношения наследования ролей:
@Bean
RoleHierarchy roleHierarchy() {
RoleHierarchyImpl hierarchy = new RoleHierarchyImpl();
hierarchy.setHierarchy("ROLE_admin > ROLE_user");
return hierarchy;
}
Обратите внимание, что в конфигурации вам нужно вручную добавить ROLE_
префикс символа . Вышеупомянутая конфигурация означает ROLE_admin
автоматическое ROLE_user
разрешение.
После завершения настройки перезапустите проект, на этот раз мы обнаружили, что yolo также может получить доступ к /user/hello
этому интерфейсу.