В статье рассказывается об операции авторизации в Spring Security.

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этому интерфейсу.

Вставьте описание изображения сюда

рекомендация

отblog.csdn.net/nanhuaibeian/article/details/108596231