В последние дни я немного читал о spring security, поэтому я собираюсь поделиться некоторыми вещами, которые я узнал.
Аутентификация: подтвердите личность пользователя. Авторизация: какие разрешения есть у пользователей.
Начните с добавления зависимости безопасности Spring Boot Starter в pom.xml чтобы включить базовую аутентификацию. Создайте конечную точку в своем контроллере и попытайтесь использовать ее, будет показана форма входа, предоставленная spring security.
Взгляните на консоль, когда вы запустите приложение, вы должны увидеть автоматически сгенерированный пароль, имя пользователя по умолчанию “пользователь”.
Мы даже можем настроить ваши собственные учетные данные пользователя в application.properties
spring.security.user.name=jhoni spring.security.user.password=1234
Чтобы создать настраиваемый класс безопасности, нам нужно использовать @EnableWebSecurity и расширить класс с помощью @WebSecurityConfigurerAdapter, чтобы мы могли переопределить некоторые методы, предоставляемые этим классом. Spring security также принуждает youtu хэшировать ваши пароли, чтобы они не сохранялись в виде обычного текста. Для следующего примера мы можем использовать PasswordEncoder , конечно, это не следует использовать в производстве, но для этого примера подойдет. Альтернативой может быть BCryptPasswordEncoder .
Идентификация
В IntelliJ cmd+N и посмотрите на методы, которые вы можете переопределить. Мы собираемся использовать настроить метод с AuthenticationManagerBuilder Параметры. автор имеет различные методы, такие как Аутентификация jdbc , аутентификация ldap , Служба пользовательских данных … но мы будем использовать inMemoryAuthentication
@EnableWebSecurity public class WebSecurity extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("user1") .password("123") .roles("APPRENTICE") .and() .withUser("user2") .password("123") .roles("SENSEI"); } @Bean public PasswordEncoder getPasswordEncoder() { return NoOpPasswordEncoder.getInstance(); } }
Авторизация
Здесь мы определяем, какие URL-адреса должны быть защищены, а какие нет. Теперь мы используем метод configure с параметром Http Security . Я предоставляю доступ любому пользователю, у которого есть роль СЕНСЕЯ.
@Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/**").hasRole("SENSEI") .and().formLogin(); }
Если мы попытаемся войти в систему с помощью пользователя 2, доступ будет предоставлен./** означает разрешить доступ к текущему уровню и любым внутренним уровням. Мы можем создавать разные конечные точки и вводить разные ограничения, как в следующем примере. Важно знать, что наиболее строгие правила должны быть вверху.
@Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/sensei").hasRole("SENSEI") .antMatchers("/apprentice").hasRole("APPRENTICE") .antMatchers("/").permitAll() .and().formLogin(); }
Если вы хотите использовать разные роли, попробуйте hasAnyRole() . Мы также можем добавить фильтры, их цель – перехватывать запросы, и у каждого из них есть своя ответственность (мы добавим ее позже).
.hasAnyRole("ROLE1", "ROLE2", "ROLE3") .addFilterBefore() .addFilterAfter()
Служба пользовательских данных
Мы собираемся настроить Spring Security так, чтобы она зависела от службы пользовательских данных. Он в основном загружает пользовательские данные. автор имеет метод, называемый UserDetailsService() , который позволяет проводить индивидуальную аутентификацию на основе интерфейса UserDetailsService
@EnableWebSecurity public class WebSecurity extends WebSecurityConfigurerAdapter { @Autowired private MyUserDetailService myUserDetailService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(myUserDetailService); }
Давайте создадим наш собственный класс Userdetailsservice и UserDetail. В MyUserDetailService мы переопределяем loadUserByUsername метод, который получит имя пользователя в качестве параметра и передаст его в наши myuserdetails .
@Service public class MyUserDetailService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return new MyUserDetails(username); } }
Когда мы реализуем интерфейс UserDetails, мы можем переопределить несколько методов. Я собираюсь создать поле имя пользователя для передачи имени пользователя при входе пользователя в систему. Остальные методы будут иметь жестко закодированные значения. getAuthorities возвращает разрешения, предоставленные пользователю, в этом случае я просто добавлю роль СЕНСЕЯ.
@Data @AllArgsConstructor @NoArgsConstructor public class MyUserDetails implements UserDetails { private String username; @Override public Collection extends GrantedAuthority> getAuthorities() { return List.of(new SimpleGrantedAuthority("ROLE_SENSEI")); } @Override public String getPassword() { return "pass"; } @Override public String getUsername() { return username; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } }
Поток выглядит следующим образом:
- Класс веб-безопасности загружен
- Когда пользователь вводит имя пользователя + пароль, фильтр аутентификации перехватывает запрос, и создается объект UsernamePasswordAuthenticationToken с учетными данными запроса.
- loadUserByUsername получает имя пользователя.
- Объект myuserdetails создается с любым отправленным именем пользователя и всем остальным жестко запрограммированным (притворяющимся пользователем, который у нас есть в нашей базе данных), и он сравнивается с объектом UsernamePasswordAuthenticationToken.
- Если все в порядке 😃 , в противном случае ⛔️
Вместо жесткого кодирования создания моих пользовательских данных в сервисе вы можете внедрить репозиторий и получить данные пользователя из базы данных. Конечно, класс MyUserDetails придется изменить, чтобы вместо получения строки, как мы делали раньше, он получал Пользователь .
@Service @RequiredArgsConstructor public class MyUserDetailService implements UserDetailsService { private final UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("Username does not exist")); return new MyUserDetails(user); } }
Я собираюсь продолжить, добавив JWT в другой пост, чтобы этот не стал слишком длинным.
Оригинал: “https://dev.to/jhonifaber/getting-started-with-spring-security-authentication-and-authorization-32de”