密码登录密码错误三次等待5分钟,超过6次锁定
在controller设置登录
@Log("登录")
@PostMapping("/login")
@ResponseBody
R ajaxLogin(String username, String password, String verify, HttpServletRequest request)
{
//先查询是否锁定
boolean isLocked = userService.isLocked(username);
if (isLocked){
return R.error("账号已锁定,请联系管理员解锁");
}
//若当前累计登录失败次数大于3,先判断时间间隔
String loginTimeDiff = userService.getLoginTimeDiff(username);
if (!StringUtils.isEmpty(loginTimeDiff)){
int loginTimeLeft = 5 - Integer.parseInt(loginTimeDiff);
if ( loginTimeLeft > 0){
return R.error("当前存在登录失败记录,请 "+loginTimeLeft+" 分钟后重试");
}
}
try
{
// 从session中获取随机数
String random = (String) request.getSession().getAttribute(RandomValidateCodeUtil.RANDOMCODEKEY);
if (StringUtils.isBlank(verify))
{
return R.error("请输入验证码");
}
if (random.equals(verify))
{
} else
{
return R.error("请输入正确的验证码");
}
} catch (Exception e)
{
logger.error("验证码校验失败", e);
return R.error("验证码校验失败");
}
request.getSession().setAttribute(RandomValidateCodeUtil.RANDOMCODEKEY, "");
password = MD5Utils.encrypt(username, password);
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
Subject subject = SecurityUtils.getSubject();
try
{
subject.login(token);
//登录成功,清除登录失败信息
userService.clearLoginFail(username);
UserDO returnUser = new UserDO();
beanConverter.convert(ShiroUtils.getUser().copy(), returnUser);
returnUser.setPassword("");
logger.debug("token:"+returnUser.getToken());
return R.ok().put("token", returnUser.getToken()).put("user", returnUser);
/*
* UserDO currUser = ShiroUtils.getUser().copy(); currUser.setPassword(""); return
* R.ok().put("token", subject.getSession().getId()).put("user", currUser);
*/
} catch (AuthenticationException e)
{
logger.error(e.getMessage(), e);
return R.error(e.getMessage());
}
}
DAO层
//检查是否被锁定
boolean isLocked(String username);
//当错误次数超过三次没有到达6次时计算锁定时间还有多久
String getLoginTimeDiff(String username);
//登录成功后清除错误次数
int clearLoginFail(String username);
//记录失败次数
int loginFail(String username);
//还可以尝试次数
int tryLeft(String username);
mapper层
<select id="isLocked" resultType="boolean" >
select count(*)
from sys_user s
where login_fail_count >= 6
and username = #{value}
</select>
<select id="getLoginTimeDiff" resultType="String" >
<!-- select round((UNIX_TIMESTAMP(sysdate())-UNIX_TIMESTAMP(login_fail_time))/60) -->
select TIMESTAMPDIFF(MINUTE, login_fail_time, sysdate())
from sys_user s
where login_fail_count between 4 and 5
and username = #{value}
limit 1
</select>
<update id="loginFail">
update sys_user
set login_fail_count = ifnull(login_fail_count, 0) + 1,
login_fail_time = sysdate()
where username = #{value}
</update>
<update id="clearLoginFail">
update sys_user
set login_fail_count = 0,
login_fail_time = null
where username = #{value}
</update>
<update id="changeLoginStatus">
update sys_user
set login_fail_count = 0 ,
login_fail_time = null
where user_id = #{value}
</update>
<select id="tryLeft" resultType="int" >
select (6 - login_fail_count) from sys_user where username = #{value}
</select>
shiro层
package com.eastcom.system.shiro;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import com.eastcom.common.config.ApplicationContextRegister;
import com.eastcom.common.domain.UserDO;
import com.eastcom.common.utils.ShiroUtils;
import com.eastcom.common.utils.UtilJWT;
import com.eastcom.system.dao.UserDao;
import com.eastcom.system.service.MenuService;
public class UserRealm extends AuthorizingRealm
{
@Autowired
UserDao userMapper;
/*@Autowired
MenuService menuService;*/
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof UsernamePasswordToken;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0)
{
Long userId = ShiroUtils.getUserId();
MenuService menuService = ApplicationContextRegister.getBean(MenuService.class);
Set<String> perms = menuService.listPerms(userId);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setStringPermissions(perms);
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException
{
String username = (String) token.getPrincipal();
Map<String, Object> map = new HashMap<>(16);
map.put("username", username);
String password = new String((char[]) token.getCredentials());
UserDao userMapper = ApplicationContextRegister.getBean(UserDao.class);
// 查询用户信息
UserDO userDO = userMapper.getByUserName(map);
// 账号不存在
if (userDO == null)
{
throw new UnknownAccountException("账号不存在");
}
// 密码错误
if (!password.equals(userDO.getPassword()))
{
//记录登录失败信息
userMapper.loginFail(username);
还可以尝试次数
int tryLeft = userMapper.tryLeft(username);
if (tryLeft == 0){
throw new IncorrectCredentialsException("账号已锁定,请联系管理员解锁");
} else {
throw new IncorrectCredentialsException("密码不正确,还可以尝试 "+ tryLeft + " 次");
}
}
// 账号锁定
if (userDO.getStatus() == null || userDO.getStatus() == 0)
{
throw new LockedAccountException("账号已被禁用,请联系管理员");
}
//jwt签名制作token
String jwtToken = UtilJWT.sign(new UserDO(username));
userDO.setToken(jwtToken);
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userDO, password, getName());
return info;
}
}