解决Spring Security 登录(登出)成功 后置处理的业务

目前的项目使用了 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 属性, 指向一个自己需要做后置事情的地址,该地址判断用户是否确实 无授权了, 无授权即认为 登出了一次 做想过后置操作



你可能感兴趣的:(security 后置处理)