管理系统用户登录功能

一、前言

任何一个管理信息系统都会有登录功能。我们简单可以通过用户名加密码加验证码进行登录。但是就是一个这样的简单功能却涉及的要求很多。

比如对账号的要求,对密码复杂度的要求,对登录时长的要求,对密码有效期的要求,对登录用户登录日志的记录,登录用户的权限等等。非常非常多。本文就介绍简单的登录功能。

二、登录功能数据库表设计


-- Drop table

-- DROP TABLE public.t_user;

CREATE TABLE public.t_user (
	id varchar(32) NOT NULL,
	user_name varchar(255) NOT NULL,
	login_name varchar(255) NOT NULL,
	"password" varchar(255) NOT NULL,
	create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
	last_login_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
	deleted int4 NOT NULL DEFAULT 0,
	pwd_val_time timestamp NOT NULL,
	belong_code varchar(8) NULL,
	belong_name varchar(255) NULL,
	data_type varchar(255) NULL,
	phone varchar(255) NULL,
	CONSTRAINT t_user_pkey PRIMARY KEY (id)
);

 三、注册用户

注册用户分以下几步

1、判断新增的用户是否存在,如果存在不允许注册同账号的用户

2、判断用户名和密码是否是空

3、校验密码复杂度是否复合要求

4、对密码进行加密处理

5、报错新注册管理员账号

/**
	 * 保存后台管理用户信息
	 * @param tUser
	 * @return
	 */
	@ApiOperation(value = "保存后台管理用户信息", notes = "保存后台管理用户信息")
	@PostMapping("save")
	public ResponseData<Boolean> save(@RequestBody TUser tUser) {
		//先校验用户是否存在
		if(tUserService.userIsExists(tUser)) {
			log.error(TUserConstant.SAVE_USER_EXISTS);
			return ResponseData.error(TUserConstant.SAVE_USER_EXISTS);
		}

		if(StringUtils.isEmpty(tUser.getPassword()) || StringUtils.isEmpty(tUser.getLoginName())) {
			log.error(TUserConstant.SAVE_USER_EMP);
			return ResponseData.error(TUserConstant.SAVE_USER_EMP);
		}

		//校验密码复杂度
		Boolean checkPWD = tUserService.checkPWD(tUser.getPassword());
		if (!checkPWD) {
			log.error(TUserConstant.PWD_CHECK_ERROR);
			return ResponseData.error(TUserConstant.PWD_CHECK_ERROR);
		}
		
		tUser.setPassword(Des3Utils.get3DESEncryptECB(tUser.getPassword(), AES_KEY));
		tUser.setPwdValTime(new Date());
		boolean res = tUserService.save(tUser);
		if(res) {
			return ResponseData.success(true);
		}else {
			log.error(TUserConstant.SAVE_USER_ERROR);
			return ResponseData.error(TUserConstant.SAVE_USER_ERROR);
		}
	}

密码复杂度函数:

/**
	 * 校验复杂度
	 */
	public Boolean checkPWD(String PWD) {

		// 规定的正则表达式
		// (?![a-zA-Z]+$) 表示 字符串不能完全由大小写字母组成
		// (?![A-Z0-9]+$) 表示 字符串不能完全由大写字母和数字组成
		// (?![A-Z\W_]+$) 表示 字符串不能完全由大写字母和特殊字符组成
		// (?![a-z0-9]+$) 表示 字符串不能完全由小写字母和数字组成
		// (?![a-z\W_]+$) 表示 字符串不能完全由小写字母和特殊字符组成
		// (?![0-9\W_]+$) 表示 字符串不能完全由数字和特殊字符组成
		// [a-zA-Z0-9\W_]{8,} 表示 字符串应该匹配大小写字母、数字和特殊字符,至少匹配8次
		String regex = "^(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![a-z0-9]+$)(?![A-Z\\W_]+$)(?![a-z\\W_]+$)(?![0-9\\W_]+$)[a-zA-Z0-9\\W_]{8,}$";

		return ReUtil.isMatch(regex, PWD);
	}

四、用户登录

1、限制频繁刷登录操作

2、校验码校验

3、校验用户和密码是否正确

4、判断密码是否过期是否需要重置密码

