spring boot 实现密码连续输入错误5次,限制十分钟内不能进行登录
我们要实现的就是,密码连续输入错误5次,就限制用户十分钟不能进行登录。
大致的流程图
数据库设计如下
DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(64) NOT NULL COMMENT '用户名', `password` varchar(255) NOT NULL COMMENT '用户密码', `email` varchar(64) DEFAULT NULL COMMENT '用户邮箱', `status` int(11) NOT NULL DEFAULT '0' COMMENT '状态,1代表删除', `admin` int(11) NOT NULL DEFAULT '0' COMMENT '是否是管理员,1代表是管理员', `iphone` varchar(20) DEFAULT NULL COMMENT '用户手机号', `workid` int(11) NOT NULL DEFAULT '0', `token` varchar(255) DEFAULT NULL, `errornum` int(2) NOT NULL DEFAULT '0', `freeze` int(2) NOT NULL DEFAULT '0', `freezetime` datetime DEFAULT NULL, PRIMARY KEY (`id`,`username`), KEY `username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=49 DEFAULT CHARSET=utf8 COMMENT='用户表';
那么我们来实现dao层
package pan.DaoObject; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; import org.hibernate.annotations.DynamicUpdate; import pan.enmus.FreezeEmus; import pan.enmus.UserEmus; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import java.io.Serializable; import java.util.Date; @Data @DynamicUpdate @Entity @JsonIgnoreProperties(value = {"hibernateLazyInitializer", "handler"}) public class User implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String username; private String password; private String email; private String iphone; private Integer status = UserEmus.UNDELETE.getCode(); private Integer admin = UserEmus.NOTADMIN.getCode(); private String token; private Date freezetime; private Integer errornum; private Integer freeze= FreezeEmus.UNDELETE.getCode(); }
对应的UserEmus
package pan.enmus; import lombok.Getter; @Getter public enum UserEmus { ADMIN(1, "管理员"), NOTADMIN(0, "非管理员"), DELETE(1, "删除"), UNDELETE(0, "正常"); private Integer code; private String message; UserEmus(Integer code, String message) { this.code = code; this.message = message; } }
FreezeEmus 为:
package pan.enmus; import lombok.Getter; @Getter public enum FreezeEmus { DELETE(1,"冻结"), UNDELETE(0,"正常"); private Integer code; private String message; FreezeEmus(Integer code, String message){ this.code=code; this.message=message; } }
那么接下来,我们就是UserRepository实现
public interface UserRepository extends JpaRepository<User, Integer> {
User findByUsername(String username);
}
里面就用到了一个通过username查找用户
那么我们接下来去实现service
@Service public class UserSericeImpl { @Autowired private UserRepository userRepository;
@Override
public User login(String username, String password) {
User user = userRepository.findByUsername(username);
if (user != null) {
if (user.getStatus().equals( UserEmus.DELETE.getCode())){
throw new PanExection(ResultEmus.USER_DELETE);
}
SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try{
try {
if(user.getFreeze().equals(FreezeEmus.DELETE.getCode())&& (new Date().getTime()-format.parse(user.getFreezetime().toString()).getTime()<6*60*1000)){
user.setErrornum(0);
userRepository.saveAndFlush(user);
throw new PanExection(ResultEmus.USER_FREE);
}
} catch (ParseException e) {
e.printStackTrace();
}
}catch (NullPointerException e){
userRepository.saveAndFlush(user);
}
Boolean b = null;
try {
b = MD5Until.checkoutpassword(password, user.getPassword());
} catch (Exception e) {
throw new PanExection(ResultEmus.EXCEPTIONS);
}
if (b) {
String key = "Plan_" + user.getUsername();
String tokned = (String) userredis(redisTemplate).opsForValue().get(key);
user.setErrornum(0);
user.setFreezetime(null);
if (tokned == null) {
Date date = new Date();
String tokne = null;
try {
tokne = MD5Until.md5(key + date.toString());
} catch (Exception e) {
throw new PanExection(ResultEmus.EXCEPTIONS);
}
String token = user.getUsername() + "_" + tokne;
user.setToken(token);
userRepository.saveAndFlush(user);
userredis(redisTemplate).opsForValue().set(key, token, 1, TimeUnit.DAYS);
return user;
} else {
userRepository.saveAndFlush(user);
return user;
}
}else {
if(user.getErrornum()>4){
user.setErrornum(user.getErrornum()+1);
user.setFreeze(FreezeEmus.DELETE.getCode());
user.setFreezetime(new Date());
userRepository.saveAndFlush(user);
throw new PanExection(ResultEmus.USER_FREE);
}else {
Integer err=user.getErrornum()+1;
user.setErrornum(err);
userRepository.saveAndFlush(user);
throw new PanExection(ResultEmus.USER_ERROR_PASSWORD);
}
}
}
throw new PanExection(ResultEmus.USER_NOT_EXIT);
}
}
我们最后去实现一个contorller类
import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.*; import pan.DaoObject.User; import pan.Form.UserForm; import pan.config.RedisConfig; import pan.converter.UserForm2User; import pan.enmus.ResultEmus; import pan.exection.PanExection; import pan.service.FileService; import pan.service.UserSerice; import pan.untils.RedisDbInit; import pan.untils.ResultVOUntils; import pan.vo.ResultVO; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import java.util.HashMap; import java.util.Map; @RestController @Api(tags = "2.4", description = "登录", value = "实现登录") @RequestMapping("/plan") public class LoginContorl { @Autowired private UserSerice userSerice; @Autowired private RedisTemplate redisTemplate; @Autowired private FileService fileService; private RedisTemplate setusertoken(RedisTemplate redisTemplate) { redisTemplate = RedisDbInit.initRedis(RedisConfig.userreidport, redisTemplate); return redisTemplate; } @ApiOperation(value = "登录", notes = "用户登录") @PostMapping(value = "/login", produces = "application/json") public ResultVO login(@Valid UserForm userForm, BindingResult bindingResult) { if (bindingResult.hasErrors()) { throw new PanExection(ResultEmus.PARM_ERROR.getCode(), bindingResult.getFieldError().getDefaultMessage()); } User user = UserForm2User.convert(userForm); User login = userSerice.login(user.getUsername(), user.getPassword()); Map<String, String> map = new HashMap<>(); String redis = (String) setusertoken(redisTemplate).opsForValue().get("Plan_" + user.getUsername()); Boolean superadmin=userSerice.usersuperadmin(login.getId()); if(superadmin){ map.put("is_super","1"); }else{ map.put("is_super","0"); } if (login != null) { map.put("userid", login.getId().toString()); map.put("token", redis); return ResultVOUntils.success(map); } return ResultVOUntils.error(1, "密码或者用户名错误"); } }
到此我们的代码部分已经实现,
补充
ResultVOUntils代码
public class ResultVOUntils { public static ResultVO success(Object object){ ResultVO resultVO=new ResultVO(); resultVO.setData(object); resultVO.setMsg("成功"); resultVO.setCode(0); return resultVO; } public static ResultVO success(){ return success(null); } public static ResultVO error(Integer code ,String msg){ ResultVO resultVO=new ResultVO(); resultVO.setCode(code); resultVO.setMsg(msg); return resultVO; } public static ResultVO error(Object object){ ResultVO resultVO=new ResultVO(); resultVO.setData(object); resultVO.setMsg("失败"); resultVO.setCode(1); return resultVO; } }
restultvo代码
import lombok.Data; @Data public class ResultVO<T> { private Integer code; private String msg; private T data; }
PanExection代码
package pan.exection; import lombok.Getter; import pan.enmus.CaseResultEmus; import pan.enmus.ResultEmus; @Getter public class PanExection extends RuntimeException { private Integer code; public PanExection(ResultEmus resultEmuns) { super(resultEmuns.getMessage()); this.code = resultEmuns.getCode(); } public PanExection(CaseResultEmus resultEmuns) { super(resultEmuns.getMessage()); this.code = resultEmuns.getCode(); } public PanExection(Integer code, String message) { super(message); this.code = code; } }
那么到现在我们的代码已经实现 完毕,那么我们去实验下,
使用数据 lileilei 密码lileilei 进行校验
使用postman进行测试,密码输入正确返回结果正常
密码输入错误
![](https://img2018.cnblogs.com/blog/920110/201902/920110-20190225135740662-1753927117.png)
超出后
补充ResultEmus代码:
package pan.enmus; import lombok.Getter; @Getter public enum ResultEmus { SUCCESS_REQUEST(0, "成功"), USER_NOT_EXIT(1, "用户不存在"), USER_BIND(2, "用户已经绑定"), USER_DELETE(3, "用户已经删除"), EXCEPTIONS(4, "转化异常"), USER_ERROR_PASSWORD(225, "密码错误"), USER_FREE(115,"你已经被冻结,密码输入次数超过五次,请10分钟再来登录"), ; private Integer code; private String message; ResultEmus(Integer code, String message) { this.code = code; this.message = message; } }
到这里,我们的登录已经实现完毕。在标准的工程里面可以正常实现,
由于我配置了阿里的druid的监控
那么我可以看到相应的监控信息sql执行情况
![](https://img2018.cnblogs.com/blog/920110/201902/920110-20190225142030458-721069876.png)
这样我们用mysql实现的简单的用户名密码输入错误5次,限制登录十分钟就实现完毕。
实现起来没有那么难,难的是我们的思路,已经在不断的调试中前进,其实我还是感觉这里面是有bug的,后续有空我会来测试下这里的代码。