【问题标题】:remember-me and authentication-success-handler记住我和身份验证成功处理程序
【发布时间】:2012-07-19 12:34:54
【问题描述】:

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

下面是我的 spring 安全配置。

<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。

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

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

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

【问题讨论】:

  • spring security的版本是多少? 3.1 还是 3.0?您是否将属性 alwaysUseDefaultTargetUrl 设置为 true?
  • 我正在使用 Spring Security 3.1。是的,我使用了属性 alwaysUseDefaultTargetUrl。如果我将此设置为 true,那么它总是将我重定向到 / 两种情况(记住我和正常登录)
  • 我在问你版本,因为这个问题发生在我身上:我的 spring xml 文件使用 3.1 命名空间,但 pom.xml 仍然使用 3.0...对我来说糟糕的一天.. . :) 那么为什么需要自定义成功处理程序?
  • 我正在使用自定义成功处理程序为登录的用户初始化某些数据,并在会话中存储一些数据。我也在管理多个标签访问using
  • 你能把 maxSessions 改成大于 1 吗?此外,打开 Spring Security 的调试级别日志记录

标签: spring spring-security


【解决方案1】:

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

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

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

【讨论】:

  • 谢谢卢克,我对你提到的表单登录重定向和记住我直接身份验证有同样的疑问。让我将我的实现从 SavedRequestAwareAuthenticationSuccessHandler 更改为 SimpleUrlAuthenticationSuccessHandler 并检查。
  • 不,那也行不通。 SimpleUrlAuthenticationSuccessHandler 重定向到一个 URL。只需创建自己的实现 AuthenticationSuccessHandler 的 bean 并将其用于记住我。
  • 这也不起作用,也没有重定向到任何 URL,或者没有从服务器重新调整任何内容。
  • @William 仍然存在问题,已发布到 spring 但没有确认的解决方案。
  • 你想要什么是不可能的,因为如果你提供一个 successHandler 过滤器将返回并且不调用 chain.doFilter(request, response);尝试使用 AuthenticationApplicationListener 代替 kabak 提到的。
【解决方案2】:

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

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

@Component
class AuthenticationApplicationListener implements ApplicationListener<InteractiveAuthenticationSuccessEvent> {

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

}

在rememberMe 上使用AuthenticationSuccessHandler 的自定义实现会导致问题。看看RememberMeAuthenticationFilter 中的流程。如果使用successHandler,则绕过过滤器链

【讨论】:

  • 是否可以访问 Listener 中的会话?
【解决方案3】:

您应该为登录表单和记住我实现不同的身份验证成功处理程序。 如果你想在 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);
}

【讨论】:

    【解决方案4】:

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

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

    这里是一个例子(顺便说一句:@EventListener 自 Spring Security 4.2 起使用 - 如果您使用早期版本,请通过实现 ApplicationListener&lt;InteractiveAuthenticationSuccessEvent&gt; 执行以下操作):

    @Component
    public class AuthenticationApplicationListener {
    
        @EventListener
        public void handleInteractiveAuthenticationSuccess(InteractiveAuthenticationSuccessEvent event) {
            if (RememberMeAuthenticationToken.class.isAssignableFrom(event.getAuthentication().getClass())) {
                .... do some stuff
        }
      }
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-02
      • 1970-01-01
      • 2016-12-03
      • 1970-01-01
      • 2013-05-30
      • 2021-08-12
      相关资源
      最近更新 更多