欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

spring boot 实现密码连续输入错误5次,限制十分钟内不能进行登录

程序员文章站 2022-04-28 12:42:27
我们要实现的就是,密码连续输入错误5次,就限制用户十分钟不能进行登录。 大致的流程图 数据库设计如下 那么我们来实现dao层 对应的UserEmus 那么接下来,我们就是UserRepository实现 里面就用到了一个通过username查找用户 那么我们接下来去实现service 到此我们的代码 ......

 

     我们要实现的就是,密码连续输入错误5次,就限制用户十分钟不能进行登录。

     大致的流程图

      spring boot 实现密码连续输入错误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进行测试,密码输入正确返回结果正常

spring boot 实现密码连续输入错误5次,限制十分钟内不能进行登录

 

 密码输入错误
spring boot 实现密码连续输入错误5次,限制十分钟内不能进行登录


超出后

spring boot 实现密码连续输入错误5次,限制十分钟内不能进行登录

 

 补充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执行情况
spring boot 实现密码连续输入错误5次,限制十分钟内不能进行登录

这样我们用mysql实现的简单的用户名密码输入错误5次,限制登录十分钟就实现完毕。


实现起来没有那么难,难的是我们的思路,已经在不断的调试中前进,其实我还是感觉这里面是有bug的,后续有空我会来测试下这里的代码。