`
野之皇
  • 浏览: 21064 次
  • 性别: Icon_minigender_1
  • 来自: 韶关
社区版块
存档分类
最新评论

成功登录系统的后置处理(1)

阅读更多

成功登录系统的后置处理

一般的业务系统在用户登录成功后,需要在数据库中记录一条相应的用户登录日志。我们可以通过Acegi提供的事件机制来完成这一功能。当用户身份认证成功后,Acegi会产生一个AuthenticationSuccessEvent事件,该事件是org.springframework.context.ApplicationEvent的子类,所以AuthenticationSuccessEvent是一个Spring容器事件。我们可以定义一个监听器响应该事件以记录用户登录日志,请看LoginSuccessListener的代码:

代码清单 9 LoginSuccessListener

package com.baobaotao.service;
import org.acegisecurity.Authentication;
import org.acegisecurity.event.authentication.AuthenticationSuccessEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
public class LoginSuccessListener implements ApplicationListener {
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof AuthenticationSuccessEvent) {①判断是否是认证成功的事件
AuthenticationSuccessEvent authEvent = (AuthenticationSuccessEvent)event;
Authentication auth = authEvent.getAuthentication();
String userName = auth.getName();
②这里,我们仅通过一条输出信息的语句模拟记录登录日志的操作
System.out.println("模拟记录用户["+userName+"]成功登录日志...");
}
}
} 

 

通过扩展Spring的ApplicationListener接口定义一个监听Acegi AuthenticationSuccessEvent事务的监听器。在实际系统中,你可以使用DAO替换②处的逻辑,执行记录用户登录日志的操作。在编写好LoginSuccessListener后,剩下的工作就是在Spring容器中声明这个监听器,仅需要一行简单的配置就可以了:

<bean class="com.baobaotao.service.LoginSuccessListener"/> 

 

 

这样,当用户登录并通过了Acegi的用户身份认证后, LoginSuccessListener监听器的onApplicationEvent()方法将接收到AuthenticationSuccessEvent事件。

在多个请求之间共享SecurityContext
我们知道SecurityContext保持着Acegi框架重要的Authentication对象,而SecurityContext保存在SecurityContextHolder中。然而SecurityContextHolder只为SecurityContext对象提供请求线程范围内的生命周期。也就是说,当一个登录认证请求结束后,用户相关的SecurityContext对象将从SecurityContextHolder中清除了。当用户发起下一个请求时,又必须重新进行身价认证,如何使SecurityContext在Session级别中进行共享呢?

Acegi通过HttpSessionContextIntegrationFilter解决这个问题,当一个请求到达时,它尝试从Session中获取用户关联的SecurityContext并将其放入到SecurityContextHolder中,当请求结束时,HttpSessionContextIntegrationFilter又将SecurityContext转存到HttpSession中。这样,Acegi就通过HttpSessionContextIntegrationFilter将SecurityContext对象在请求级的SecurityContextHolder和Session级的HttpSession中摆渡,从而保证SecurityContext可以在多个请求之间共享。

在过滤器链中,HttpSessionContextIntegrationFilter必须位于认证处理过滤器之前,这样认证处理过滤器当发现SecurityContextHolder中已经拥有和用户关联的经过认证的Authentication时,就可以短路掉用户身份认证的步骤:

代码清单 10 applicationContext-acegi-plugin.xml

通过HttpSession转存请求之间的SecurityContext

<bean id="filterChainProxy"
class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
…
/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter ①
</value>
</property>
</bean>
<bean id="httpSessionContextIntegrationFilter" ②通过HttpSession转存SecurityContext的过滤器
class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"/>
… 

 

在①处,我们将httpSessionContextIntegrationFilter放置在authenticationProcessingFilter之前。如果用户还未通过身份认证,httpSessionContextIntegrationFilter在HttpSession中找不到对应的SecurityContext,这时authenticationProcessingFilter将启用正常的认证流程。反之,如果已经通过了身份认证,SecurityContext将直接从HttpSession中获取。

分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

Global site tag (gtag.js) - Google Analytics