Я разрабатываю приложение с микро сервисами. На самом деле это приложение имеет:
- Eureka discovery (8010)
- Zuul gateway (8011)
- Springboot-приложение для управления пользователями (случайный порт)
Чтобы добраться до пользователя API, я использую zuul: Например, у меня есть эти точки входа:
// delete a specific user
[DELETE] http://localhost:8011/users-ms/users/4RGh4MKkqdpXxYsJXLWRYXZKe6krsr
// get all users
[GET] http://localhost:8011/users-ms/users
Пока все хорошо. Моя проблема в том, что я хотел бы разрешить только «Администраторам» и «Владельцам» удалять свой профиль.
Для этого в моем пользовательском микро-сервисе у меня есть этот метод контроллера:
@PreAuthorize("hasRole('ADMIN') or #userId == principal.userId")
@Transactional
@DeleteMapping(path = "/{userId}", produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE })
public ResponseEntity<OperationStatusResponseModel> deleteUser(@PathVariable String userId) {
log.info("# deleteUser() was called");
OperationStatusResponseModel returnValue = new OperationStatusResponseModel();
userService.deleteUser(userId);
returnValue.setOperationName(RequestOperationName.DELETE.name());
returnValue.setOperationResult(RequestOperationResult.SUCCESS.getOperationName());
return new ResponseEntity<>(returnValue, HttpStatus.OK);
}
Я также реализовал класс UserPrincipal:
publi c Класс UserPrincipal реализует UserDetails {
private static final long serialVersionUID = 7464059818443209139L;
private UserEntity userEntity;
@Getter @Setter
private String userId;
public UserPrincipal(UserEntity userEntity) {
this.userEntity = userEntity;
this.userId = userEntity.getUserId();
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new HashSet<>();
Collection<AuthorityEntity> authorityEntities = new HashSet<>();
// get user roles
Collection<RoleEntity> roles = userEntity.getRoles();
if (roles == null) {
return authorities; // null
}
// get user roles
roles.forEach((role) ->{
authorities.add(new SimpleGrantedAuthority(role.getName()));
authorityEntities.addAll(role.getAuthorities());
});
// get user authorities
authorityEntities.forEach(authorityEntity -> {
authorities.add(new SimpleGrantedAuthority(authorityEntity.getName()));
});
return authorities;
}
И в моем UserServiceImpl:
@ Service publi c Класс UserServiceImpl реализует UserService {
private UserRepository userRepository;
private PasswordResetTokenRepository passwordResetTokenRepository;
private RoleRepository roleRepository;
private Utils utils;
private BCryptPasswordEncoder bCryptPasswordEncoder;
private AmazonSES amazonSES;
@Autowired
public UserServiceImpl(UserRepository userRepository,
PasswordResetTokenRepository passwordResetTokenRepository,
RoleRepository roleRepository,
AmazonSES amazonSES,
Utils utils,
BCryptPasswordEncoder bCryptPasswordEncoder) {
this.userRepository = userRepository;
this.passwordResetTokenRepository = passwordResetTokenRepository;
this.roleRepository = roleRepository;
this.amazonSES = amazonSES;
this.utils = utils;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
// load user by username : the interface is extending UserDetailsService
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
UserEntity userEntity = userRepository.findByEmail(email);
if (userEntity == null)
throw new UsernameNotFoundException(email);
return new UserPrincipal(userEntity);
}
У меня есть спецификация c websecurity в zuul которые позволяют мне получить доступ к этим точкам входа и определенному c классу веб-безопасности, который разрешает только «вызов» с zuul IP-адреса.
Я получаю этот ответ из приложения:
{
"timestamp": "2020-04-21T08:38:22.260+0000",
"message": "Failed to evaluate expression 'hasRole('ADMIN') or #userId == principal.userId'"
}
Если точка входа доступна только для ADMIN, я получаю ошибку 500, что нормально, если у меня нет роли ADMIN ,