在我的Spring Boot MVC应用程序中,我使用Spring Security提供身份验证和用户注册。用户的身份验证和注册工作正常,但在创建用户帐户后,我想自动登录他。执行此操作时,我收到BadCredentialsException。具有相同凭据的此用户通常使用登录表单正确登录。我感谢你的任何帮助。以下是我的代码:
来自控制器的方法
@RequestMapping(value = "/register", method = RequestMethod.POST)
public String registerUser(@ModelAttribute("user") User user, BindingResult result,
WebRequest request, Errors errors) {
User registeredUser = null;
if (result.hasErrors() == false) {
registeredUser = createUserAccount(user, result);
}
if (registeredUser == null) {
return "/register";
}
securityService.autologin(registeredUser.getLogin(), registeredUser.getPassword());
return "/whiprounds";
}
SecurityServiceImpl(方法身份验证抛出异常)
@Service
public class SecurityServiceImpl implements SecurityService {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
private static final Logger logger = LoggerFactory.getLogger(SecurityServiceImpl.class);
@Override
public String findLoggedInLogin() {
Object userDetails = SecurityContextHolder.getContext().getAuthentication().getDetails();
if (userDetails instanceof UserDetails) {
return ((UserDetails) userDetails).getUsername();
}
return null;
}
@Override
public void autologin(String username, String password) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
authenticationManager.authenticate(usernamePasswordAuthenticationToken);
if (usernamePasswordAuthenticationToken.isAuthenticated()) {
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
logger.debug(String.format("Auto login %s successfully!", username));
}
}
}
UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Autowired
private RoleRepository roleRepository;
@Override
public User registerNewUserAccount(User user) throws LoginExistsException {
if (loginExists(user.getLogin())) {
throw new LoginExistsException("User with this login already exists");
}
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
user.setRoles(new HashSet<>((Collection<? extends Role>) roleRepository.findAll()));
return userRepository.save(user);
}
private boolean loginExists(String login) {
User user = userRepository.findByLogin(login);
if (user != null) {
return true;
}
return false;
}
}
UserDetailsServiceImpl
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User user = userRepository.findByLogin(s);
if (user == null) {
throw new UsernameNotFoundException(s);
}
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.getLogin(), user.getPassword(), grantedAuthorities);
}
}
答案 0 :(得分:2)
首先,此方法因密码问题而抛出异常(据我所知,从您的代码中可以看出)。您的方法registerNewUserAccount
返回User
对象,该密码已经过哈希处理。然后你把它传递到这里:
securityService.autologin(registeredUser.getLogin(), registeredUser.getPassword());
事实证明,您稍后会将哈希密码传递给authenticationManager
。这是错误的 - 您应该将原始密码传递给它。像这样的Smth:
@RequestMapping(value = "/register", method = RequestMethod.POST)
public String registerUser(@ModelAttribute("user") User user, BindingResult result,
WebRequest request, Errors errors) {
User registeredUser = null;
String originalPassword = user.getPassword();
if (result.hasErrors() == false) {
registeredUser = createUserAccount(user, result);
}
if (registeredUser == null) {
return "/register";
}
securityService.autologin(registeredUser.getLogin(), originalPassword);
return "/whiprounds";
}
其次,authenticationManager.authenticate(usernamePasswordAuthenticationToken);
- 此方法实际返回已填充的Authentication
对象(如果身份验证成功),您应将此对象放入SecurityContext
,而不是你传递给`authenticationManager'的那个。像这样的Smth:
@Override
public void autologin(String username, String password) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
Authentication auth = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
if (auth.isAuthenticated()) {
SecurityContextHolder.getContext().setAuthentication(auth);
logger.debug(String.format("Auto login %s successfully!", username));
}
}
希望这有帮助。