SpringSecurity 踩坑了,遇到了无限循环认证的问题。具体是认证失败后,我想转发到登录页面,并且返回一些提示信息,结果就踩坑了。

我是 SpringMVC 4.1.7,SpringSecurity 4.0.4

这是 xml 配置

<security:form-login login-page="/admin/login"
    login-processing-url="/admin/login"
    username-parameter="username"
    password-parameter="password" />

我配置了登录页面是 /admin/login,登录表单提交的地址是 /admin/login

当认证失败时,SpringSecurity 默认的失败处理器是 SimpleUrlAuthenticationFailureHandler 类,它默认采用重定向的方式,重定向到 login-page 设置的 URL,也就是重定向到登录页面。

然后我想在认证失败后,根据失败信息返回给客户端一些友好的提示。但是采用重定向的方式,我的提示信息就丢失了,客户端无法收到提示信息。所以我想将重定向的方式改成转发的方式。

这是我改后的 xml 配置

<security:form-login login-page="/admin/login"
    login-processing-url="/admin/login"
    username-parameter="username"
    password-parameter="password" 
    authentication-failure-handler-ref="simpleUrlAuthenticationFailureHandler"/>
    
<bean id="simpleUrlAuthenticationFailureHandler" 
    class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
    <constructor-arg name="defaultFailureUrl" value="/admin/login"></constructor-arg>
    <property name="useForward" value="true" />
</bean>

我手动配置了 SimpleUrlAuthenticationFailureHandler 类,将 useForward 属性设置为 true,表示启用转发的方式。defaultFailureUrl 属性设置为 /admin/login,表示转发到登录页面。这里说明一下,defaultFailureUrl 属性是认证失败后,重定向或者转发的 URL。如果不设置,默认是 login-page 的值。

重启后发现果然采用了转发的方式,但是这样又遇到了一个问题,转发到 /admin/login 之后,又进入了认证的方法,认证失败后又转发到 /admin/login,然后又进入认证的方法,一直无限循环下去。。。

仔细想了一下,应该是我的配置出了问题

我配置的登录页是 /admin/login,请求方法是 GET,登录表单提交的地址是 /admin/login,请求方式是 POST,也就是说登录页面和登录提交的地址都是同一个,唯一的区别是请求方法不同。

转发之前的地址是 admin/login,请求方法是 POST,由于转发是同一个请求,它的请求方法不会变,所以转发的请求方法也是 POST。又由于我设置的转发 URL 是admin/login,所以转发之后又会进入认证的方法,相当于重新提交了登录表单。所以无论如何都不会进入到登录页面,所以就会造成无限循环。

这里也特别说明一下,为什么默认的重定向不会造成无限循环。因为重定向是客户端的行为,相当于客户端重新发起请求,并且重定向肯定是 GET 请求,所以会正常进入到登录页面,不会造成无线循环。

最后的 xml 配置如下:

<security:form-login login-page="/admin/login.jsp"
    login-processing-url="/admin/login"
    username-parameter="username"
    password-parameter="password" 
    authentication-failure-handler-ref="simpleUrlAuthenticationFailureHandler"/>
    
<bean id="simpleUrlAuthenticationFailureHandler" 
    class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
    <constructor-arg name="defaultFailureUrl" value="/admin/login.jsp"></constructor-arg>
    <property name="useForward" value="true" />
</bean>

结论:login-pagelogin-processing-url 最好不要设置相同的 URL

原文链接:https://miansen.wang/2020/03/17/2/