Я пытаюсь защитить свои конечные точки с помощью контроля доступа на основе ролей.Я реализовал всю структуру, а также CustomUserDetailService, однако я не уверен, как мне применять эти правила к точкам, я искал какую-то хорошую оценку на основе аннотаций, такую как @PreAuthorize(hasRole('role'))
.Моя структура выглядит следующим образом:
Разрешение:
@Entity
public class Permission implements GrantedAuthority {
@Id
private Long id;
@Column(name = "NAME")
private String name;
@ManyToMany(mappedBy = "permissions", fetch = FetchType.LAZY)
private Collection<Role> roles;
@Override
public String getAuthority() {
return name;
}
Роль:
@Entity
public class Role implements GrantedAuthority {
@Id @Column(name="ID" )
private Long id;
@Column(name="NAME", nullable=false , unique=false)
private String name;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
name = "role_x_permission",
joinColumns = @JoinColumn(
name = "role_id"),
inverseJoinColumns = @JoinColumn(
name = "permission_id"))
private List<Permission> permissions;
@Override
public String getAuthority() {
return name;
}
Пользователь:
@Entity(name = "User")
@Table(name = "USERS")
@Data
public class User {
@Id
private Long id;
@Column(name="LOGIN" , nullable=true , unique=false)
private String login;
@Column(name="PASSWORD" , nullable=false , unique=false)
private String password;
@ManyToMany( fetch = FetchType.LAZY)
@JoinTable(name = "USER_ROLES",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles;
Теперь я определил свой CustomUserDetailsService:
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
@Transactional
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User applicationUser = userRepository.findByUsername(username);
if (applicationUser.getId() == null) {
throw new UsernameNotFoundException(username);
}
return new org.springframework.security.core.userdetails.User(applicationUser.getLogin(), applicationUser.getPassword(),
getAuthorities(applicationUser.getRoles()));
}
@Transactional
public Collection<? extends GrantedAuthority> getUserAuthorities(String username) {
User user = userRepository.findByUsername(username);
return getAuthorities(user.getRoles());
}
private Collection<? extends GrantedAuthority> getAuthorities(
Collection<Role> roles) {
return getGrantedAuthorities(getPermissions(roles));
}
private List<String> getPermissions(Collection<Role> roles) {
List<String> permissions = new ArrayList<>();
List<Permission> collection = new ArrayList<>();
for (Role role : roles) {
collection.addAll(role.getPermissions());
}
for (Permission item : collection) {
permissions.add(item.getName());
}
return permissions;
}
private List<GrantedAuthority> getGrantedAuthorities(List<String> permissions) {
List<GrantedAuthority> authorities = new ArrayList<>();
for (String permission : permissions) {
authorities.add(new SimpleGrantedAuthority(permission));
}
return authorities;
}
}
Затем я пытаюсь аннотировать свою конечную точку с помощью @ PreAuthorize
@PostMapping("/doSomething")
@PreAuthorize("hasRole('doSomething')")
public SomeEntity createComment(@RequestBody SomeEntity something) {
...
}
У меня есть пользователь с ролью USER
, эта роль не имеет разрешения для doSomething
, однако кажется, что @PreAuthorize("hasRole('doSomething')")
не работает.Я не уверен, что я сделал не так, не могли бы вы указать мою ошибку?
Кроме того, поскольку я использую RBAC
, этот hasRole
очень обманчив, поскольку доступ основан на разрешениях, а не на ролях.
Каков будет правильный способ авторизации доступа к конечной точке при RBAC
подходе?