spring boot 实现密码连续输入错误5次,限制十分钟内不能进行登录
程序员文章站
2022-04-28 12:42:27
我们要实现的就是,密码连续输入错误5次,就限制用户十分钟不能进行登录。 大致的流程图 数据库设计如下 那么我们来实现dao层 对应的UserEmus 那么接下来,我们就是UserRepository实现 里面就用到了一个通过username查找用户 那么我们接下来去实现service 到此我们的代码 ......
我们要实现的就是,密码连续输入错误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进行测试,密码输入正确返回结果正常
密码输入错误
超出后
补充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执行情况
这样我们用mysql实现的简单的用户名密码输入错误5次,限制登录十分钟就实现完毕。
实现起来没有那么难,难的是我们的思路,已经在不断的调试中前进,其实我还是感觉这里面是有bug的,后续有空我会来测试下这里的代码。