web登录添加用户+IP限制方法

231 阅读2分钟

@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!
欢迎点赞、关注、留言,一起学习、交流!