arrow-left

All pages
gitbookPowered by GitBook
1 of 1

Loading...

7. Работа со Spring Security, часть 1

Spring Security – это фреймворк обеспечения безопасности, предоставляющий возможность декларативного управления безопасностью приложений на основе фреймворка Spring.

Создадим новый проект, который включает модуль Spring Security или добавим в существующий проект зависимость

При попытке перейти на любой URL-адрес проекта нас перенаправит на форму ввода логина и пароля

По умолчанию, логином является user, а пароль генерируется каждый раз при старте приложения.

Если вы ввели правильно логин и пароль, то сервер переадресует вас на указанный URL.

В файле application.properties вы можете указать желаемый логин и пароль для пользователя по умолчанию (в данной лекции будет использоваться конфигурация с помощью языка yaml).

Фреймворк Spring Security "из коробки" предоставляет вам возможность простой версии так называемой form-based аутентификации. Если быть точнее, то по умолчанию, Spring Security реализует следующее поведение:

  • добавляет обязательный процесс аутентификации для всех URL;

  • добавляет форму для входа;

  • обрабатывает ошибки формы ввода;

hashtag
Основные понятия, связанные со Spring Security:

Authentication

Authorization

Principal - текущий залогиненный пользователь или текущий залогиненный аккаунт (если у одного физического лица или программы есть несколько аккаунтов, то тогда ему будет соответствовать несколько возможных principal`ов). Иногда, в общем случае, principal - это субъект, который принимает участие в осуществлении процедур безопасности. В качестве principal могут выступать люди, компьютеры, службы, процессы или их группа;

Granted Authority - ;

Role - .

hashtag
Настройка процесса аутентификации в Spring

Для того, чтобы сконфигурировать процесс аутентификации, необходимо создать объект AuthenticationManager, в котором следует указать требуемые параметры аутентификации. Объект типа AuthenticationManager обычно настраивают с помощью builder`а, который имеет тип AuthenticationManagerBuilder.

Добавим класс SecurityConfig, который наследуется от класса WebSecurityConfigurerAdaper. Также укажем аннотации @Configuration (это означает, что данный класс является конфигурационным) и @EnableWebSecurity (это означает, что данный класс является содержит настройки для защиты веб-приложения).

Переопределим метод configure(), который принимает на вход объект типа AuthenticationManagerBuilder (обратите внимание, что нам нужна именно эта версия перегруженного метода).

Для начала укажем, что источник аутентификации это жестко прописанные пользователи (так называемая inMemoryAuthentication(). Далее указываем логин, пароль и роль пользователя.

Если необходимо указать несколько пользователей, после параметров первого пользователя вызываете метод and() после чего указываете параметры следующего пользователя.

hashtag
Хеширование паролей

Хранить пароли без хеширования является грубейшим нарушением правил безопасности, поэтому нам необходимо добавить процесс хеширования пароля в нашу систему.

Не будем вдаваться в подробности различных алгоритмов хеширования пароля, просто скажем, что на даннай момент рекомендуемым является алгоритм Bcrypt. Для обеспечения хеширования, вы можете поступить несколькими способами.

Первый способ - создайте Bean, который будет возвращать объект Encoder`а и добавьте его как метод конфигурационного класса.

Далее найдите в интернете генератор хеша с помощью алгоритма Bcrypt, скопируйте хеш для вашего пароля в метод password.

Если не хотите использовать Bean для хеширования пароля, можете в начале хеша добавить обозначение, что это хеш для алгоритма bcrypt.

hashtag
Настройка процесса авторизации

Добавим класс контроллера

Изменим SecurityConfig

Изменим formLogin() на httpBasic().

Создадим MyUserDetailsService

Создадим MyUserDetails

Добавим в pom.xml

Настроим подключение к БД

Добавим сущность User

Изменим MyUserDetailsService

Создадим UserRepository

Изменим MyUserDetails

pom.xml
<dependencies>
    ...
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    
    ...
    
</dependencies>
создает пользователя по умолчанию и генерирует пароль.
resources/application.yml
spring:
  security:
    user:
      name: nick
      password: 1234
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        super.configure(auth);
    }
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("foo")
                .password("bar")
                .roles("USER");
    }
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("foo")
                .password("bar")
                .roles("USER")
                .and()
                .withUser("nick")
                .roles("MODERATOR");
    }
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("foo")
                .password("$2y$12$kElDOfhm4WgdsDc4UQjgtuz0VEi5MOqVVhXaMoD1F2lhLivokhCqe")
                .roles("USER")
                .and()
                .withUser("nick")
                .roles("MODERATOR");
    }

    @Bean
    public PasswordEncoder getPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("foo")
                .password("{bcrypt}$2y$12$.JzV1A3qlof1.NzZpGaTYO1b26JGHevg0900QvwrSOdU3U9.g4hta")
                .roles("USER");
    }

//    @Bean
//    public PasswordEncoder getPasswordEncoder() {
//        return new BCryptPasswordEncoder();
//    }
}
@Controller
public class IndexController {

    @GetMapping("/")
    public String index() {
        return "index";
    }

    @GetMapping("/user/index")
    public String user_index() {
        return "/user/index";
    }

    @GetMapping("/admin/index")
    public String admin_index() {
        return "/admin/index";
    }
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("foo")
                .password("$2y$12$kElDOfhm4WgdsDc4UQjgtuz0VEi5MOqVVhXaMoD1F2lhLivokhCqe")
                .roles("USER")
                .and()
                .withUser("admin")
                .password("$2y$12$DQlTV6V1wMKEoCIW5lo1huAn2/bRk4hULDmRS5Jw6YW7HayHV4K66")
                .roles("ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/", "static/css", "static/js").permitAll()
                .antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
                .antMatchers("/admin/**").hasRole("ADMIN")
                .and().formLogin();
    }

    @Bean
    public PasswordEncoder getPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
@Service
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    UserRepository repository;

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        return new MyUserDetails(s);
    }
}
public class MyUserDetails implements UserDetails {
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
    }

    private String userName;

    public MyUserDetails(String userName) {
        this.userName = userName;
    }

    public MyUserDetails() {
    }

    @Override
    public String getPassword() {
        return "$2y$12$8fKhxW71f4DzkzXYCh592.I.cd1uKkMrNwrHAApR1x5KHJ3qy1IjS";
    }

    @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;
    }
}
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<!-- PostgreSQL -->
<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
</dependency>
application.yml
  jpa:
    database: POSTGRESQL
    show-sql: true
    hibernate:
      ddl-auto: create-drop
    properties:
      hibernate:
        dialect: org.hibernate.dialect.PostgreSQLDialect
  datasource:
    platform: postgres
    url: jdbc:postgresql://localhost:5432/ejournal
    username: ejournal_user
    password: 123456
    driverClassName: org.postgresql.Driver
@Entity
@Table(name = "profile")
@Data
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @Column(name = "user_name")
    private String userName;
    private String password;
    private boolean active;
    private String roles;
}
@Service
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    UserRepository repository;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        Optional<User> user = repository.findByUserName(s);

        user.orElseThrow(() -> new UsernameNotFoundException("User not found: " + s));

        return user.map(MyUserDetails::new).get();
    }
}
public interface UserRepository extends JpaRepository<User, Integer> {

    Optional<User> findByUserName(String userName);
}
public class MyUserDetails implements UserDetails {
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorityList;
    }

    private String userName;
    private String password;
    private boolean active;
    private List<GrantedAuthority> authorityList;

    public MyUserDetails(User userName) {
        this.userName = userName.getUserName();
        this.password = userName.getPassword();
        this.active = userName.isActive();
        this.authorityList = Arrays.stream(userName.getRoles().split(",")).map(SimpleGrantedAuthority::new).collect(Collectors.toList());
    }

    public MyUserDetails() {
    }

    @Override
    public String getPassword() {
        return password;
    }

    @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 active;
    }
}