mirror of
https://github.com/insistence/RuoYi-Vue3-FastAPI.git
synced 2026-09-21 20:55:15 +00:00
feat: 初始密码支持自定义修改策略
This commit is contained in:
@@ -165,6 +165,7 @@ async def reset_system_user_pwd(
|
|||||||
edit_user = EditUserModel(
|
edit_user = EditUserModel(
|
||||||
userId=reset_user.user_id,
|
userId=reset_user.user_id,
|
||||||
password=PwdUtil.get_password_hash(reset_user.password),
|
password=PwdUtil.get_password_hash(reset_user.password),
|
||||||
|
pwdUpdateDate=datetime.now(),
|
||||||
updateBy=current_user.user.user_name,
|
updateBy=current_user.user.user_name,
|
||||||
updateTime=datetime.now(),
|
updateTime=datetime.now(),
|
||||||
type='pwd',
|
type='pwd',
|
||||||
@@ -304,6 +305,7 @@ async def reset_system_user_password(
|
|||||||
userId=current_user.user.user_id,
|
userId=current_user.user.user_id,
|
||||||
oldPassword=reset_password.old_password,
|
oldPassword=reset_password.old_password,
|
||||||
password=reset_password.new_password,
|
password=reset_password.new_password,
|
||||||
|
pwdUpdateDate=datetime.now(),
|
||||||
updateBy=current_user.user.user_name,
|
updateBy=current_user.user.user_name,
|
||||||
updateTime=datetime.now(),
|
updateTime=datetime.now(),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ class SysUser(Base):
|
|||||||
del_flag = Column(CHAR(1), nullable=True, server_default='0', comment='删除标志(0代表存在 2代表删除)')
|
del_flag = Column(CHAR(1), nullable=True, server_default='0', comment='删除标志(0代表存在 2代表删除)')
|
||||||
login_ip = Column(String(128), nullable=True, server_default="''", comment='最后登录IP')
|
login_ip = Column(String(128), nullable=True, server_default="''", comment='最后登录IP')
|
||||||
login_date = Column(DateTime, nullable=True, comment='最后登录时间')
|
login_date = Column(DateTime, nullable=True, comment='最后登录时间')
|
||||||
|
pwd_update_date = Column(DateTime, nullable=True, comment='密码最后更新时间')
|
||||||
create_by = Column(String(64), nullable=True, server_default="''", comment='创建者')
|
create_by = Column(String(64), nullable=True, server_default="''", comment='创建者')
|
||||||
create_time = Column(DateTime, nullable=True, comment='创建时间', default=datetime.now())
|
create_time = Column(DateTime, nullable=True, comment='创建时间', default=datetime.now())
|
||||||
update_by = Column(String(64), nullable=True, server_default="''", comment='更新者')
|
update_by = Column(String(64), nullable=True, server_default="''", comment='更新者')
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ class UserModel(BaseModel):
|
|||||||
del_flag: Optional[Literal['0', '2']] = Field(default=None, description='删除标志(0代表存在 2代表删除)')
|
del_flag: Optional[Literal['0', '2']] = Field(default=None, description='删除标志(0代表存在 2代表删除)')
|
||||||
login_ip: Optional[str] = Field(default=None, description='最后登录IP')
|
login_ip: Optional[str] = Field(default=None, description='最后登录IP')
|
||||||
login_date: Optional[datetime] = Field(default=None, description='最后登录时间')
|
login_date: Optional[datetime] = Field(default=None, description='最后登录时间')
|
||||||
|
pwd_update_date: Optional[datetime] = Field(default=None, description='密码最后更新时间')
|
||||||
create_by: Optional[str] = Field(default=None, description='创建者')
|
create_by: Optional[str] = Field(default=None, description='创建者')
|
||||||
create_time: Optional[datetime] = Field(default=None, description='创建时间')
|
create_time: Optional[datetime] = Field(default=None, description='创建时间')
|
||||||
update_by: Optional[str] = Field(default=None, description='更新者')
|
update_by: Optional[str] = Field(default=None, description='更新者')
|
||||||
@@ -125,6 +126,7 @@ class CurrentUserModel(BaseModel):
|
|||||||
permissions: List = Field(description='权限信息')
|
permissions: List = Field(description='权限信息')
|
||||||
roles: List = Field(description='角色信息')
|
roles: List = Field(description='角色信息')
|
||||||
user: Union[UserInfoModel, None] = Field(description='用户信息')
|
user: Union[UserInfoModel, None] = Field(description='用户信息')
|
||||||
|
is_default_modify_pwd: bool = Field(default=False, description='是否初始密码修改提醒')
|
||||||
|
|
||||||
|
|
||||||
class UserDetailModel(BaseModel):
|
class UserDetailModel(BaseModel):
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ class LoginService:
|
|||||||
else:
|
else:
|
||||||
# 此方法可实现同一账号同一时间只能登录一次
|
# 此方法可实现同一账号同一时间只能登录一次
|
||||||
redis_token = await request.app.state.redis.get(
|
redis_token = await request.app.state.redis.get(
|
||||||
f"{RedisInitKeyConfig.ACCESS_TOKEN.key}:{query_user.get('user_basic_info').user_id}"
|
f'{RedisInitKeyConfig.ACCESS_TOKEN.key}:{query_user.get("user_basic_info").user_id}'
|
||||||
)
|
)
|
||||||
if token == redis_token:
|
if token == redis_token:
|
||||||
if AppConfig.app_same_time_login:
|
if AppConfig.app_same_time_login:
|
||||||
@@ -229,7 +229,7 @@ class LoginService:
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await request.app.state.redis.set(
|
await request.app.state.redis.set(
|
||||||
f"{RedisInitKeyConfig.ACCESS_TOKEN.key}:{query_user.get('user_basic_info').user_id}",
|
f'{RedisInitKeyConfig.ACCESS_TOKEN.key}:{query_user.get("user_basic_info").user_id}',
|
||||||
redis_token,
|
redis_token,
|
||||||
ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes),
|
ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes),
|
||||||
)
|
)
|
||||||
@@ -242,6 +242,9 @@ class LoginService:
|
|||||||
post_ids = ','.join([str(row.post_id) for row in query_user.get('user_post_info')])
|
post_ids = ','.join([str(row.post_id) for row in query_user.get('user_post_info')])
|
||||||
role_ids = ','.join([str(row.role_id) for row in query_user.get('user_role_info')])
|
role_ids = ','.join([str(row.role_id) for row in query_user.get('user_role_info')])
|
||||||
roles = [row.role_key for row in query_user.get('user_role_info')]
|
roles = [row.role_key for row in query_user.get('user_role_info')]
|
||||||
|
is_default_modify_pwd = await cls.__init_password_is_modify(
|
||||||
|
request, query_user.get('user_basic_info').pwd_update_date
|
||||||
|
)
|
||||||
|
|
||||||
current_user = CurrentUserModel(
|
current_user = CurrentUserModel(
|
||||||
permissions=permissions,
|
permissions=permissions,
|
||||||
@@ -253,12 +256,27 @@ class LoginService:
|
|||||||
dept=CamelCaseUtil.transform_result(query_user.get('user_dept_info')),
|
dept=CamelCaseUtil.transform_result(query_user.get('user_dept_info')),
|
||||||
role=CamelCaseUtil.transform_result(query_user.get('user_role_info')),
|
role=CamelCaseUtil.transform_result(query_user.get('user_role_info')),
|
||||||
),
|
),
|
||||||
|
isDefaultModifyPwd=is_default_modify_pwd,
|
||||||
)
|
)
|
||||||
return current_user
|
return current_user
|
||||||
else:
|
else:
|
||||||
logger.warning('用户token已失效,请重新登录')
|
logger.warning('用户token已失效,请重新登录')
|
||||||
raise AuthException(data='', message='用户token已失效,请重新登录')
|
raise AuthException(data='', message='用户token已失效,请重新登录')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def __init_password_is_modify(cls, request: Request, pwd_update_date: datetime):
|
||||||
|
"""
|
||||||
|
判断当前用户是否初始密码登录
|
||||||
|
|
||||||
|
:param request: Request对象
|
||||||
|
:param pwd_update_date: 密码最后更新时间
|
||||||
|
:return: 是否初始密码登录
|
||||||
|
"""
|
||||||
|
init_password_is_modify = await request.app.state.redis.get(
|
||||||
|
f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.initPasswordModify'
|
||||||
|
)
|
||||||
|
return init_password_is_modify == '1' and pwd_update_date is None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_current_user_routers(cls, user_id: int, query_db: AsyncSession):
|
async def get_current_user_routers(cls, user_id: int, query_db: AsyncSession):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ create table sys_user (
|
|||||||
del_flag char(1) default '0',
|
del_flag char(1) default '0',
|
||||||
login_ip varchar(128) default '',
|
login_ip varchar(128) default '',
|
||||||
login_date timestamp(0),
|
login_date timestamp(0),
|
||||||
|
pwd_update_date timestamp(0),
|
||||||
create_by varchar(64) default '',
|
create_by varchar(64) default '',
|
||||||
create_time timestamp(0),
|
create_time timestamp(0),
|
||||||
update_by varchar(64) default '',
|
update_by varchar(64) default '',
|
||||||
@@ -91,6 +92,7 @@ comment on column sys_user.status is '帐号状态(0正常 1停用)';
|
|||||||
comment on column sys_user.del_flag is '删除标志(0代表存在 2代表删除)';
|
comment on column sys_user.del_flag is '删除标志(0代表存在 2代表删除)';
|
||||||
comment on column sys_user.login_ip is '最后登录IP';
|
comment on column sys_user.login_ip is '最后登录IP';
|
||||||
comment on column sys_user.login_date is '最后登录时间';
|
comment on column sys_user.login_date is '最后登录时间';
|
||||||
|
comment on column sys_user.pwd_update_date is '密码最后更新时间';
|
||||||
comment on column sys_user.create_by is '创建者';
|
comment on column sys_user.create_by is '创建者';
|
||||||
comment on column sys_user.create_time is '创建时间';
|
comment on column sys_user.create_time is '创建时间';
|
||||||
comment on column sys_user.update_by is '更新者';
|
comment on column sys_user.update_by is '更新者';
|
||||||
@@ -98,6 +100,12 @@ comment on column sys_user.update_time is '更新时间';
|
|||||||
comment on column sys_user.remark is '备注';
|
comment on column sys_user.remark is '备注';
|
||||||
comment on table sys_user is '用户信息表';
|
comment on table sys_user is '用户信息表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 初始化-用户信息表数据
|
||||||
|
-- ----------------------------
|
||||||
|
insert into sys_user values(1, 103, 'admin', '超级管理员', '00', 'niangao@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', current_timestamp, current_timestamp, 'admin', current_timestamp, '', null, '管理员');
|
||||||
|
insert into sys_user values(2, 105, 'niangao', '年糕', '00', 'niangao@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', current_timestamp, current_timestamp, 'admin', current_timestamp, '', null, '测试员');
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- 3、岗位信息表
|
-- 3、岗位信息表
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
@@ -136,12 +144,6 @@ insert into sys_post values(2, 'se', '项目经理', 2, '0', 'admin', current
|
|||||||
insert into sys_post values(3, 'hr', '人力资源', 3, '0', 'admin', current_timestamp, '', null, '');
|
insert into sys_post values(3, 'hr', '人力资源', 3, '0', 'admin', current_timestamp, '', null, '');
|
||||||
insert into sys_post values(4, 'user', '普通员工', 4, '0', 'admin', current_timestamp, '', null, '');
|
insert into sys_post values(4, 'user', '普通员工', 4, '0', 'admin', current_timestamp, '', null, '');
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 初始化-用户信息表数据
|
|
||||||
-- ----------------------------
|
|
||||||
insert into sys_user values(1, 103, 'admin', '超级管理员', '00', 'niangao@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', current_timestamp, 'admin', current_timestamp, '', null, '管理员');
|
|
||||||
insert into sys_user values(2, 105, 'niangao', '年糕', '00', 'niangao@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', current_timestamp, 'admin', current_timestamp, '', null, '测试员');
|
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- 4、角色信息表
|
-- 4、角色信息表
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
@@ -704,6 +706,7 @@ insert into sys_config values(3, '主框架页-侧边栏主题', 'sys.
|
|||||||
insert into sys_config values(4, '账号自助-验证码开关', 'sys.account.captchaEnabled', 'true', 'Y', 'admin', current_timestamp, '', null, '是否开启验证码功能(true开启,false关闭)');
|
insert into sys_config values(4, '账号自助-验证码开关', 'sys.account.captchaEnabled', 'true', 'Y', 'admin', current_timestamp, '', null, '是否开启验证码功能(true开启,false关闭)');
|
||||||
insert into sys_config values(5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 'admin', current_timestamp, '', null, '是否开启注册用户功能(true开启,false关闭)');
|
insert into sys_config values(5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 'admin', current_timestamp, '', null, '是否开启注册用户功能(true开启,false关闭)');
|
||||||
insert into sys_config values(6, '用户登录-黑名单列表', 'sys.login.blackIPList', '', 'Y', 'admin', current_timestamp, '', null, '设置登录IP黑名单限制,多个匹配项以;分隔,支持匹配(*通配、网段)');
|
insert into sys_config values(6, '用户登录-黑名单列表', 'sys.login.blackIPList', '', 'Y', 'admin', current_timestamp, '', null, '设置登录IP黑名单限制,多个匹配项以;分隔,支持匹配(*通配、网段)');
|
||||||
|
insert into sys_config values(7, '用户管理-初始密码修改策略', 'sys.account.initPasswordModify', '1', 'Y', 'admin', current_timestamp, '', null, '0:初始密码修改策略关闭,没有任何提示,1:提醒用户,如果未修改初始密码,则在登录时就会提醒修改密码对话框');
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- 14、系统访问记录
|
-- 14、系统访问记录
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ create table sys_user (
|
|||||||
del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)',
|
del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)',
|
||||||
login_ip varchar(128) default '' comment '最后登录IP',
|
login_ip varchar(128) default '' comment '最后登录IP',
|
||||||
login_date datetime comment '最后登录时间',
|
login_date datetime comment '最后登录时间',
|
||||||
|
pwd_update_date datetime comment '密码最后更新时间',
|
||||||
create_by varchar(64) default '' comment '创建者',
|
create_by varchar(64) default '' comment '创建者',
|
||||||
create_time datetime comment '创建时间',
|
create_time datetime comment '创建时间',
|
||||||
update_by varchar(64) default '' comment '更新者',
|
update_by varchar(64) default '' comment '更新者',
|
||||||
@@ -65,8 +66,8 @@ create table sys_user (
|
|||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- 初始化-用户信息表数据
|
-- 初始化-用户信息表数据
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
insert into sys_user values(1, 103, 'admin', '超级管理员', '00', 'niangao@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 'admin', sysdate(), '', null, '管理员');
|
insert into sys_user values(1, 103, 'admin', '超级管理员', '00', 'niangao@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), sysdate(), 'admin', sysdate(), '', null, '管理员');
|
||||||
insert into sys_user values(2, 105, 'niangao', '年糕', '00', 'niangao@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 'admin', sysdate(), '', null, '测试员');
|
insert into sys_user values(2, 105, 'niangao', '年糕', '00', 'niangao@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), sysdate(), 'admin', sysdate(), '', null, '测试员');
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
@@ -554,6 +555,7 @@ insert into sys_config values(3, '主框架页-侧边栏主题', 'sys.
|
|||||||
insert into sys_config values(4, '账号自助-验证码开关', 'sys.account.captchaEnabled', 'true', 'Y', 'admin', sysdate(), '', null, '是否开启验证码功能(true开启,false关闭)');
|
insert into sys_config values(4, '账号自助-验证码开关', 'sys.account.captchaEnabled', 'true', 'Y', 'admin', sysdate(), '', null, '是否开启验证码功能(true开启,false关闭)');
|
||||||
insert into sys_config values(5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 'admin', sysdate(), '', null, '是否开启注册用户功能(true开启,false关闭)');
|
insert into sys_config values(5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 'admin', sysdate(), '', null, '是否开启注册用户功能(true开启,false关闭)');
|
||||||
insert into sys_config values(6, '用户登录-黑名单列表', 'sys.login.blackIPList', '', 'Y', 'admin', sysdate(), '', null, '设置登录IP黑名单限制,多个匹配项以;分隔,支持匹配(*通配、网段)');
|
insert into sys_config values(6, '用户登录-黑名单列表', 'sys.login.blackIPList', '', 'Y', 'admin', sysdate(), '', null, '设置登录IP黑名单限制,多个匹配项以;分隔,支持匹配(*通配、网段)');
|
||||||
|
insert into sys_config values(7, '用户管理-初始密码修改策略', 'sys.account.initPasswordModify', '1', 'Y', 'admin', sysdate(), '', null, '0:初始密码修改策略关闭,没有任何提示,1:提醒用户,如果未修改初始密码,则在登录时就会提醒修改密码对话框');
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ export const constantRoutes = [
|
|||||||
redirect: 'noredirect',
|
redirect: 'noredirect',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'profile',
|
path: 'profile/:activeTab?',
|
||||||
component: () => import('@/views/system/user/profile/index'),
|
component: () => import('@/views/system/user/profile/index'),
|
||||||
name: 'Profile',
|
name: 'Profile',
|
||||||
meta: { title: '个人中心', icon: 'user' }
|
meta: { title: '个人中心', icon: 'user' }
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import router from '@/router'
|
||||||
|
import { ElMessageBox } from 'element-plus'
|
||||||
import { login, logout, getInfo } from '@/api/login'
|
import { login, logout, getInfo } from '@/api/login'
|
||||||
import { getToken, setToken, removeToken } from '@/utils/auth'
|
import { getToken, setToken, removeToken } from '@/utils/auth'
|
||||||
import { isHttp, isEmpty } from "@/utils/validate"
|
import { isHttp, isEmpty } from "@/utils/validate"
|
||||||
@@ -51,6 +53,12 @@ const useUserStore = defineStore(
|
|||||||
this.name = user.userName
|
this.name = user.userName
|
||||||
this.nickName = user.nickName
|
this.nickName = user.nickName
|
||||||
this.avatar = avatar
|
this.avatar = avatar
|
||||||
|
/* 初始密码提示 */
|
||||||
|
if(res.isDefaultModifyPwd) {
|
||||||
|
ElMessageBox.confirm('您的密码还是初始密码,请修改密码!', '安全提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => {
|
||||||
|
router.push({ name: 'Profile', params: { activeTab: 'resetPwd' } })
|
||||||
|
}).catch(() => {})
|
||||||
|
}
|
||||||
resolve(res)
|
resolve(res)
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
reject(error)
|
reject(error)
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
<span>基本资料</span>
|
<span>基本资料</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-tabs v-model="activeTab">
|
<el-tabs v-model="selectedTab">
|
||||||
<el-tab-pane label="基本资料" name="userinfo">
|
<el-tab-pane label="基本资料" name="userinfo">
|
||||||
<userInfo :user="state.user" />
|
<userInfo :user="state.user" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
@@ -68,7 +68,8 @@ import userInfo from "./userInfo";
|
|||||||
import resetPwd from "./resetPwd";
|
import resetPwd from "./resetPwd";
|
||||||
import { getUserProfile } from "@/api/system/user";
|
import { getUserProfile } from "@/api/system/user";
|
||||||
|
|
||||||
const activeTab = ref("userinfo");
|
const route = useRoute()
|
||||||
|
const selectedTab = ref("userinfo")
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
user: {},
|
user: {},
|
||||||
roleGroup: {},
|
roleGroup: {},
|
||||||
@@ -83,5 +84,11 @@ function getUser() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
getUser();
|
onMounted(() => {
|
||||||
|
const activeTab = route.params && route.params.activeTab
|
||||||
|
if (activeTab) {
|
||||||
|
selectedTab.value = activeTab
|
||||||
|
}
|
||||||
|
getUser()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user