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進行測試,密碼輸入正確返回結果正常

 

 密碼輸入錯誤



超出后

 

 補充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的,后續有空我會來測試下這里的代碼。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM