java - 如何通过一个通用的 UserDetailsService 注册不同角色和字段的用户?
问题描述
我有一个超类User
及其四个后代。每个继承人对应一个特定的角色,并具有一定的领域。我需要在这样的数据库结构上进行用户注册和身份验证。我尝试通过 执行此@Inheritance(JOINED)
操作,它适用于正常的 CRUD 操作,但注册和身份验证存在问题。我尝试通过几个UserDetailsService
,@Configuration
和来做到这一点@Order
,但是一个配置阻止了另一个,一些请求不起作用或UserDetails
返回空。身份验证提供程序还有其他内容。
是否可以通过它来实施,或者有更好的建议来实现这一目标?
谢谢。
父类用户及其后代:
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "usr", schema = "public")
@Inheritance(strategy = InheritanceType.JOINED)
public class User implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
@Transient
private String matchingPassword;
private String name;
private String surname;
private String patronymic;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate birthday;
private String hometown;
private String number;
private String mail;
private String avatar;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<Role> roles;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return getRoles();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
@Entity
@Table(name = "student", schema = "public")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public class Student extends User implements Serializable {
private String faculty;
private Integer rating;
@Builder
public Student(Long id,
String username,
String password,
String matchingPassword,
String name,
String surname,
String patronymic,
LocalDate birthday,
String hometown,
String number,
String mail,
String avatar,
Set<Role> roles,
String faculty,
Integer rating) {
super(id, username, password, matchingPassword, name, surname, patronymic, birthday, hometown, number, mail, avatar, roles);
this.faculty = faculty;
this.rating = rating;
}
}
@Entity
@Table(name = "director", schema = "public")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public class Director extends User implements Serializable {
private String department;
@Builder
public Director(Long id,
String username,
String password,
String matchingPassword,
String name,
String surname,
String patronymic,
LocalDate birthday,
String hometown,
String number,
String mail,
String avatar,
Set<Role> roles,
String department) {
super(id, username, password, matchingPassword, name, surname, patronymic, birthday, hometown, number, mail, avatar, roles);
this.department = department;
}
}
实现 UserDetailsService 的 UserService:
@Service
public class UserService implements UserDetailsService {
private final UserRepository userRepository;
private final FileService fileService;
@Value("${application.avatar-folder}")
private String avatarFolder;
@Autowired
public UserService(UserRepository userRepository,
@Lazy FileService fileService) {
this.userRepository = userRepository;
this.fileService = fileService;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if(user != null) {
Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
for(Role role : user.getRoles()) {
grantedAuthorities.add(new SimpleGrantedAuthority(role.getName()));
}
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
grantedAuthorities
);
}
throw new UsernameNotFoundException("Пользователя с именем " + username + " не существует!");
}
弹簧安全配置:
@Configuration
@EnableWebSecurity
@ComponentScan("com.amirdigiev.tsaritsynostudentportfolio")
@SuppressWarnings("Duplicates")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final UserService userService;
@Autowired
public SecurityConfig(UserService userService) {
this.userService = userService;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/registration")
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().permitAll()
.loginPage("/login")
.usernameParameter("username")
.passwordParameter("password")
.defaultSuccessUrl("/home", true)
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID");
http.headers()
.cacheControl().disable()
.and()
.csrf().disable();
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/static/**", "/images/**");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(bCryptPasswordEncoder());
}
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
解决方案
最后,我决定将 User 字段(通过组合)添加到所有角色。
推荐阅读
- spring-boot - 在 RabbitMQ 消费者中出现关闭错误
- php - 在我的 laravel 目录中保存 milon 生成的条形码
- python - 迭代至小数点后 12 位
- excel - 如何在 Excel 或 Powershell 中根据 IP 地址搜索域名?
- php - laravel 无法发送电子邮件,也不是错误
- javascript - 有没有可能的方法将它绑定到使用 vue 方法的事件中?
- jquery - 如何在此计算器中添加两个功能?(1) 如何添加第一个方程答案的新值?(2)如何用新值替换eval值?
- powershell - 如何在 PowerShell 中找到部分路径的潜在源环境变量?
- reactjs - TypeError:Events.map 不是函数
- reactjs - 我可以将 Auth0 sdk 与有状态组件一起使用吗?