2010-04-05 137 views
19

我想跟踪用户何时登录到我的应用程序。我有一些代码,我想在用户通过身份验证后立即执行。问题是,我无法弄清楚应该在哪里调用。春季安全有没有办法在认证后调用方法?Spring-Security:认证后的调用方法

回答

4

只需编写您自己的SpringSecurityFilter并在调用身份验证提供程序后立即将其添加到过滤器链中。

package my.code; 

public class AuditFilter extends SpringSecurityFilter { 

    public void doFilterHttp(...) throws ... { 
     {application code to run before request is processed} 
     chain.doFilter(...); 
     {application code to run after request has fully processed} 
    } 
} 
配置中的XML

然后(无论你设置安全过滤器链)加上这样一行:

<bean id="auditFilter" class="my.code.AuditFilter> 
    <security:custom-filter position="LAST"/> <-- you can change the position 
</bean> 
+0

请注意,SpringSecurityFilter改为通用Spring的web GenericFilterBean Spring Security的3 – 2013-01-22 13:51:16

11

最好的方法是创建一个应用程序侦听器并使用spring安全上下文进行注册。

import org.springframework.context.ApplicationListener; 
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent; 

public class AuthenticationSuccessListener implements ApplicationListener<InteractiveAuthenticationSuccessEvent> { 

    @Override 
    public void onApplicationEvent(InteractiveAuthenticationSuccessEvent event) { 
     System.out.println("User Logged In"); 

    } 
} 

确保添加上面的类弹簧security.xml文件作为一个bean。还有很多其他类型的安全事件侦听器可以侦听,请检查类型层次结构以查看可以侦听的所有安全事件类型的列表。

+0

视情况而定,但这通常是我的出路。如果您需要创建身份验证事件的副作用,请使用ApplicationListener。如果您需要指定如何处理认证过程,请使用处理程序。在这种情况下,“跟踪认证行动”,我会去参加这个活动,它更像是一种副作用。 – wooki 2015-10-11 22:24:29

30

可能会是有用的人...... 在Spring 3的情况下,配置安全:

<security:http use-expressions="true" auto-config="true"> 
    <security:intercept-url pattern="..."/> 
    <security:form-login 
      authentication-failure-handler-ref="authFailureHandler" 
      authentication-success-handler-ref="authSuccessHandler"/> 
    <security:logout success-handler-ref="logoutSuccessHandler" 
      invalidate-session="true"/> 
    <security:session-management session-fixation-protection="newSession"/> 
</security:http> 

<bean id="authFailureHandler" class="mine.AuthenticationFailureHandlerImpl"/> 
<bean id="authSuccessHandler" class="mine.AuthenticationSuccessHandlerImpl"/> 
<bean id="logoutSuccessHandler" class="mine.LogoutSuccessHandlerImpl"/> 

和实施适当的类:

public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler { 

    @Override 
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { 
     //do what you want with 
     response.getOutputStream().write("success".getBytes()); 
    } 
} 

您可以通过该XML链接资源配置。

+1

好东西!感谢您的身份验证 - 成功处理程序 - 参考号 – 2013-01-23 09:30:50

+0

如果我想添加一个小动作,然后继续正常处理,它将如何? – DiegoSahagun 2015-12-10 14:05:35

6

如果您想继续默认行为,但只是在执行自己的业务逻辑之间,您可能会在返回之前extend SimpleUrlAuthenticationSuccessHandler并调用super.onAuthenticationSuccess(request, response, authentication);。更多详情,请参阅https://stackoverflow.com/a/6770785/418439

+0

这就是我通常所做的事情,而且我建议您也这么做,如果您不需要在原始实现中更改任何内容,只需要附加功能即可。我创建了一个ChainAuthenticationSuccessHandler,然后它会调用我的自定义处理程序和一个像SimpleUrlAuthenticationSuccessHandler这样的现有处理程序。我发现它比扩展Spring的课程更可靠和干净。我想你也可以在原始处理程序的顶部创建某种装饰器类以避免继承,但是链式解决方案对我更有吸引力。 – wooki 2015-10-11 22:34:21

1

Authentication没有一定意味着成功登录。用户可以通过例如双向SSL(X.509证书)成功进行身份验证,如果会话并发管理设置为max-sessions="1",并且这是第二次并发登录尝试,Spring Security仍会将您重定向到错误页面。如果你的设置很简单,没有会话并发控制,你可以假设login = authentication用于所有实际目的。否则,如果您有,例如,逻辑记录每个登录数据库中的每个,您将不得不在实际登录点处调用此逻辑,而不是在身份验证点。做到这一点的一种方法(绝不是最佳的,受我对Spring Security框架理解有限),要实现你自己的ConcurrentSessionControlAuthenticationStrategy(点击here获取源代码),并将它注入到您的Spring Security(3.2及更高版本)的CompositeSessionAuthenticationStrategy中,配置XML:

<http> 
    . 
    . 
    <session-management session-authentication-strategy-ref="sas" /> 
    . 
    . 
</http> 
. 
. 
<beans:bean id="sas" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy"> 
    <beans:constructor-arg> 
     <beans:list> 
      <beans:bean class="path.to.my.implementation.of.ConcurrentSessionControlAuthenticationStrategy"> 
       <beans:constructor-arg ref="sessionRegistry"/> 
       <beans:property name="maximumSessions" value="1"/> 
       <beans:property name="exceptionIfMaximumExceeded" value="true"/> 
      <beans:bean> 
      <beans:bean class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy"/> 
      <beans:bean class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy"/> 
       <beans:constructor-arg ref="sessionRegistry"/> 
      </beans:bean> 
     </beans:list> 
    </beans:constructor-arg> 
</beans:bean> 

<beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl"/> 

我宁愿注入定制PostLogin处理程序进入该框架的ConcurrentSessionControlAuthenticationStrategy,而不是复制粘贴,从它变成我的自定义ConcurrentSessionControlAuthenticationStrategy并进行修改时,但我不知道的方式目前要做到这一点。

可以找到更完整的配置示例here

2

如果你想避免读取所有的线程:具有注释&多一点解释策划版本:

import org.springframework.context.ApplicationListener; 
import org.springframework.security.authentication.event.AuthenticationSuccessEvent; 
import org.springframework.security.core.userdetails.User; 
import org.springframework.stereotype.Component; 

@Component 
public class LoginSuccessListener implements ApplicationListener<AuthenticationSuccessEvent{ 

    @Override 
    public void onApplicationEvent(AuthenticationSuccessEvent evt) { 

     // if you just need the login 
     String login = evt.getAuthentication().getName(); 
     System.out.println(login + " has just logged in"); 

     // if you need to access full user (ie only roles are interesting -- the rest is already verified as login is successful) 
     User user = (User) evt.getAuthentication().getPrincipal(); 
     System.out.println(user.getUsername() + " has just logged in"); 

    } 
}