目前我们的项目中使用基于基于FilterSecurityInterceptor过滤链对系统资web资源进行保护,升级ss3后发现原来使用的filter的SSO登录方式不再适用。
昨天研究FilterSecurityInterceptor源码发现其实这个实现其实很简单,发出来分享下。
分析:
我们一般在过滤链时使用实现AbstractSecurityInterceptor构成整个链,AbstractSecurityInterceptor的机制可以分为几个步骤:
1、事前评估--检查请求资源是否为受保护资源;
2、查找认证--当前安全上下文中是否是通过安全认证的用户;
3、认证用户--查找认证时认证失败会抛出异常来重新认证用户;
4、实施投票--获取认证用户后检查是否有资源权限。
...
原来基于表单提交认证的方式就是在认证失败后跳转认证页面进行用户认证的,我们现在要加入SSO方式直接在认证用户阶段将SSO用户加入即可。
根据源码,认证用户环节在AbstractSecurityInterceptor事前评估内部方法中,其主要访问对象为安全上下文中的Authentication对象。
因此我们在事前评估前将安全上下文中的Authentication对象替换为SSO用户。实现如下:
public void invoke(FilterInvocation filter) throws IOException, ServletException {
// 加入对SSO方式登录的判断,并进行SSO登录
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication.getPrincipal()==null||"anonymousUser".equals(authentication.getPrincipal())) {
String ssoUser = filter.getHttpRequest().getHeader("iv-user");
String ssoPassword = filter.getHttpRequest().getHeader("iv-password");
if(StringUtils.isNotBlank(ssoUser)){
authentication = new UsernamePasswordAuthenticationToken(ssoUser, ssoPassword);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
InterceptorStatusToken token = super.beforeInvocation(filter);
filter.getChain().doFilter(filter.getRequest(), filter.getResponse());
super.afterInvocation(token, null);
}
增加这个处理后只需在用户认证的authenticationManager认证判断通过验证。
PS:这里只是一个简单的实现,真实环境中这样的实现是不安全的,在SSO方式登录判断环节需增加一系列的安全判断多次握手匹配。