Spring Security - 注册用户后自动登录无效

时间:2017-09-14 14:16:59

标签: java spring spring-mvc spring-boot spring-security

在我的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;
    }
}

UserDetailsS​​erviceImpl

@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);
    }
}

1 个答案:

答案 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));
    }
}

希望这有帮助。