package cn.exrick.xboot.core.config.security.jwt;
|
|
import cn.exrick.xboot.core.common.exception.LoginFailLimitException;
|
import cn.exrick.xboot.core.common.redis.RedisTemplateHelper;
|
import cn.exrick.xboot.core.common.utils.ResponseUtil;
|
import cn.exrick.xboot.core.config.properties.XbootTokenProperties;
|
import cn.hutool.core.util.StrUtil;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.DisabledException;
|
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
import org.springframework.stereotype.Component;
|
|
import javax.servlet.ServletException;
|
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletResponse;
|
import java.io.IOException;
|
import java.util.concurrent.TimeUnit;
|
|
/**
|
* @author Exrickx
|
*/
|
@Slf4j
|
@Component
|
public class AuthenticationFailHandler extends SimpleUrlAuthenticationFailureHandler {
|
|
@Autowired
|
private XbootTokenProperties tokenProperties;
|
|
@Autowired
|
private RedisTemplateHelper redisTemplate;
|
|
@Override
|
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
|
|
if (e instanceof UsernameNotFoundException || e instanceof BadCredentialsException) {
|
String username = request.getParameter("username");
|
recordLoginTime(username);
|
String key = "loginTimeLimit:" + username;
|
String value = redisTemplate.get(key);
|
if (StrUtil.isBlank(value)) {
|
value = "0";
|
}
|
//获取已登录错误次数
|
int loginFailTime = Integer.parseInt(value);
|
int restLoginTime = tokenProperties.getLoginTimeLimit() - loginFailTime;
|
log.info("用户" + username + "登录失败,还有" + restLoginTime + "次机会");
|
if (restLoginTime <= 3 && restLoginTime > 0) {
|
ResponseUtil.out(response, ResponseUtil.resultMap(false, 500, "用户名或密码错误,还有" + restLoginTime + "次尝试机会"));
|
} else if (restLoginTime <= 0) {
|
ResponseUtil.out(response, ResponseUtil.resultMap(false, 500, "登录错误次数超过限制,请" + tokenProperties.getLoginAfterTime() + "分钟后再试"));
|
} else {
|
ResponseUtil.out(response, ResponseUtil.resultMap(false, 500, "用户名或密码错误"));
|
}
|
} else if (e instanceof DisabledException) {
|
ResponseUtil.out(response, ResponseUtil.resultMap(false, 500, "账户被禁用,请联系管理员"));
|
} else if (e instanceof LoginFailLimitException) {
|
ResponseUtil.out(response, ResponseUtil.resultMap(false, 500, ((LoginFailLimitException) e).getMsg()));
|
} else {
|
ResponseUtil.out(response, ResponseUtil.resultMap(false, 500, "登录失败,其他内部错误"));
|
}
|
}
|
|
/**
|
* 判断用户登陆错误次数
|
*/
|
public boolean recordLoginTime(String username) {
|
|
String key = "loginTimeLimit:" + username;
|
String flagKey = "loginFailFlag:" + username;
|
String value = redisTemplate.get(key);
|
if (StrUtil.isBlank(value)) {
|
value = "0";
|
}
|
// 获取已登录错误次数
|
Integer loginFailTime = Integer.parseInt(value) + 1;
|
redisTemplate.set(key, loginFailTime.toString(), tokenProperties.getLoginAfterTime(), TimeUnit.MINUTES);
|
if (loginFailTime >= tokenProperties.getLoginTimeLimit()) {
|
redisTemplate.set(flagKey, "fail", tokenProperties.getLoginAfterTime(), TimeUnit.MINUTES);
|
return false;
|
}
|
return true;
|
}
|
}
|