Автор оригинала: 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 Collectionroles; }
Как вы можете видеть, пользователь содержит роли, но и несколько дополнительных деталей, которые необходимы для надлежащего механизма регистрации.
Далее – вот роль :
@Entity public class Role { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; @ManyToMany(mappedBy = "roles") private Collectionusers; @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 Collectionroles; }
Как вы можете видеть, мы рассматриваем как роль пользователя <->, так и отношения Роли <-> 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 extends GrantedAuthority> getAuthorities( Collectionroles) { 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 основе проекта, поэтому она должна быть легко импортировать и работать, как она есть.