我已经基于Spring-Boot 1.2.2.RELEASE创建了一个Web应用程序。我还有一个数据库表,用于管理用户凭据。它有基本列,例如ID,用户名和密码。还添加了盐柱,我计划在每个帐户存储随机生成的盐。
我正在尝试使用Spring Security,并且使用编码密码进行身份验证时遇到一些困难。所以基本上我有一个寄存器控制器:
@Autowired
private UserRepository userRepository;
private BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
@RequestMapping(value = "/register", method = RequestMethod.POST)
public ResponseEntity<User> register(@RequestParam(value = "email_address") String emailAddress, @RequestParam(value = "password") String password) {
String username = emailAddress;
String salt = KeyGenerators.string().generateKey();
User user = new User();
user.setUsername(emailAddress);
user.setEmailAddress(emailAddress);
user.setSalt(salt);
user.setPassword(passwordEncoder.encode(username+salt+password));
user.setCreatedBy(1);
user.setCreatedOn(new Date());
user.setLastUpdatedby(1);
user.setLastUpdatedOn(new Date());
user.setStartDate(new Date());
return new ResponseEntity<User>(this.userRepository.save(user), HttpStatus.OK);
}
然后我实现了UserDetailsService:
@Service
protected static class ApplicationUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = this.userRepository.findByUsername(username);
if (user == null) {
return null;
}
List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER");
String password = passwordEncoder.encode(username+user.getSalt()+user.getPassword());
return new org.springframework.security.core.userdetails.User(username, password, auth);
}
}
但是,由于BCryptPasswordEncoder每次都会生成新的结果,即使输入相同,它将如何进行身份验证?
修改 只是想补充一点,如果我不使用任何编码器并将密码存储为纯文本,我可以进行身份验证。但当然这不是我想做的事。
更新1 这是WebSecurityConfigurerAdapter的配置。在里面我有配置方法。
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
protected static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private ApplicationUserDetailsService applicationUserDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(applicationUserDetailsService).passwordEncoder(passwordEncoder);
}
@Bean
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
}
更新2 我通过扩展DaoAuthenticationProvider来实现它。请参阅下面的更新代码。
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
protected static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private ApplicationUserDetailsService applicationUserDetailsService;
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(applicationUserDetailsService);
authenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());
return authenticationProvider;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
@Bean
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
}
还必须修改我的RegisterController,如下所示。
@RestController
public class RegisterController {
@Autowired
private UserRepository userRepository;
private BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
@RequestMapping(value = "/register", method = RequestMethod.POST)
public ResponseEntity<User> register(@RequestParam(value = "email_address") String emailAddress, @RequestParam(value = "password") String password) {
User user = new User();
user.setUsername(emailAddress);
user.setEmailAddress(emailAddress);
user.setPassword(passwordEncoder.encode(password));
user.setSalt(KeyGenerators.string().generateKey());
user.setCreatedBy(1);
user.setCreatedOn(new Date());
user.setLastUpdatedby(1);
user.setLastUpdatedOn(new Date());
user.setStartDate(new Date());
return new ResponseEntity<User>(this.userRepository.save(user), HttpStatus.OK);
}
}
更新3
忘记包含更新的UserDetailService实现。
@Service
protected static class ApplicationUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = this.userRepository.findByUsername(username);
if (user == null) {
return null;
}
List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER");
String password = passwordEncoder.encode(user.getPassword());
return new org.springframework.security.core.userdetails.User(username, password, auth);
}
}
我可能需要立即删除盐柱,因为它基本上没用。
希望这对其他人也有帮助。