我已经使用spring boot实现了OAuth 2.0。我将散列密码(包括盐)存储到我的数据库中。
我是Spring的新手,无法弄清楚如何验证用户名/密码。
这是我的UserDAO类:
@Service
public class UserDAO implements UserDetailsService{
@Autowired
private LoginDetailsManager loginDetailsManager;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("Get user");
LoginDetails user = loginDetailsManager.getByUsername(username);
System.out.println(user.toString());
if (user == null) {
// Not found...
throw new UsernameNotFoundException(
"User " + username + " not found.");
}
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_USER");
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
grantedAuthorities.add(grantedAuthority);
String password = user.getPasswordHash();
String salt = user.getSalt();
return new UserDetailsImpl(
user.getUsername(),
user.getPasswordHash(),
salt,
grantedAuthorities);
}
}
这是Application类的安全配置器:
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients();
}
问题:
答案 0 :(得分:2)
在Spring Security中,检索主体,提供分别匹配密码的salt和编码都是相互分离的。您的UserDetails服务基本上是获取主体的正确方法。
你必须提供一个PasswordEncoder,Spring Boot中的默认值是BCrypt,它与你的哈希值不匹配。 Spring Boot和Spring Security不再使用旧密码编码器(ShaPasswordEncoder等)以及salt源。你必须手动定义它们。
如果您的UserDetails
包含salt列,则此配置应该基本上可以执行您想要的操作。如果您不知道如何做到这一点,请参阅我即将出版的书中的完整实施ShaPasswordEncoderConfig.java。
@Configuration
public class ShaPasswordEncoderConfig
extends WebSecurityConfigurerAdapter {
final UserDetailsService userDetailsService;
public ShaPasswordEncoderConfig(final UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Override
public void configure(
AuthenticationManagerBuilder auth
) {
DaoAuthenticationProvider authProvider
= new DaoAuthenticationProvider();
authProvider.setUserDetailsService(
userDetailsService);
authProvider.setPasswordEncoder(
new ShaPasswordEncoder(256));
authProvider.setSaltSource(
user -> ((UserWithSalt)user).getSalt());
auth.authenticationProvider(authProvider);
}
}
为了使这项工作,您必须为自己的UserDetails实现角色,而不是使用Spring Security本身的那个,因为它没有存储salt的属性。
我在示例中使用的SaltSource
是一个lambda,它将UserDetails
强制转换为我的实现并获取盐。您还可以使用ReflectionSaltSource
这是一个通过反射获取salt的实现。
修改强>
UserDetails
易于实施,请参阅:
你可以使用这样的实现:
class UserDetailsImpl implements UserDetails {
private final String username;
private final String hashedPassword;
private final String salt;
private final List<GrantedAuthority> grantedAuthorities;
public UserDetailsImpl(String username, String hashedPassword, String salt, List<GrantedAuthority> grantedAuthorities) {
this.username = username;
this.hashedPassword = hashedPassword;
this.salt = salt;
this.grantedAuthorities = grantedAuthorities;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return grantedAuthorities;
}
@Override
public String getPassword() {
return hashedPassword;
}
@Override
public String getUsername() {
return username;
}
public String getSalt() {
return salt;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}