11

我有登录成功和重定向到页面的奇怪问题。

下面是我的弹簧安全配置。

<http auto-config="true" use-expressions="true">
    <intercept-url pattern="/login.hst**" access="anonymous or authenticated" />
    <intercept-url pattern="/**/*.hst" access="authenticated" />
    <form-login login-page="/login.hst"
        authentication-failure-url="/login.hst?error=true"
        authentication-success-handler-ref="loginSucessHandler" />
    <logout invalidate-session="true" logout-success-url="/home.hst"
        logout-url="/logout.hst" />
    <remember-me key="jbcpHaverERP" authentication-success-handler-ref="loginSucessHandler"/>
    <session-management>
    <concurrency-control max-sessions="1" />
</session-management>
</http>

LoginSuessHandler 类:

@Service
public class LoginSucessHandler extends
        SavedRequestAwareAuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
            HttpServletResponse response, Authentication authentication)
            throws ServletException, IOException {
            ...
        super.setUseReferer(true);
        super.onAuthenticationSuccess(request, response, authentication);
    }

}

现在成功重定向到请求页面的问题。如果我直接引用任何安全 url,spring 会将我重定向到登录页面并成功登录到原始请求的链接。但是,如果用户之前选择了记住我,然后关闭浏览器并现在请求直接 URL,则这不起作用,他正在被正确验证,而不是将他重定向到请求的页面弹簧重定向到 /。我检查了日志和一些 spring 源代码,发现它无法确定目标 url。

我试图设置参考,但参考值为空。但是我注意到一件奇怪的事情,在 spring 安全配置中,如果我从 remember-me 配置中删除 authentication-success-handler ,那么它就可以工作。

    <remember-me key="jbcpHaverERP" authentication-success-handler-ref="loginSucessHandler"/>

无法弄清楚问题。表单登录和记住我的身份验证成功处理程序实现是否需要不同?

4

4 回答 4

15

记住我与表单登录的不同之处在于,身份验证发生在用户提出的实际请求期间。对于表单登录,用户必须首先被重定向到登录页面,提交登录表单,然后他们被重定向到原始目标(通常缓存在会话中)。所以 form-login 需要重定向,而 remember-me 不需要。使用记住我的请求,可以对用户进行身份验证,并且允许请求​​继续进行而无需任何干预。

an 的主要目的AuthenticationSuccessHandler是在身份验证后控制导航流程,因此您通常根本不会将其与 remember-me 一起使用。使用SavedRequestAwareAuthenticationSuccessHandler不是一个好主意,因为没有可用的已保存请求。如果没有保存的请求,则默认情况下它将执行重定向到“/”,如您所见。

如果您只想在记住我登录期间添加一些功能,那么您可以AuthenticationSuccessHandler直接实现接口,而无需执行重定向或转发。正如我上面解释的,你不能对 form-login 使用相同的实现,因为当前请求是提交登录表单(通常是到 URL j_spring_security_check),而不是对应用程序中 URL 的请求。所以你需要一个重定向表单登录。

于 2012-07-26T22:14:21.060 回答
13

您宁愿使用ApplicationListener并查找事件InteractiveAuthenticationSuccessEvent

InteractiveAuthenticationSuccessEvent有一个属性generatedBy将成为过滤器,即UsernamePasswordAuthenticationFilter(表单登录)和RememberMeAuthenticationFilter(记住我的登录)

@Component
class AuthenticationApplicationListener implements ApplicationListener<InteractiveAuthenticationSuccessEvent> {

  @Override
  void onApplicationEvent(InteractiveAuthenticationSuccessEvent event) {
    //do something
  }

}

使用AuthenticationSuccessHandleron rememberMe 的自定义实现会导致问题。看看里面的流量RememberMeAuthenticationFilter。如果successHandler使用 ,则绕过过滤器链

于 2013-05-16T14:58:37.720 回答
3

使用 anAuthenticationSuccessHandler不起作用。如另一个答案所述,将绕过弹簧安全过滤器链!
有效的是使用ApplicationListener- 作为另一个答案也建议。但是要找出,如果您的用户通过记住我的身份验证,那么使用的想法InteractiveAuthenticationSuccessEvent.getGeneratedBy()是行不通的:getGeneratedBy返回Class<T>,这意味着通用。因此,在运行时您无法确定 ifT是否为RememberMeAuthenticationFilter.

什么对我有用:使用InteractiveAuthenticationSuccessEvent.getAuthentication().

这是一个示例(顺便说一句:@EventListener自 Spring Security 4.2 起使用 - 如果您使用早期版本,请通过 implementation 执行以下操作ApplicationListener<InteractiveAuthenticationSuccessEvent>):

@Component
public class AuthenticationApplicationListener {

    @EventListener
    public void handleInteractiveAuthenticationSuccess(InteractiveAuthenticationSuccessEvent event) {
        if (RememberMeAuthenticationToken.class.isAssignableFrom(event.getAuthentication().getClass())) {
            .... do some stuff
    }
  }
 }
于 2016-12-07T15:44:03.300 回答
1

您应该为登录表单和记住我实现不同的身份验证成功处理程序。如果你想在 remeber-me 处理程序中执行重定向,你可以使用 SimpleUrlAuthenticationSuccessHandler 并设置 DefaultTargetUrl。

public class RememberMeAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
    Authentication authentication) throws IOException, ServletException {

    // ...

    super.setAlwaysUseDefaultTargetUrl(true);
    super.setDefaultTargetUrl(request.getRequestURL().toString());
    super.onAuthenticationSuccess(request, response, authentication);
}
于 2014-07-26T00:36:16.407 回答