Java “春季安全”;转发:“;指令can';t转发到登录表单

Java “春季安全”;转发:“;指令can';t转发到登录表单,java,authentication,spring-mvc,spring-security,Java,Authentication,Spring Mvc,Spring Security,用户创建帐户后,我希望自动登录该用户 我的标准表单登录由Springs filter在/postlogin上处理。如果我转到http://localhost/postlogin它尝试让我登录(失败是因为我没有包含post参数),但进行了正确的尝试 但是,如果我想以编程方式登录用户,并尝试从控制器返回:“forward:/postlogin”,我会得到404 我假设forward:指令没有通过过滤器,因此没有被UsernamePasswordAuthenticationFilter处理 如何通过编

用户创建帐户后,我希望自动登录该用户

我的标准表单登录由Springs filter在
/postlogin
上处理。如果我转到
http://localhost/postlogin
它尝试让我登录(失败是因为我没有包含post参数),但进行了正确的尝试

但是,如果我想以编程方式登录用户,并尝试从控制器返回:“forward:/postlogin”,我会得到404

我假设forward:指令没有通过过滤器,因此没有被
UsernamePasswordAuthenticationFilter
处理


如何通过编程手动引导登录?我想在用户创建新帐户后执行此操作(注册完成后应立即登录该帐户)。

我错误地阅读了另一条指南,并意识到正确的处理方法如下:

1) 在SecurityContextHolder上手动设置身份验证令牌

    UsernamePasswordWithAttributesAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( loadUserByUsername(username), password, authorities );
    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
2) 此时不要呈现页面,也不要使用forward:指令。必须使用重定向:指令

return "redirect:/accountcreated";
如果呈现页面,页面将正常加载,但会话对象将丢失,因为将创建新的j_会话id,但不会发送到浏览器mid请求,下一个请求将使用旧的j_会话id,从而失去新会话对象和身份验证

使用forward:指令将绕过身份验证过滤器,这没有好处


但是重定向:使更新的会话信息进入浏览器。

Servlet 2.4中的新过滤功能基本上减轻了过滤器只能在应用服务器实际处理请求前后在请求流中运行的限制。相反,Servlet2.4过滤器现在可以在每个调度点与请求调度器交互。这意味着,当一个Web资源将请求转发给另一个资源(例如,一个servlet将请求转发给同一应用程序中的JSP页面)时,可以在目标资源处理该请求之前运行一个过滤器。这还意味着,如果一个Web资源包含来自其他Web资源的输出或函数(例如,一个包含来自多个其他JSP页面的输出的JSP页面),Servlet2.4过滤器可以在每个包含的资源之前和之后工作

要启用该功能,您需要:

web.xml

<filter>   
    <filter-name>springSecurityFilterChain</filter-name>   
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 
</filter>  
<filter-mapping>   
    <filter-name>springSecurityFilterChain</filter-name>   
    <url-pattern>/<strike>*</strike></url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>
通过REST进行Spring身份验证(泽西岛) 为了说明@David的答案(尽可能简化):

@POST
@路径(“登录”)
公共响应登录(@FormParam(“登录”)字符串登录,@FormParam(“通过”)字符串通过)
{
如果(您的检查(登录,通过))
{
列表权限=新建ArrayList();
添加(新的SimpleGrantedAuthority(“角色用户”);
Authentication auth=新用户名PasswordAuthenticationToken(登录、通过、授权);
SecurityContextHolder.getContext().setAuthentication(auth);
//重要提示:请勿在响应正文中传递任何数据
//显示空200页(适用于REST客户端)
返回Response.ok().build();
//或重定向到您的主页(用于web UI)
return Response.temporaryRedirect(新URI(“/homepage/”).build();
}
其他的
{
返回Response.status(status.UNAUTHORIZED).build();
}
}

这有多脏?嗨@David正在就此事联系你
return "forward:/login?j_username=" + registrationModel.getUserEmail()
    + "&j_password=" + registrationModel.getPassword();
@POST
@Path("login")
public Response login(@FormParam("login") String login, @FormParam("pass") String pass)
{
    if (yourCheck(login, pass))
    {
        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
        Authentication auth = new UsernamePasswordAuthenticationToken(login, pass, authorities);
        SecurityContextHolder.getContext().setAuthentication(auth);

        // IMPORTANT: Do not pass any data in the response body

        // show empty 200 page (suitable for REST clients)
        return Response.ok().build();
        // or redirect to your home page (for web UI)
        return Response.temporaryRedirect(new URI("/homepage/")).build();
    }
    else
    {
        return Response.status(Status.UNAUTHORIZED).build();
    }
}