目前的项目使用了 Spring Security 2.0.4 权限管理框架。 登录授权都由框架直接处理,所以也就产生了登录成功后 记录登录日志的需求。
找一上午资料基本都是 Spring Security 3的配置实现。最后随手拿起Spring企业应用开发详解看了一下Acegi的章节,发现原来如此。
首先看一下关键代码 ProviderManager 类中 在 doAuthentication 授权成功的时候,
创建了授权成功事件。 触发登录成功后置业务 就是 监听该事件并做相关操作。
if (result != null) {
sessionController.registerSuccessfulAuthentication(result);
[b] publishEvent(new AuthenticationSuccessEvent(result));[/b]
return result;
}
实现 授权成功 事件监听器
public class LoginSuccessListener implements ApplicationListener {
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof AuthenticationSuccessEvent) {
AuthenticationSuccessEvent authEvent = (AuthenticationSuccessEvent) event;
UserDetails user = (UserDetails) authEvent.getAuthentication().getPrincipal();
System.out.println("模拟输出用户登录日志:[" + java.util.Calendar.getInstance().getTime() + "] " + user.getUsername());
}
}
}
在Spring中加入 监听器。
<bean class="LoginSuccessListener"></bean>
至此成功写入登录日志
登录后置处理好了 紧接着 登出后置处理需求有来了!
看看登出 业务处理的关键代码吧!
详见 LogoutFilter
private String filterProcessesUrl = "/j_spring_security_logout";
private String logoutSuccessUrl;
private LogoutHandler[] handlers;
private boolean useRelativeContext;
与登出过滤器有关的主要属性
登出成功后的 转向 URL 登出处理程序 接口数组
具体的登出处理代码
if (requiresLogout(request, response)) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (logger.isDebugEnabled()) {
logger.debug("Logging out user '" + auth + "' and redirecting to logout page");
}
for (int i = 0; i < handlers.length; i++) {
handlers[i].logout(request, response, auth);
}
String targetUrl = determineTargetUrl(request, response);
sendRedirect(request, response, targetUrl);
return;
}
登出操作 其实就是 循环没有登出处理接口 然后在转向 目标URL. 那么登出处理接口都包括哪些 又是从哪里来的呢?
答案就在 LogoutBeanDefinitionParser 里
if (!StringUtils.hasText(logoutUrl)) {
logoutUrl = DEF_LOGOUT_URL;
}
builder.addPropertyValue("filterProcessesUrl", logoutUrl);
if (!StringUtils.hasText(logoutSuccessUrl)) {
logoutSuccessUrl = DEF_LOGOUT_SUCCESS_URL;
}
builder.addConstructorArg(logoutSuccessUrl);
if (!StringUtils.hasText(invalidateSession)) {
invalidateSession = DEF_INVALIDATE_SESSION;
}
ManagedList handlers = new ManagedList();
[b] SecurityContextLogoutHandler sclh = new SecurityContextLogoutHandler();[/b]
if ("true".equals(invalidateSession)) {
sclh.setInvalidateHttpSession(true);
} else {
sclh.setInvalidateHttpSession(false);
}
handlers.add(sclh);
if (rememberMeServices != null) {
[b] handlers.add(new RuntimeBeanReference(rememberMeServices));[/b]
}
builder.addConstructorArg(handlers);
所以 LogoutHandler 数组其实也就是 2个 固化了得数值,没有找到可以灵活配置 添加后置处理的地方。 (rememberMeServices 可以接受一个传入的bean id)
可以说 Logout 没有预备 事件的触发和扩展了, 要实现 Logout后置其实也很简单
修改 logout-success-url 属性, 指向一个自己需要做后置事情的地址,该地址判断用户是否确实 无授权了, 无授权即认为 登出了一次 做想过后置操作