SmartAdmin三级等保-安全登录
登录相关功能
SmartAdmin的登录功能完全满足三级等保,且支持配置化,具体如下功能:
- 采用双因子技术对用户进行登录身份鉴别。使用了:密码+X(验证码、证书、令牌等)进行登录身份鉴别。
- 登录超时自动退出,默认:登录30分钟内没操作,则自动退出当前登录状态
- 登录提交用户名和密码参数进行 国产SM参数加密
- 登录失败处理功能,默认:连续5次密码错误,则锁定账号30分钟
双因子登录
系统默认使用了邮箱作为第二个因子,即登录的时候需要:用户名、密码、邮箱验证码
具体后端代码可在 LoginService
中 sendEmailCode
和 validateEmailCode
两个方法中体现。
登录超时自动退出
登录30分钟内没操作,则自动退出当前登录状态
这个功能直接使用了 sa-token
自带的功能,具体在 Level3ProtectConfigService
类中进行设置;
java
private void setProp(Level3ProtectConfigForm configForm) {
......
// 设置 最低活跃时间(单位:秒)
if (this.loginActiveTimeoutSeconds > 0) {
StpUtil.getStpLogic().getConfigOrGlobal().setActiveTimeout(getLoginActiveTimeoutSeconds());
} else {
StpUtil.getStpLogic().getConfigOrGlobal().setActiveTimeout(-1);
}
}
登录密码请求加密
在前端代码 login.vue
中,在发送登录请求之前,使用 lib/encrypt.js
,支持SM4和AES加密, 进行加密,后端使用 ApiEncryptService
的实现类进行密码解密,代码如下
js
try {
SmartLoading.show();
// 密码加密
let encryptPasswordForm = Object.assign({}, loginForm, {
password: encryptData(loginForm.password),
});
const res = await loginApi.login(encryptPasswordForm);
// 登录成功
stopRefreshCaptchaInterval();
localSave(LocalStorageKeyConst.USER_TOKEN, res.data.token ? res.data.token : '');
message.success('登录成功');
//更新用户信息到pinia
useUserStore().setUserLoginInfo(res.data);
//构建系统的路由
buildRoutes();
router.push('/home');
} catch (e) {
...
...
}
登录失败处理功能
默认功能为:连续登录失败5次,锁定30分钟;
表结构:使用 t_login_fail
记录登录失败次数,以及开始锁定的开始时间 代码实现:
1)登录时候 校验 t_login_fail
的失败次数和是否已经开启锁定
2)登录成功,删除 t_login_fail
表数据,登录失败:根据t_login_fail
记录数据 进行次数增加和判断是否锁定
表结构:
sql
CREATE TABLE `t_login_fail` (
`login_fail_id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增id',
`user_id` bigint NOT NULL COMMENT '用户id',
`user_type` int NOT NULL COMMENT '用户类型',
`login_name` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '登录名',
`login_fail_count` int DEFAULT NULL COMMENT '连续登录失败次数',
`lock_flag` tinyint DEFAULT '0' COMMENT '锁定状态:1锁定,0未锁定',
`login_lock_begin_time` datetime DEFAULT NULL COMMENT '连续登录失败锁定开始时间',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`login_fail_id`) USING BTREE,
UNIQUE KEY `uid_and_utype` (`user_id`,`user_type`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='登录失败次数记录表';
后端类: SecurityLoginService
java
public ResponseDTO<LoginFailEntity> checkLogin(Long userId, UserTypeEnum userType) {
// 若登录最大失败次数小于1,无需校验
if (level3ProtectConfigService.getLoginFailMaxTimes() < 1) {
return ResponseDTO.ok();
}
LoginFailEntity loginFailEntity = loginFailDao.selectByUserIdAndUserType(userId, userType.getValue());
if (loginFailEntity == null) {
return ResponseDTO.ok();
}
// 校验登录失败次数
if (loginFailEntity.getLoginFailCount() < level3ProtectConfigService.getLoginFailMaxTimes()) {
return ResponseDTO.ok(loginFailEntity);
}
// 校验是否锁定
if (loginFailEntity.getLoginLockBeginTime() == null) {
return ResponseDTO.ok(loginFailEntity);
}
// 校验锁定时长
if (loginFailEntity.getLoginLockBeginTime().plusSeconds(level3ProtectConfigService.getLoginFailLockSeconds()).isBefore(LocalDateTime.now())) {
// 过了锁定时间
return ResponseDTO.ok(loginFailEntity);
}
LocalDateTime unlockTime = loginFailEntity.getLoginLockBeginTime().plusSeconds(level3ProtectConfigService.getLoginFailLockSeconds());
return ResponseDTO.error(UserErrorCode.LOGIN_FAIL_LOCK, String.format(LOGIN_LOCK_MSG, loginFailEntity.getLoginFailCount(), level3ProtectConfigService.getLoginFailLockSeconds() / 60, LocalDateTimeUtil.formatNormal(unlockTime)));
}
联系我们
1024创新实验室-主任:卓大,混迹于各个技术圈,研究过计算机,熟悉点 java,略懂点前端。
1024创新实验室 致力于成为中原领先、国内一流的技术团队, 以AI+数字化为驱动,用技术为产业互联网提供无限可能, 业务如下:
- 教育(就业创业大数据平台、继续教育平台、在线教育系统、题库、医学考试、专升本等)
- 供应链(网络货运、大宗贸易进销存ERP、物流TMS、B2B电商、仓储WMS、AI提效等)
- 中医大健康(诊所数字化管理、AI辅助诊疗、中医适宜技术、在线问诊、空中药房等)
- AI+软件(软件定制外包、数据大屏、国产化改造、人员外包、技术顾问、技术培训等)
- 欢迎各类合作哦,一起赚钱~
加微信: 卓大 拉你入群,一起学习 | 公众号 :六边形工程师 分享:赚钱、代码、生活 | 请 “1024创新实验室” 烩面里加肉 咖啡配胡辣汤,提神又饱腹 | 抖音 : 六边形工程师 直播:赚钱、代码、中医 |