5、将登录信息写到缓存,设置不操作2小时过期

6、获取登录用户的权限

代码示例:

/**
	 * 后台管理用户登录
	 * @param tUser
	 * @return
	 */
	@ApiOperation(value = "后台管理用户登录", notes = "后台管理用户登录")
	@PostMapping("login")
	public ResponseData<String> login(@RequestBody Map<String,Object> map,HttpServletRequest request,HttpServletResponse response) {
		//防刷登录限制,一分钟内刷连续30次,限制访问
		if (!tUserService.isLimit(request,30)) {
			ResponseData<Object> responseData = ResponseData.error(ResponseCode.IS_LIMIT_ACC.getCode(),
					ResponseCode.IS_LIMIT_ACC.getMessage());
			tUserService.resNoPermiss(response, responseData);
			return ResponseData.error(TUserConstant.IS_LIMIT_ACC);
		}
		
		String verCode = "";
	  
		if(map.containsKey("verCode")) {
			verCode = map.get("verCode").toString();
		}else {
			return ResponseData.error(TUserConstant.VERCODE_EMP);
		} 
		
		 log.info("前端传入验证码:"+verCode);
		/**登录验证码(暂时屏蔽)**/
		if (!CaptchaUtil.ver(verCode, request)) {
			 log.info("验证码验证失败");
	         return ResponseData.error(TUserConstant.VERCODE_ERROE);
	     }
		
		TUser tUser = new TUser();
		if(map.containsKey("loginName")) {
			tUser.setLoginName(map.get("loginName").toString());
		} 
		if(map.containsKey("password")) {
			tUser.setPassword(map.get("password").toString()); 
		} 
		
		String pwdError = redisUtils.get(RedisKeys.getLoginPwdError(tUser.getLoginName()));
		if(!StringUtils.isEmpty(pwdError)) {
			if(Integer.parseInt(pwdError) > 4) {
				return ResponseData.error(TUserConstant.LOGIN_PERMISS_ERROR);	
			}
		}
		
		log.info("获取到后台登录的密码为:"+ tUser.getPassword());
		log.info("获取到后台登录的加密后的密码为:"+ Des3Utils.get3DESEncryptECB(tUser.getPassword(),AES_KEY));
		tUser.setPassword(Des3Utils.get3DESEncryptECB(tUser.getPassword(),AES_KEY));
		TUser tUserRes = tUserService.getByLoginName(tUser);
		if(null != tUserRes) {
			//判断密码更新时间是否超过有效期
			if (((new Date().getTime() - tUserRes.getPwdValTime().getTime())/(1000*3600*24)) > pwdValTime) {
				return ResponseData.error(-1,TUserConstant.PWD_VAL_TIME_ERROR);
			}
			//更新最后登录时间
			tUserService.updateUserLastLoginTime(tUser.getLoginName(), DateTimeUtils.getDateStr());
 
			// 添加session
			HttpSession session = request.getSession();
			try {
				session.setAttribute(Constant.CTG_ADMIN_USER_NAME,AesUtil.aesEncrypt(tUserRes.getUserName(),AES_KEY));
				session.setAttribute(Constant.CTG_ADMIN_USER_ID,AesUtil.aesEncrypt(tUserRes.getLoginName(),AES_KEY));
			} catch (Exception e) {
				e.printStackTrace();
			}
			//两个小时的有效期
			session.setMaxInactiveInterval(7200);
			
			//获取最新权限缓存
			tMenuService.getMenuUrlByloginName(tUserRes.getLoginName());
			
			return	ResponseData.success(tUserRes.getUserName());
		}else {
			
			log.error(TUserConstant.LOGIN_PSW_ERROR);
			return ResponseData.error(TUserConstant.LOGIN_PSW_ERROR);
		}
	}

五、单点登录

作为登录功能因为所有的系统都需要登录,往往我们就可以把登录功能封装处理供所有的系统使用。我们可以把它作为一个登录系统或者认证中心,也可以作为单点登录。

单点登录的原理:

 

 关于单点登录,我会上传一份源码到资源。开箱即用。

猜你喜欢

转载自blog.csdn.net/dongjing991/article/details/132446679