通常而言,使用spring security来进行身份验证的同时,还需要进行一些附加操作,注入校验码检查,session中安全信息的检查,用户最后登录流水记录等。不排除这些在ss执行完成后进入某个页面,在其渲染类中可以实现,但是这样的方式从设计角度而言,是拆分了登录的整个独立过程,是属于单纯的实现功能而实现功能。
所以这里我们就需要封装底层spring security过滤器,以实现自己需求的过滤器。
先说第一个常用需求:用户登录的时候检查校验码,并且记录用户的登录流水。
这里的重点在于将这两个逻辑代码切入到过滤器中,我们知道表单方式的身份检查过滤器是AuthenticationProcessingFilter,所以这里我们需要继承其并重写其中的attemptAuthentication(HttpServletRequest request)方法。已达到我们的目的。
/**
* 这里在进行一次是否通过了校验码的检查主要是防止一些表单篡改绕过校验码检查的情况
*/
Object isCheckSuccess = session.getAttribute(SESSION_KEY.SESSION_IS_CHECK_OK.getKey());
if(null == isCheckSuccess){
logger.error("can not login because no_is_ck_ok is null !");
throw new BadCredentialsException("can not login because no_is_ck_ok is null !");
} else if(!(Boolean)isCheckSuccess){
logger.error("check code failed !");
throw new BadCredentialsException("check code failed !");
}
// 判断是否校验成功,如果成功,则修改最后登录信息
Authentication authentication = super.attemptAuthentication(request);
if(null != authentication){
Object principal = null == authentication ? null : authentication.getPrincipal();
if(null == principal){
return null;
}
// 修改最后登录信息
String userName = "";
if (principal instanceof NorUserDetails) {
NorUserDetails nud = (NorUserDetails)principal;
userName = nud.getUserId();
} else if(principal instanceof org.springframework.security.userdetails.User){
org.springframework.security.userdetails.User user = (org.springframework.security.userdetails.User)principal;
userName = user.getUsername();
}
String ip = request.getRemoteAddr();
String mac = "";
norCustomerManager.modifyLastLoginInfo(userName, ip, mac);
}
return aut
注意上面的代码中,对于校验码的检查已经在异步请求中执行过了,只是有一个二次安全检查,其原理是相同的。
然后我们可以配置自己的过滤器:
同样的,对于第二个常用需求,就是用户注销后,清空session中的一些附加的重要信息,这里可以使用继承LogoutFilter,并重写其中的doFilterHttp(HttpServletRequest request,HttpServletResponse response, FilterChain chain)方法
这里做的是清空了session中的用户名称和用户id,为什么要这样做呢,因为在此之前我们在session中放入了上述两个值,为了那些配置了不使用ss过滤器而导致无法使用安全上下文取信息的页面。
同样的配置