Я интегрировал role и хочу управлять доступом к конкретной службе на основе роли.
Администратор может создать АГЕНТ, и этот агент входит в группу пользователя ADMIN.
По сути, у меня возникла связь с 1 to Many, потому что у моего пользователя могла быть только 1 роль.
@Entity
@Table(name = "role")
public class Role {
private Long id;
private String name;
private Collection<User> users;
public Role() {
}
public Role(String name) {
this.name = name;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@OneToMany(mappedBy = "role", cascade = CascadeType.ALL)
public Collection<User> getUsers() {
return users;
}
public void setUsers(Collection<User> users) {
this.users = users;
}
}
И здесь у меня есть пользователь, у которого отношение группы, а также группа, также 1 TO MANY, потому что user_admin может иметь несколько агентов, но агент не может иметь нескольких администраторов.
@Entity
@Table(name = "user")
public class User {
private long id;
private String username;
private String password;
private boolean enabled = false;
private Role role;
private UserGroup userGroup;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public User(String username, String password, Role role) {
this.username = username;
this.password = password;
this.role = role;
}
public User(String username, String password, boolean enabled, Role role, UserGroup userGroup) {
this.username = username;
this.password = password;
this.enabled = enabled;
this.role = role;
this.userGroup = userGroup;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@NotBlank
@Column(nullable = false, updatable = false, unique = true)
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@NotBlank
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Column(nullable = false, updatable = true)
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@ManyToOne
@JoinColumn(name = "role_id", referencedColumnName = "id")
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
@ManyToOne
@JoinColumn(name = "user_group_id", referencedColumnName = "id")
public UserGroup getUserGroup() {
return userGroup;
}
public void setUserGroup(UserGroup userGroup) {
this.userGroup = userGroup;
}
}
При создании пользователя я также указываю роль и группу.
А в SecurityConfig я настроил вот так.
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().authorizeRequests()
.antMatchers(Constants.BASE_URL_FILE_UPLOADER + Constants.URL_UPLOAD_FILE).hasRole("ADMIN") .anyRequest().authenticated()
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
// this disables session creation on Spring Security
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.exceptionHandling().authenticationEntryPoint(new ContentSearcherAuthenticationEntryPoint());
}
Но если я получаю доступ к этой конечной точке с пользователем-администратором, я бросаю запрещенный, а также в функции, когда я получаю доступ к authentication.getAuthorities()it return emptyList
ResponseEntity<JsonNode> uploadFile(@RequestParam("file") MultipartFile file, Authentication authentication) {
logger.info("Authentication is [{}] and user is [{}]", authentication.getAuthorities(), authentication.getName()); // []
}
Я запутался в UserDetailsService, я также добавил GrantedAuthority, вот так.
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
private UserRepository userRepository;
private RoleRepository roleRepository;
public UserDetailsServiceImpl(UserRepository userRepository, RoleRepository roleRepository) {
this.userRepository = userRepository;
this.roleRepository = roleRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findUserByUsername(username);
if (user == null) {
throw new UsernameNotFoundException(username + " Not Exists");
}
user.setEnabled(true);
userRepository.save(user);
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), user.isEnabled(),
true, true, true, getAuthorities(user.getRole()));
}
private Collection<? extends GrantedAuthority> getAuthorities(
Role role) {
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority(Constants.ROLE_PREFIX + role.getName()));
return authorities;
}
}
Что мне не хватает, есть ли еще конфигурация, которую я должен добавить?
Я использую JWT для аутентификации, что-то не должно быть добавлено и в это?
Потому что, когда я получаю Authentication в JWT successfulAuthentication, он показывает Authorities.
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
logger.info("Auth in the successful is [{}]", authResult.getAuthorities()); // [ROLE_ADMIN]
}
Использование ядра Spring-Security 5.0.9.
У меня есть, позвольте мне обновить его и добавить полный код.
Как вы храните роли в базе данных? Когда вы говорите hasRole("ADMIN");, Spring ожидает, что роль в JWT будет ROLE_ADMIN.




Я сделал это после того, как получил подсказку от вопроса @Reza Nasiri, в основном я не добавлял Authorities при аутентификации токена JWT, теперь то, что я сделал,
return new UsernamePasswordAuthenticationToken(user, null, getAuthorities("ADMIN");
В моей функции getAuthentication в классе JWTAuthorizationFilter.
JWTAuthorizationFilter
У вас нет сопоставления между пользователем и ролью, поэтому Hibernate не знает, как получить коллекцию. Поместите аннотации OneToMany и ManyToOne в ваши отношения, и получение данных должно работать.