Java 为新创建的用户添加自动登录会中断登录表单身份验证

Java 为新创建的用户添加自动登录会中断登录表单身份验证,java,spring,authentication,login,spring-security,Java,Spring,Authentication,Login,Spring Security,我在Spring 4.2.0中创建了一个自定义的登录表单和一个创建新帐户表单。它们工作得很好。但是现在我已经为新创建的用户实现了自动登录,它成功地登录了用户创建的日志。但是,如果我注销并尝试使用相同的凭据再次登录,身份验证将失败。身份验证也不适用于其他用户。因此,用户只有在创建时才能登录。之后,身份验证失败。让我觉得自动登录代码出于某种原因破坏了spring登录身份验证。请看下面的代码。猜猜为什么会这样 登入表格: <form:form modelAttribute="loginForm"

我在Spring 4.2.0中创建了一个自定义的
登录表单
和一个
创建新帐户
表单。它们工作得很好。但是现在我已经为新创建的用户实现了自动登录,它成功地登录了用户创建的日志。但是,如果我注销并尝试使用相同的凭据再次登录,身份验证将失败。身份验证也不适用于其他用户。因此,用户只有在创建时才能登录。之后,身份验证失败。让我觉得自动登录代码出于某种原因破坏了spring登录身份验证。请看下面的代码。猜猜为什么会这样

登入表格:

<form:form modelAttribute="loginForm" action="${pageContext.request.contextPath}/login" method="POST">
            Username:<form:input path="username" size="30" />
            Password:<form:password path="password" size="30" />
            <input type="submit" value="Login" />
</form:form>
成功创建用户后自动登录控制器:

@RequestMapping("/createAccount")
public ModelAndView submitCreateAccount(@ModelAttribute("newAccount") NewAccountDetails newAccountDetails) {
    System.out.println(newAccountDetails);
    ModelAndView mv = new ModelAndView();
    if (userServices.createUserService(newAccountDetails)) {

        System.out.println("user created successfully");
        try {
            userDetails = userDetailService.loadUserByUsername(newAccountDetails.getUsername());
            System.out.println(userDetails);
            UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(userDetails,
                    newAccountDetails.getPassword(), userDetails.getAuthorities());
            authManager.authenticate(authToken);
            if (authToken.isAuthenticated()) {
                System.out.println("New User is authenticated");
                SecurityContextHolder.getContext().setAuthentication(authToken);
                mv.setViewName("redirect:/home");
            } else {
                System.out.println("user not authenticated.");
                mv.setViewName("redirect:/");
            }
        } catch (Exception e) {
            System.err.println("e: " + e);
            mv.setViewName("redirect:/");
        }
    } else {
        System.out.println("user not created");
        mv.setViewName("redirect:/newaccount");
    }
    return mv;
}

您使用特定的
id
定义了自己的
AuthenticationManager
。但是,Spring Security对这个特定实例一无所知,仍然使用默认的
authenticationManager
。因此,对于注册和登录,您基本上使用了
AuthenticationManager的两个不同实例

要解决此问题,您需要告诉Spring Security要使用哪一个,方法是向主
http
元素添加
authentication manager ref
属性

<security:http auto-config="true" use-expressions="true" authentication-manager-ref="<your-authetnication-manager-id>">

有关更多信息,请参阅。

您是否使用完全相同的编码器?如果加载配置两次,那么加载bean两次,就会得到不同的编码器。@M.Deinum是的,我使用的是同一个编码器。在安全配置中,我声明了类型为
BCryptPasswordEncoder
的PasswordEncoder,它在身份验证提供程序中用作密码编码器。对于在插入数据库之前对用户密码进行编码,使用相同的
PasswordEncoder
。所以我认为情况并非如此。你能解释一下配置被加载两次的情况吗。我将在我的代码中检查这一点。如果在
ContextLoaderListener
DispatcherServlet
中加载配置,则会得到编码器的两个不同实例。另一件事是,您创建一个身份验证管理器,给它一个id,但不要将其连接到Spring Security。@M.Deinum No,我通过
ContextLoaderListener
加载配置一次。但是你所说的
永远不要将它连接到Spring-Security
是什么意思?我在控制器方法中使用了身份验证管理器,用于新用户的自动登录。因此,我在控制器中使用id作为
@Qualifier
的自动连线身份验证管理器。所以我认为这是我这边唯一需要的接线。至于Spring身份验证,我想它是由Spring自己负责的。不是吗。正确,但您必须告诉它您有一个自定义配置的身份验证管理器(或删除
id
属性,以便自动使用该属性)。
@RequestMapping("/createAccount")
public ModelAndView submitCreateAccount(@ModelAttribute("newAccount") NewAccountDetails newAccountDetails) {
    System.out.println(newAccountDetails);
    ModelAndView mv = new ModelAndView();
    if (userServices.createUserService(newAccountDetails)) {

        System.out.println("user created successfully");
        try {
            userDetails = userDetailService.loadUserByUsername(newAccountDetails.getUsername());
            System.out.println(userDetails);
            UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(userDetails,
                    newAccountDetails.getPassword(), userDetails.getAuthorities());
            authManager.authenticate(authToken);
            if (authToken.isAuthenticated()) {
                System.out.println("New User is authenticated");
                SecurityContextHolder.getContext().setAuthentication(authToken);
                mv.setViewName("redirect:/home");
            } else {
                System.out.println("user not authenticated.");
                mv.setViewName("redirect:/");
            }
        } catch (Exception e) {
            System.err.println("e: " + e);
            mv.setViewName("redirect:/");
        }
    } else {
        System.out.println("user not created");
        mv.setViewName("redirect:/newaccount");
    }
    return mv;
}
<security:http auto-config="true" use-expressions="true" authentication-manager-ref="<your-authetnication-manager-id>">
<security:authentication-manager id="authManager" alias="authenticationManager ">