代码如下
/**
* 登陆成功监听
*
*/
@Component
public class AuthenticationSuccessEventListener implements ApplicationListener<AuthenticationSuccessEvent> {
@Resource
private IUserService userService;
@Resource
private ILoginLogService loginLogService;
@Override
public void onApplicationEvent(AuthenticationSuccessEvent authenticationSuccessEvent) {
//登录成功认证
UserDetails userDetails = (UserDetails) authenticationSuccessEvent.getAuthentication().getPrincipal();
String username = userDetails.getUsername();
User newUser = new User();
newUser.setActive("true");
newUser.setUserAccounts(username);
newUser.setFailsCount(0);
userService.authenticationUpdateUser(username, newUser);
//写入登录日志
//Object details = authenticationSuccessEvent.getAuthentication().getDetails();//默认的details
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();//使用自定义的details,因为默认的Details只能获取到IP,和sessionid,才想着重写WebAuthenticationDetails
MyWebAuthenticationDetails details = (MyWebAuthenticationDetails) authentication.getDetails();
User user = userService.findUser(username);
LoginLog loginLog = new LoginLog();
loginLog.setAccount(username);
loginLog.setUserId(user.getId().toString());
loginLog.setLoginIp(details.getRemoteAddress());
loginLog.setLoginStatus("1");
loginLogService.save(loginLog);
}
}
/**
* 登陆失败监听
*
*/
@Component
public class AuthenticationFailureListener implements ApplicationListener<AuthenticationFailureBadCredentialsEvent> {
@Resource
private IUserService userService;
@Resource
private ILoginLogService loginLogService;
@Override
public void onApplicationEvent(AuthenticationFailureBadCredentialsEvent authenticationFailureBadCredentialsEvent) {
String username = authenticationFailureBadCredentialsEvent.getAuthentication().getPrincipal().toString();
User user = userService.findUser(username);
//写入登录日志
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();//使用自定义的details
MyWebAuthenticationDetails details = (MyWebAuthenticationDetails) authentication.getDetails();
LoginLog loginLog = new LoginLog();
loginLog.setAccount(username);
loginLog.setUserId(user.getId().toString());
loginLog.setLoginIp(details.getRemoteAddress());
loginLog.setLoginStatus("-1");
loginLogService.save(loginLog);
if (user != null) {
// 用户失败次数
Integer fails = user.getFailsCount();
if(fails==null){
fails = 0;
}
fails++;
// 超出失败5次,停用账户
if (fails >= 5) {
User newUser = new User();
newUser.setActive("false");
newUser.setUserAccounts(username);
newUser.setFailsCount(fails);
userService.authenticationUpdateUser(username, newUser);
throw new BaseException("您的账号已被锁定,请联系管理员...");
} else {
User newUser = new User();
newUser.setFailsCount(fails);
newUser.setUserAccounts(username);
userService.authenticationUpdateUser(username, newUser);
}
}
}
}
/**
* 退出登陆监听
*
*/
@Component
public class LogoutSuccessListener implements ApplicationListener<LogoutSuccessEvent> {
@Resource
private IUserService userService;
@Resource
private ILoginLogService loginLogService;
@Override
public void onApplicationEvent(LogoutSuccessEvent event) {
//退出登录监听
//写入登录日志
UserDetails userDetails = (UserDetails) event.getAuthentication().getPrincipal();
String username = userDetails.getUsername();
User user = userService.findUser(username);
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();//使用自定义的details
MyWebAuthenticationDetails details = (MyWebAuthenticationDetails) authentication.getDetails();
LoginLog loginLog = new LoginLog();
loginLog.setAccount(username);
loginLog.setUserId(user.getId().toString());
loginLog.setLoginIp(details.getRemoteAddress());
loginLog.setLoginStatus("0");
loginLogService.save(loginLog);
}
}
重写WebAuthenticationDetails
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import javax.servlet.http.HttpServletRequest;
public class MyWebAuthenticationDetails extends WebAuthenticationDetails {
public String getRemoteAddr() {
return remoteAddr;
}
public void setRemoteAddr(String remoteAddr) {
this.remoteAddr = remoteAddr;
}
private String remoteAddr;
public MyWebAuthenticationDetails(HttpServletRequest request) {
super(request);
remoteAddr = request.getRemoteAddr();//得到来访者的IP地址
// String requestUrl = request.getRequestURL().toString();//得到请求的URL地址
// String requestUri = request.getRequestURI();//得到请求的资源
// String queryString = request.getQueryString();//得到请求的URL地址中附带的参数
// String remoteAddr = request.getRemoteAddr();//得到来访者的IP地址
// String remoteHost = request.getRemoteHost();
// int remotePort = request.getRemotePort();
// String remoteUser = request.getRemoteUser();
// String method = request.getMethod();//得到请求URL地址时使用的方法
// String pathInfo = request.getPathInfo();
// String localAddr = request.getLocalAddr();//获取WEB服务器的IP地址
// String localName = request.getLocalName();//获取WEB服务器的主机名
}
}
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class MyWebAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest, MyWebAuthenticationDetails> {
@Override
public MyWebAuthenticationDetails buildDetails(HttpServletRequest context) {
return new MyWebAuthenticationDetails(context);
}
}
最后的问题就是如何用自定义的 MyWebAuthenticationDetailsSource 代替系统默认的 WebAuthenticationDetailsSource,很简单,我们只需要在 SecurityConfig 中稍作定义即可
@Autowired
MyWebAuthenticationDetailsSource myWebAuthenticationDetailsSource;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
...
.and()
.formLogin()
.authenticationDetailsSource(myWebAuthenticationDetailsSource)
...
}
若代码中有写到
new WebAuthenticationDetailsSource().buildDetails(request)
那一定要改为new MyWebAuthenticationDetailsSource().buildDetails(request)
不然不起效
我的代码中是写了token认证,因为忽略了.buildDetails这里没有改成我们自定义的MyWebAuthenticationDetailsSource,找了半天bug