@TOC
前言
因为项目需要限制同一个用户的同一个IP只能登录一个,并且7天后要重新登录,所以考虑用redis实现。项目使用springmvc+shiro+vue。一、流程及图
1.简易流程图如下:
1.登录页面:
一、前端:
1.表单提交
<el-form id="app" :model="loginForm" :rules="rules" ref="loginForm" label-width="70px" label-position="right" @keyup.native.enter="login">
<div class="login-page">
<div class="dialog">
<div class="info">
<el-form-item label="用户名" prop="username">
<el-input v-model="loginForm.username" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" v-model="loginForm.password" placeholder="请输入密码"></el-input>
</el-form-item>
<el-form-item prop="code" >
<el-row :gutter="20">
<el-col :span="15">
<el-input v-model="loginForm.code" :disabled="sendCodeBtn.writedisabled" placeholder="短信验证码">
<i slot="prefix" class="el-icon-tickets"></i>
</el-input>
</el-col>
<el-col :span="8">
<el-button :type="sendCodeBtn.type" @click="sendLoginSms" :disabled="sendCodeBtn.disabled">{{sendCodeBtn.content}}</el-button>
</el-col>
</el-row>
</el-form-item>
<div class="remembers">
<el-form-item label="" prop="rememberMe">
<el-checkbox v-model="loginForm.rememberMe">记住我</el-checkbox>
</el-form-item>
</div>
</div>
<div class="btndiv">
<el-button type="primary" style="width:100%;" @click="login">登录</el-button>
</div>
</div>
</div>
</el-form>
2.登录方法
login : function() {// 登录
debugger;
// 获取实例对象
var _this = this;
if(_this.isLoginValidate){
this.getLogin();
}else {
this.$refs['loginForm'].validate((valid) => {
if (valid) {
this.getLogin();
}
})
}
},
getLogin(){
var _this = this;
_this.send = _this.send + 1;
axios.get(_this.loginUrl, {params : _this.loginForm}).then(function (response) {
debugger;
// 获取响应数据
var r = response.data;
debugger;
console.log(r);
if (r.sysUser || r.success) {
debugger;
window.location.href = "${urlPath }index.do";
_this.sendCodeBtn.disabled = true;
_this.sendCodeBtn.type = "info";
} else {
// 提示错误信息
if(r.message){
_this.$message.error(r.message);
}
_this.sendCodeBtn.writedisabled = false;
if(r.code == "5"){
_this.sendCodeBtn.disabled = false;
_this.sendCodeBtn.type = "primary";
_this.isLoginValidate = false;
}
}
}).catch(function (error) {// 请求数据处理失败
// 提示错误信息
_this.$message.error("请再点击一次“登录”按钮确认登录");
})
},
3.发送短信方法
sendLoginSms : function(){
debugger;
var _this = this;
_this.sendCodeBtn.disabled = true;
_this.sendCodeBtn.type = "info";
axios.get(_this.sendLoginSmsUrl,{params : _this.loginForm}).then(function (response) {
debugger;
// 获取响应数据
var r = response.data;
if(r.success){
_this.sendCodeBtn.writedisabled = false;
_this.$message.success(r.message);
var time = 60;
_this.sendSmsInterval = window.setInterval(function () {
if(time > 0){
_this.sendCodeBtn.content = time--;
}else {
window.clearInterval(_this.sendSmsInterval);
_this.sendCodeBtn.content = "发送";
_this.sendCodeBtn.disabled = false;
_this.sendCodeBtn.type = "primary";
}
},1000)
}else {
_this.$message.error(r.message);
_this.sendCodeBtn.disabled = false;
_this.sendCodeBtn.type = "primary";
if(r.code == "6"){
_this.sendCodeBtn.disabled = true;
_this.sendCodeBtn.type = "info";
}
}
}).catch(function (error) {
_this.$message.error("服务器异常!")
})
}
4.发送短信倒计时
mounted(){
this.time = this.countDown
}
三、login控制
1.login登录接口
/**
* @Description web端登陆
* @Param [req]
**/
@RequestMapping("/login")
@ResponseBody
public Result login(HttpServletRequest req) {
// 获取登录异常类名
String className = (String) req.getAttribute("shiroLoginFailure");
// 登录异常处理
if (UnknownAccountException.class.getName().equals(className) ||
IncorrectCredentialsException.class.getName().equals(className)) {
return Results.opError("用户名或密码错误!");
}
if (DisabledAccountException.class.getName().equals(className)) {
return Results.opError("该用户被禁用!");
}
String code = req.getParameter("code");
String username = req.getParameter("username");
if(StringUtils.isBlank(username) ){
return Results.error("请输入用户名及密码");
}
SysUser sysUser = sysUserService.selectOne(
SQLHelper.build(SysUser.class).mustEq("username",username).geEntityWrapper());
String ip = IPUtil.getIp(req);
if(sysUser==null){
return Results.error("该用户不存在,请填写正确的用户名");
}
byte[] ipKeyByte = RedisUtil.getKeyByte(Constants.LOGIN_IP, username+ip);
if(StringUtils.isNotBlank(code)) {
String phone = sysUser.getTelephone();
if(StringUtils.isBlank(phone)){
logger.error("手机号码不存在");
return Results.error("该用户手机号码不存在,请联系管理员");
}
byte[] codeKeyByte = RedisUtil.getKeyByte(Constants.LOGIN_CODE, phone);
String redisCode = RedisUtil.getRedisString(codeKeyByte);
if(StringUtils.isNotBlank(redisCode)){
if(code.equals(redisCode)){
RedisUtil.addRedisString(username,ipKeyByte,LOGIN_IP_SECONDS);
return Results.opOk();
}else {
return Results.error("请输入正确的短信验证码");
}
}else {
return Results.error("5","短信验证码已过期,请重新发送");
}
}else {
String ipStr = RedisUtil.getRedisString(ipKeyByte);
if (StringUtils.isEmpty(ipStr)) {
return Results.error("5","请验证短信码后才能登陆");
}else {
return Results.opOk();
}
}
}
2.发送短信接口
为了之后其他测试模块复用
/**
* @Description web端登陆短信验证
* @Param [req]
**/
@RequestMapping("/sendLoginSms")
@ResponseBody
public Result sendLoginSms(HttpServletRequest req) {
try{
String username = req.getParameter("username");
if(StringUtils.isBlank(username) ){
return Results.error("请输入用户名及密码");
}
SysUser sysUser = sysUserService.selectOne(
SQLHelper.build(SysUser.class).eq("username",username).geEntityWrapper());
String phone = null;
if(sysUser !=null){
phone = sysUser.getTelephone();
}else {
logger.error("该用户不存在");
return Results.error("该用户不存在,请填写正确的用户名");
}
if(StringUtils.isBlank(phone)){
logger.error("手机号码不存在");
return Results.error("该用户手机号码不存在,请联系管理员");
}
String ip = IPUtil.getIp(req);
byte[] codeCountByte = RedisUtil.getKeyByte(Constants.LOGIN_Code_COUNT_PREFIX, phone + ip);
String redisCodeCount = RedisUtil.getRedisString(codeCountByte);
Integer count = redisCodeCount == null ? 1 : Integer.valueOf(redisCodeCount) + 1;
if (count > 4 && count <= 8){
RedisUtil.addRedisString(count.toString(),codeCountByte,60*60);
return Results.error("操作太过频繁,请1小时后再试");
}
if(count > 8 && count < 12){
RedisUtil.addRedisString(count.toString(),codeCountByte,60*60*4);
return Results.error("操作太过频繁,请4小时后再试");
}
if(count >= 12){
RedisUtil.addRedisString(count.toString(),codeCountByte,60*60*24);
return Results.error("6","操作太过频繁,请24小时后再试");
}
RedisUtil.addRedisString(count.toString(),codeCountByte,LOGIN_CODE_COUNT_SECONDS);
byte[] codeKeyByte = RedisUtil.getKeyByte(Constants.LOGIN_CODE_PREFIX, phone);
String redisCode = RedisUtil.getRedisString(codeKeyByte);
if(StringUtils.isNotBlank(redisCode)){
return Results.error("验证码已发送,请不要频繁操作");
}
String code = RandomStringUtils.randomNumeric(6);
if(messageService.sendLoginSms(code, phone)){
RedisUtil.addRedisString(code,codeKeyByte,LOGIN_CODE_SECONDS);
return Results.ok("短信验证码发送成功,5分钟内有效",null);
}
} catch (Exception e) {
logger.error("短信发送失败",e);
}
return Results.error("发送失败,请稍后重试");
}
随心所往,看见未来。Follow your heart,see night!
欢迎点赞、关注、留言,一起学习、交流!