Рубрики
Без рубрики

Весенняя безопасность – Роли и привилегии

Как сопоставить роли и привилегии для приложения Spring Security: настройка, аутентификация и процесс регистрации.

Автор оригинала: Eugen Paraschiv.

Весенняя безопасность – Роли и привилегии

1. Обзор

В этой статье продолжается серия Регистрация с весенней безопасностью с взглядом на то, как правильно реализовать Роли и привилегии .

Дальнейшее чтение:

Введение в весеннее выражение безопасности

Введение в безопасность весеннего метода

Весенняя безопасность – Перенаправить на предыдущий URL после входа

2. Роль пользователя и привилегия

Во-первых, давайте начнем с наших сущностей. У нас есть три основных сущности:

  • пользователь
  • Ролевая – это представляет собой роль пользователя высокого уровня в системе; каждая роль будет иметь набор низкоуровневых привилегий
  • Привилегия – представляет собой низкоуровневую, гранулированную привилегию/власть в системе

Вот пользователь :

@Entity
public class User {
 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String firstName;
    private String lastName;
    private String email;
    private String password;
    private boolean enabled;
    private boolean tokenExpired;

    @ManyToMany 
    @JoinTable( 
        name = "users_roles", 
        joinColumns = @JoinColumn(
          name = "user_id", referencedColumnName = "id"), 
        inverseJoinColumns = @JoinColumn(
          name = "role_id", referencedColumnName = "id")) 
    private Collection roles;
}

Как вы можете видеть, пользователь содержит роли, но и несколько дополнительных деталей, которые необходимы для надлежащего механизма регистрации.

Далее – вот роль :

@Entity
public class Role {
 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;
    @ManyToMany(mappedBy = "roles")
    private Collection users;

    @ManyToMany
    @JoinTable(
        name = "roles_privileges", 
        joinColumns = @JoinColumn(
          name = "role_id", referencedColumnName = "id"), 
        inverseJoinColumns = @JoinColumn(
          name = "privilege_id", referencedColumnName = "id"))
    private Collection privileges;   
}

И, наконец привилегированное :

@Entity
public class Privilege {
 
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;

    @ManyToMany(mappedBy = "privileges")
    private Collection roles;
}

Как вы можете видеть, мы рассматриваем как роль пользователя <->, так и отношения Роли <-> Privilege много-много двунаправленных .

3. Настройка Привилегий и ролей

Далее – давайте сосредоточимся на ранней настройке Привилегий и Ролей в системе.

Мы свяжем это со запуском приложения и будем использовать ПриложениеЛистенер на КонтекстРефрефшедЕвочение для загрузки наших исходных данных на сервере начать:

@Component
public class SetupDataLoader implements
  ApplicationListener {

    boolean alreadySetup = false;

    @Autowired
    private UserRepository userRepository;
 
    @Autowired
    private RoleRepository roleRepository;
 
    @Autowired
    private PrivilegeRepository privilegeRepository;
 
    @Autowired
    private PasswordEncoder passwordEncoder;
 
    @Override
    @Transactional
    public void onApplicationEvent(ContextRefreshedEvent event) {
 
        if (alreadySetup)
            return;
        Privilege readPrivilege
          = createPrivilegeIfNotFound("READ_PRIVILEGE");
        Privilege writePrivilege
          = createPrivilegeIfNotFound("WRITE_PRIVILEGE");
 
        List adminPrivileges = Arrays.asList(
          readPrivilege, writePrivilege);        
        createRoleIfNotFound("ROLE_ADMIN", adminPrivileges);
        createRoleIfNotFound("ROLE_USER", Arrays.asList(readPrivilege));

        Role adminRole = roleRepository.findByName("ROLE_ADMIN");
        User user = new User();
        user.setFirstName("Test");
        user.setLastName("Test");
        user.setPassword(passwordEncoder.encode("test"));
        user.setEmail("[email protected]");
        user.setRoles(Arrays.asList(adminRole));
        user.setEnabled(true);
        userRepository.save(user);

        alreadySetup = true;
    }

    @Transactional
    Privilege createPrivilegeIfNotFound(String name) {
 
        Privilege privilege = privilegeRepository.findByName(name);
        if (privilege == null) {
            privilege = new Privilege(name);
            privilegeRepository.save(privilege);
        }
        return privilege;
    }

    @Transactional
    Role createRoleIfNotFound(
      String name, Collection privileges) {
 
        Role role = roleRepository.findByName(name);
        if (role == null) {
            role = new Role(name);
            role.setPrivileges(privileges);
            roleRepository.save(role);
        }
        return role;
    }
}

