密码输入失败次数限制

本文介绍了为项目添加登录失败次数限制功能,当用户在一定时间内连续多次输入错误密码后,账号将被锁定。使用Shiro实现此功能,涉及数据库中登录失败记录表的设计,以及锁定策略的设定,包括IP记录和账号解锁机制。

今天给两个项目加上了登录时在一定时间内输入密码多次失败就锁定账号的功能,锁定之后需要管理员进行解锁才能够继续登陆;两个项目一个是用shiro,一个没用shiro;不过都差不多,下面只讲用shiro的,具体业务可以根据自己需求去修改(比如:登录失败多次不锁定账号,只是以相对时间内的次数去判断,超过该段时间就可以继续登陆;时间自己设定)

数据库:建立一个表存放用户登录失败的记录(密码最好加密后再存进数据库)

	/*
	 * 登录信息和用户验证信息验证(non-Javadoc)
	 * @see org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		String username = (String) token.getPrincipal();
		String password = new String((char[]) token.getCredentials());
		HttpServletRequest request=((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		List<String> principals = new ArrayList<>();
		int retValue = checkUserPwd(request,username, password, principals);
		switch (retValue) {
			case 0: return new SimpleAuthenticationInfo(principals, password, getName());
			case 1: throw new UnknownAccountException("用户名不存在");
			case 2: throw new IncorrectCredentialsException("密码不正确");
			case 3: throw new AuthenticationException("初始化用户信息失败");
			case 4: throw new DisabledAccountException("该用户已被禁用");
			default: throw new AuthenticationException("校验用户名密码异常");
		}
	}

	private int checkUserPwd(HttpServletRequest request,String username, String password, List<String> principals) {

		String ip = RequestUtil.getIP(request);
		try {
			ChaUser chaUser = chaUserService.getByUsername(username);

			if(chaUser == null) {

					logger.info(String.format("用户名[%s]不存在", username));
					return 1;

				}

			String dbPassword = chaUser.getPassword();
				if(chaUser == null) {
					logger.info(String.format("账号[%s]不存在", username));
					return 1;
				}
				if (chaUser.getStatus() == Status.DISABLED.getId()) {
					logger.info(String.format("账号[%s]已被禁用", username));
					return 4;
				}
				dbPassword = chaUser.getPassword();


			if (!password.equalsIgnoreCase(dbPassword)) {
				if(userLoginFailRecordService.checkFailCount(username, password, ip)) {

					chaUserService.updateStatus(chaUserService.getByUsername(username).getUserId(), AccountStatus.LOCKED.getId());
				}
				logger.info(String.format("用户[%s]的密码[%s]不正确", username, password));
				return 2;
			}

			principals.add(chaUser.getUserId().toString());
			principals.add(Const.SHIRO_PREFIX_UN + chaUser.getUsername());
			return 0;
		} catch (Exception ex) {
			logger.error(username + " checkUserPwd exception", ex);
			return 99;
		}
	}
	public int add(String account, String password, String ip) throws Exception {
		UserLoginFailRecord userLoginFailRecord = new UserLoginFailRecord();
		userLoginFailRecord.setAccount(account);
		userLoginFailRecord.setPassword(password);
		userLoginFailRecord.setIp(ip);
		userLoginFailRecord.setCreateTime(new Date());
		return  (int) dao.findForObject("UserLoginFailRecordMapper.add", userLoginFailRecord);
	}

	public boolean checkFailCount(String account, String password, String ip) throws Exception {
		UserLoginFailRecord userLoginFailRecord = new UserLoginFailRecord();
		userLoginFailRecord.setAccount(account);
		userLoginFailRecord.setPassword(password);
		userLoginFailRecord.setIp(ip);
		userLoginFailRecord.setCreateTime(new Date());
		dao.findForObject("UserLoginFailRecordMapper.add", userLoginFailRecord);
		Date startTime = new Date(new Date().getTime() - 24 * 60 * 60 * 1000); // 24小时
		PageData pd = new PageData();
		pd.put("account", account);
		pd.put("startTime", startTime);
		long count = (long) dao.findForObject("UserLoginFailRecordMapper.count", pd);
		return count >= 5;
	}

mapper.xml文件简单就不贴了。一些枚举等根据自己具体业务。

总体思路就是:每登录失败一次就在登录失败表中记录一次记录(存储ip是为了分析原因能够用到);当在规定时间内登录失败一定次数再次登录失败则触发账号锁定(一般需要后台有账号解锁功能;若要写成登录失败一段时间冷却之后能继续试的话,可以根据登录失败表的次数跟时间判断,规定时间内没达到次数就可以继续尝试)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值