Spring Security中BasicUserDetails构造函数无法解析的问题求助
问题背景
最初为基础登录用户实现了BasicUserDetails类:
@Data @NoArgsConstructor @AllArgsConstructor public class BasicUserDetails implements UserDetails { @NotBlank(message = "Username is mandatory") @Email(message = "Username should be a valid email address") private String username; @NotBlank(message = "Password is mandatory") @Size(min = 8, message = "Password length should be at least 8 characters") private String password; private List<GrantedAuthority> authorities; private boolean enabled; // 重写UserDetails接口的方法(略) }
新增OAuth用户后,由于OAuth用户无需密码,调整了类结构:
OAuth用户类
@Data @NoArgsConstructor @AllArgsConstructor public class OAuthUserDetails implements UserDetails { @NotBlank(message = "Username is mandatory") @Email(message = "Username should be a valid email address") private String username; private List<GrantedAuthority> authorities; private boolean enabled; // 重写UserDetails接口的方法,getPassword返回占位符(略) }
基础用户类
@Data @NoArgsConstructor @AllArgsConstructor public class BasicUserDetails extends OAuthUserDetails { @NotBlank(message = "Password is mandatory") @Size(min = 8, message = "Password length should be at least 8 characters") private String password; @Override public String getPassword() { return password; } }
问题描述
在CustomUserService的loadUserByUsername方法中实例化BasicUserDetails时报错:
@Component @AllArgsConstructor public class CustomUserService implements UserDetailsService { private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username); if (null == user || ! user.getUsername().equals(username)) { throw new UsernameNotFoundException("No user present with username: " + username); } else { // 此处报错 return new BasicUserDetails(user.getUsername(), user.getPassword(), Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")), true); } } }
报错信息:Cannot resolve constructor 'BasicUserDetails(String, String, List, boolean)',已知BasicUserDetails的全参构造仅接收password参数,请问如何传递其余参数?
解决方案
问题核心是:BasicUserDetails的@AllArgsConstructor只会生成包含自身新增属性(仅password)的构造方法,不会自动继承父类的属性构造逻辑。要传递父类的username、authorities、enabled参数,有两种可行方案:
方案一:手动编写子类构造方法
在BasicUserDetails中添加包含父类属性的构造方法,显式调用父类的全参构造:
@Data @NoArgsConstructor public class BasicUserDetails extends OAuthUserDetails { @NotBlank(message = "Password is mandatory") @Size(min = 8, message = "Password length should be at least 8 characters") private String password; // 手动编写包含父类属性的构造方法 public BasicUserDetails(String username, List<GrantedAuthority> authorities, boolean enabled, String password) { super(username, authorities, enabled); this.password = password; } @Override public String getPassword() { return password; } }
之后在CustomUserService中调整实例化参数顺序,匹配构造方法:
return new BasicUserDetails(user.getUsername(), Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")), true, user.getPassword());
方案二:使用@SuperBuilder注解简化构造逻辑
借助Lombok的@SuperBuilder注解实现父子类的构造参数传递,无需手动编写构造方法:
修改父类OAuthUserDetails
@Data @NoArgsConstructor @AllArgsConstructor @SuperBuilder public class OAuthUserDetails implements UserDetails { // 属性和原有方法保持不变 }
修改子类BasicUserDetails
@Data @NoArgsConstructor @AllArgsConstructor @SuperBuilder public class BasicUserDetails extends OAuthUserDetails { // 属性和原有方法保持不变 }
实例化时使用Builder模式
return BasicUserDetails.builder() .username(user.getUsername()) .password(user.getPassword()) .authorities(Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"))) .enabled(true) .build();
方案对比
- 方案一适合不需要Builder模式的场景,代码逻辑直白,无额外依赖成本;
- 方案二用注解简化构造逻辑,后续新增属性时无需修改构造方法,扩展性更强。
内容的提问来源于stack exchange,提问作者xRay
相关产品推荐
相关产品推荐