Итак, что происходит во время этого простого кода настройки? Ничего сложного:

  • мы создаем привилегии
  • мы создаем роли и присваиваем им привилегии
  • мы создаем пользователя и назначаем ему роль

Обратите внимание, как мы используем ужеСетап флаг к определить, должна ли установка работать или не . Это просто потому, что, в зависимости от того, сколько контекстов вы настроили в приложении – КонтекстРефрефшедЕвочение может быть уволен несколько раз. И мы хотим, чтобы установка была выполнена только один раз.

Две быстрые заметки здесь – во-первых, о терминологии . Мы используем Привилегия – Ролевая термины здесь, но весной, они немного отличаются. Весной наша Привилегия называется ролью, а также (предоставленным) органом, что несколько сбивает с толку. Не проблема для реализации, конечно, но, безусловно, стоит отметить.

Во-вторых – эти весенние роли (наши привилегии) нуждаются в приставке ; по умолчанию, что приставка “ROLE”, но она может быть изменена. Мы не используем эту приставку здесь, просто чтобы держать вещи простыми, но имейте в виду, что если вы явно не меняете его, это будет необходимо.

4. Пользовательские UserDetailsService

Теперь – давайте проверим процесс проверки подлинности.

Мы увидим, как получить пользователя в рамках нашего пользовательского ПользовательDetailsService , и как сопоставить правильный набор органов власти с ролей и привилегий, назначенных пользователем:

@Service("userDetailsService")
@Transactional
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;
 
    @Autowired
    private IUserService service;
 
    @Autowired
    private MessageSource messages;
 
    @Autowired
    private RoleRepository roleRepository;

    @Override
    public UserDetails loadUserByUsername(String email)
      throws UsernameNotFoundException {
 
        User user = userRepository.findByEmail(email);
        if (user == null) {
            return new org.springframework.security.core.userdetails.User(
              " ", " ", true, true, true, true, 
              getAuthorities(Arrays.asList(
                roleRepository.findByName("ROLE_USER"))));
        }

        return new org.springframework.security.core.userdetails.User(
          user.getEmail(), user.getPassword(), user.isEnabled(), true, true, 
          true, getAuthorities(user.getRoles()));
    }

    private Collection getAuthorities(
      Collection roles) {
 
        return getGrantedAuthorities(getPrivileges(roles));
    }

    private List getPrivileges(Collection roles) {
 
        List privileges = new ArrayList<>();
        List collection = new ArrayList<>();
        for (Role role : roles) {
            collection.addAll(role.getPrivileges());
        }
        for (Privilege item : collection) {
            privileges.add(item.getName());
        }
        return privileges;
    }

    private List getGrantedAuthorities(List privileges) {
        List authorities = new ArrayList<>();
        for (String privilege : privileges) {
            authorities.add(new SimpleGrantedAuthority(privilege));
        }
        return authorities;
    }
}

Интересная вещь, котор нужно последовать за здесь как Привилегированности (и роли) отображены к дареноАвторитетным образованиям.

Это отображение делает всю конфигурацию безопасности очень гибкая и мощная – Вы можете смешивать и сопоставлять роли и привилегии, как гранулированные по мере необходимости, и в конце концов, они будут правильно отображены властям и возвращены обратно в рамки.

5. Регистрация пользователей

Наконец – давайте посмотрим на регистрацию нового пользователя.

Мы видели, как настройка идет о создании пользователя и присваивает роли (и привилегии) к нему – давайте теперь посмотрим, как это должно быть сделано во время регистрации нового пользователя:

@Override
public User registerNewUserAccount(UserDto accountDto) throws EmailExistsException {
 
    if (emailExist(accountDto.getEmail())) {
        throw new EmailExistsException
          ("There is an account with that email adress: " + accountDto.getEmail());
    }
    User user = new User();

    user.setFirstName(accountDto.getFirstName());
    user.setLastName(accountDto.getLastName());
    user.setPassword(passwordEncoder.encode(accountDto.getPassword()));
    user.setEmail(accountDto.getEmail());

    user.setRoles(Arrays.asList(roleRepository.findByName("ROLE_USER")));
    return repository.save(user);
}

В этой простой реализации мы предполагаем, что регистрируется стандартный пользователь, поэтому ROLE_USER роль присваивается ему.

Конечно, более сложная логика может быть легко реализована таким же образом – либо с помощью нескольких, жестких методов регистрации, или, позволяя клиенту отправить тип пользователя, который регистрируется.

6. Заключение

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

полная реализация этой регистрации с весенней безопасности учебник можно найти в проект GitHub – это Maven основе проекта, поэтому она должна быть легко импортировать и работать, как она есть.