Spring security“forward:”指令无法转发到登录表单

Posted

技术标签:

【中文标题】Spring security“forward:”指令无法转发到登录表单【英文标题】:Spring security "forward:" directive can't forward to login form 【发布时间】:2011-06-17 00:00:22 【问题描述】:

用户创建帐户后,我想自动登录该用户。

/postlogin 上的 Springs 过滤器正在处理标准表单登录。如果我转到http://localhost/postlogin,它会尝试让我登录(失败,因为我没有包含 post 参数),但会做出正确的尝试。

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

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

如何以编程方式手动诱导登录?我想在用户创建一个新帐户后执行此操作(他们应该在完成注册后立即登录该帐户)。

【问题讨论】:

【参考方案1】:

我误读了另一篇指南,并意识到处理此问题的正确方法如下:

1) 在 SecurityContextHolder 上手动设置 Authentication token

    UsernamePasswordWithAttributesAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( loadUserByUsername(username), password, authorities );
    SecurityContextHolder.getContext().setAuthentication(authenticationToken);

2) 不要此时渲染页面或使用 forward: 指令。您必须使用 redirect: 指令。

return "redirect:/accountcreated";

如果您渲染一个页面,该页面将正常加载,但会话对象将丢失,因为将创建一个新的 j_session_id 但不会将其发送到浏览器中间请求,并且下一个请求将使用旧的 j_session_id,丢失新的会话对象和身份验证。

使用 forward: 指令会绕过身份验证过滤器,不好。

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

【讨论】:

这有多脏? 嗨@David 想就这个***.com/questions/64181212/…与你联系【参考方案2】:

Servlet 2.4中新增的过滤特性,基本缓解了过滤器只能在应用服务器实际处理请求前后的请求流中操作的限制。相反,Servlet 2.4 过滤器现在可以在每个分派点与请求分派器交互。这意味着当 Web 资源将请求转发到另一个资源(例如,servlet 将请求转发到同一应用程序中的 JSP 页面)时,可以在目标资源处理请求之前运行过滤器。这也意味着如果一个 Web 资源包含来自其他 Web 资源的输出或功能(例如,一个 JSP 页面包括来自多个其他 JSP 页面的输出),Servlet 2.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>

注册控制器

return "forward:/login?j_username=" + registrationModel.getUserEmail()
    + "&j_password=" + registrationModel.getPassword();

【讨论】:

【参考方案3】:

通过 REST (Jersey) 进行 Spring 身份验证

只是为了说明@David的答案(尽可能简化):

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

【讨论】:

以上是关于Spring security“forward:”指令无法转发到登录表单的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security4.1.3实现拦截登录后向登录页面跳转方式(redirect或forward)返回被拦截界面

Spring Security4.1.3实现拦截登录后向登录页面跳转方式(redirect或forward)返回被拦截界面

spring 转发forward和重定向redirect

Spring Boot 2.3.2 server.forward-headers-strategy=framework 重定向到方案 http 而不是 https

Spring 中的 spring-security-oauth2 与 spring-security-oauth2-core

Spring mvc / security:从spring security中排除登录页面