😎1、增加用户密码历史记录 2、增加密码有效期验证 3、增加密码历史记录验证 4、增加扩展sqlsugar函数解密

This commit is contained in:
zuohuaijun 2024-12-17 17:04:27 +08:00
parent 687b7e9c38
commit 85bcd500ac
21 changed files with 297 additions and 39 deletions

View File

@ -106,6 +106,16 @@ public class ConfigConst
/// </summary>
public const string SysPasswordStrengthExpression = "sys_password_strength_expression";
/// <summary>
/// 密码有效期验证
/// </summary>
public const string SysPasswordExpirationTime = "sys_password_expiration_time";
/// <summary>
/// 密码历史记录验证
/// </summary>
public const string SysPasswordRecord = "sys_password_record";
/// <summary>
/// Default 分组
/// </summary>

View File

@ -0,0 +1,28 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core;
/// <summary>
/// 系统用户角色表
/// </summary>
[SugarTable(null, "系统用户密码记录表")]
[SysTable]
public class SysUserPasswordRecord : EntityBaseId
{
/// <summary>
/// 用户Id
/// </summary>
[SugarColumn(ColumnDescription = "用户Id")]
public long UserId { get; set; }
/// <summary>
/// 密码
/// </summary>
[SugarColumn(ColumnDescription = "密码", Length = 512)]
[MaxLength(512)]
public string Password { get; set; }
}

View File

@ -61,6 +61,12 @@ public enum ErrorCodeEnum
[ErrorCodeItemMetadata("旧密码输入错误")]
D1004,
/// <summary>
/// 密码已使用过,请更换其他密码
/// </summary>
[ErrorCodeItemMetadata("密码已使用过,请更换其他密码")]
D1104,
/// <summary>
/// 测试数据禁止更改admin密码
/// </summary>

View File

@ -43,18 +43,5 @@ public class LogJob : IJob
// 自定义日志
_logger.LogInformation(msg);
// 默认 3个月/90天 强制修改一次密码(将最新修改密码时间置空)
if (await sysConfigService.GetConfigValueByCode<bool>(ConfigConst.SysForceChangePassword))
{
var userIds = await db.Queryable<SysUser>()
.Where(u => SqlFunc.IsNullOrEmpty(u.LastChangePasswordTime) || (DateTime.Now - (DateTime)u.LastChangePasswordTime).Days > 90)
.Select(u => u.Id).ToListAsync(stoppingToken);
await db.Updateable<SysUser>()
.SetColumns(u => new SysUser() { LastChangePasswordTime = null })
.Where(u => userIds.Contains(u.Id))
.ExecuteCommandAsync(stoppingToken);
}
}
}

View File

@ -34,11 +34,13 @@ public class SysConfigSeedData : ISqlSugarEntitySeedData<SysConfig>
new SysConfig{ Id=1300000000221, Name="租户隔离登录验证", Code=ConfigConst.SysTenantHostLogin, Value="False", SysFlag=YesNoEnum.Y, Remark="租户隔离登录验证", OrderNo=370, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000231, Name="数据校验日志", Code=ConfigConst.SysValidationLog, Value="True", SysFlag=YesNoEnum.Y, Remark="是否数据校验日志", OrderNo=130, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000241, Name="行政区划同步层级", Code=ConfigConst.SysRegionSyncLevel, Value="3", SysFlag=YesNoEnum.Y, Remark="行政区划同步层级 1-省级,2-市级,3-区县级,4-街道级,5-村级", OrderNo=140, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000251, Name="开启强制修改密码", Code=ConfigConst.SysForceChangePassword, Value="False", SysFlag=YesNoEnum.Y, Remark="开启强制修改密码", OrderNo=150, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
// 新业务系统记得更改密匙,通过接口(http://localhost:5005/api/sysCommon/smKeyPair)获取
new SysConfig{ Id=1300000000261, Name="国密SM2密匙", Code=ConfigConst.SysSM2Key, Value="04851D329AA3E38C2E7670AFE70E6E70E92F8769CA27C8766B12209A0FFBA4493B603EF7A0B9B1E16F0E8930C0406EA0B179B68DF28E25334BDEC4AE76D907E9E9;3A61D1D30C6302DABFF36201D936D0143EEF0C850AF28C5CA6D5C045AF8C5C8A", SysFlag=YesNoEnum.Y, Remark="国密SM2密匙", OrderNo=160, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2024-11-21 00:00:00") },
new SysConfig{ Id=1300000000271, Name="开启密码强度验证", Code=ConfigConst.SysPasswordStrength, Value="False", SysFlag=YesNoEnum.Y, Remark="开启强制修改密码", OrderNo=150, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000281, Name="密码强度验证正则表达式", Code=ConfigConst.SysPasswordStrengthExpression, Value="(?=^.{6,16}$)(?=.*\\d)(?=.*\\W+)(?=.*[A-Z])(?=.*[a-z])(?!.*\\n).*$", SysFlag=YesNoEnum.Y, Remark="必须须包含大小写字母、数字和特殊字符的组合长度在6-16之间", OrderNo=150, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2024-11-21 00:00:00") },
new SysConfig{ Id=1300000000251, Name="国密SM2密匙", Code=ConfigConst.SysSM2Key, Value="04851D329AA3E38C2E7670AFE70E6E70E92F8769CA27C8766B12209A0FFBA4493B603EF7A0B9B1E16F0E8930C0406EA0B179B68DF28E25334BDEC4AE76D907E9E9;3A61D1D30C6302DABFF36201D936D0143EEF0C850AF28C5CA6D5C045AF8C5C8A", SysFlag=YesNoEnum.Y, Remark="国密SM2密匙", OrderNo=160, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2024-11-21 00:00:00") },
new SysConfig{ Id=1300000000261, Name="开启强制修改密码", Code=ConfigConst.SysForceChangePassword, Value="False", SysFlag=YesNoEnum.Y, Remark="开启强制修改密码", OrderNo=150, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000271, Name="开启密码强度验证", Code=ConfigConst.SysPasswordStrength, Value="False", SysFlag=YesNoEnum.Y, Remark="开启强制修改密码", OrderNo=170, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000281, Name="密码强度验证正则表达式", Code=ConfigConst.SysPasswordStrengthExpression, Value="(?=^.{6,16}$)(?=.*\\d)(?=.*\\W+)(?=.*[A-Z])(?=.*[a-z])(?!.*\\n).*$", SysFlag=YesNoEnum.Y, Remark="必须须包含大小写字母、数字和特殊字符的组合长度在6-16之间", OrderNo=180, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2024-11-21 00:00:00") },
new SysConfig{ Id=1300000000291, Name="密码时间有效期", Code=ConfigConst.SysPasswordExpirationTime, Value="0", SysFlag=YesNoEnum.Y, Remark="默认0表示永不过期否则表示过期天数", OrderNo=190, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2024-12-17 00:00:00") },
new SysConfig{ Id=1300000000301, Name="密码历史记录验证", Code=ConfigConst.SysPasswordRecord, Value="False", SysFlag=YesNoEnum.Y, Remark="是否验证历史密码禁止再次使用", OrderNo=200, GroupCode=ConfigConst.SysDefaultGroup, CreateTime=DateTime.Parse("2024-12-17 00:00:00") },
new SysConfig{ Id=1310000000301, Name="系统主标题", Code=ConfigConst.SysWebTitle, Value="Admin.NET.Pro", SysFlag=YesNoEnum.Y, Remark="系统主标题", OrderNo=300, GroupCode=ConfigConst.SysWebConfigGroup, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1310000000311, Name="系统副标题", Code=ConfigConst.SysWebViceTitle, Value="Admin.NET.Pro", SysFlag=YesNoEnum.Y, Remark="系统副标题", OrderNo=310, GroupCode=ConfigConst.SysWebConfigGroup, CreateTime=DateTime.Parse("2022-02-10 00:00:00") },

View File

@ -284,6 +284,7 @@ public class SysConfigService : IDynamicApiController, ITransient
var sysSecondVer = await GetConfigValueByCode<bool>(ConfigConst.SysSecondVer); // 登录二次验证
var sysCaptcha = await GetConfigValueByCode<bool>(ConfigConst.SysCaptcha); // 图形验证码
var sysForceChangePassword = await GetConfigValueByCode<bool>(ConfigConst.SysForceChangePassword); // 强制修改密码
var sysPasswordExpirationTime = await GetConfigValueByCode<bool>(ConfigConst.SysPasswordExpirationTime); // 密码有效期
var publicKey = App.GetConfig<string>("Cryptogram:PublicKey", true); // 获取密码加解密公钥配置
return new
@ -299,6 +300,7 @@ public class SysConfigService : IDynamicApiController, ITransient
SysSecondVer = sysSecondVer,
SysCaptcha = sysCaptcha,
SysForceChangePassword = sysForceChangePassword,
SysPasswordExpirationTime = sysPasswordExpirationTime,
PublicKey = publicKey
};
}

View File

@ -353,6 +353,18 @@ public class SysUserService : IDynamicApiController, ITransient
user.Password = CryptogramUtil.Encrypt(input.PasswordNew);
}
// 验证历史密码记录
var sysUserPasswordRecord = _sysUserRep.ChangeRepository<SqlSugarRepository<SysUserPasswordRecord>>();
if (await _sysConfigService.GetConfigValueByCode<bool>(ConfigConst.SysPasswordRecord))
{
var md5 = MD5Encryption.Encrypt(input.PasswordNew);
if (await sysUserPasswordRecord.IsAnyAsync(u => u.UserId == user.Id && u.Password == md5))
throw Oops.Oh(ErrorCodeEnum.D1104);
}
// 增加密码历史记录统一MD5存储
await sysUserPasswordRecord.InsertAsync(new SysUserPasswordRecord { UserId = user.Id, Password = MD5Encryption.Encrypt(input.PasswordNew) });
// 更新密码和最新修改时间
user.LastChangePasswordTime = DateTime.Now;
var rows = await _sysUserRep.AsUpdateable(user).UpdateColumns(u => new { u.Password, u.LastChangePasswordTime }).ExecuteCommandAsync();
@ -386,6 +398,25 @@ public class SysUserService : IDynamicApiController, ITransient
return password;
}
/// <summary>
/// 验证密码有效期
/// </summary>
/// <returns></returns>
[DisplayName("验证密码有效期")]
public async Task<bool> VerifyPwdExpirationTime()
{
var sysConfig = await _sysConfigService.GetConfig(ConfigConst.SysPasswordExpirationTime);
if (int.TryParse(sysConfig.Value, out int expirationTime) && expirationTime > 0)
{
var user = await _sysUserRep.GetByIdAsync(_userManager.UserId);
if (user.LastChangePasswordTime == null)
return false;
if ((DateTime.Now - user.LastChangePasswordTime.Value).Days > expirationTime)
return false;
}
return true;
}
/// <summary>
/// 解除登录锁定 🔖
/// </summary>

View File

@ -73,6 +73,20 @@ public static class SqlSugarSetup
if (config.DbSettings.EnableConnEncrypt)
config.ConnectionString = CryptogramUtil.Decrypt(config.ConnectionString);
// SqlFunc 扩展函数
var sqlFuncServices = new List<SqlFuncExternal>
{
// 密码解密
new SqlFuncExternal()
{
UniqueMethodName = "SqlFuncDecrypt",
MethodValue = (expInfo, dbType, expContext) =>
{
return CryptogramUtil.Decrypt(expInfo.Args[0].MemberName.ToString());
}
}
};
var configureExternalServices = new ConfigureExternalServices
{
EntityNameService = (type, entity) => // 处理表
@ -95,6 +109,7 @@ public static class SqlSugarSetup
column.DbColumnName = UtilMethods.ToUnderLine(column.DbColumnName); // 驼峰转下划线
},
DataInfoCacheService = new SqlSugarCache(),
SqlFuncServices = sqlFuncServices
};
config.ConfigureExternalServices = configureExternalServices;
config.InitKeyType = InitKeyType.Attribute;
@ -116,6 +131,18 @@ public static class SqlSugarSetup
config.MoreSettings.MaxParameterNameLength = 30;
}
/// <summary>
/// SqlFunc 扩展函数定义(密码解密)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="password"></param>
/// <returns></returns>
/// <exception cref="NotSupportedException"></exception>
public static string SqlFuncDecrypt<T>(T password)
{
throw new NotSupportedException("Can only be used in expressions");
}
/// <summary>
/// 配置Aop
/// </summary>

View File

@ -127,7 +127,9 @@ const loadSysInfo = () => {
themeConfig.value.secondVer = data.sysSecondVer;
themeConfig.value.captcha = data.sysCaptcha;
//
themeConfig.value.sysForceChangePassword = data.sysForceChangePassword;
themeConfig.value.forceChangePassword = data.sysForceChangePassword;
//
themeConfig.value.passwordExpirationTime = data.sysPasswordExpirationTime;
//
window.__env__.VITE_SM_PUBLIC_KEY = data.publicKey;

View File

@ -226,7 +226,7 @@ export const SysAuthApiAxiosParamCreator = function (configuration?: Configurati
};
},
/**
* /superadmin/123456
*
* @summary 🔖
* @param {LoginInput} body
* @param {*} [options] Override http request option.
@ -528,7 +528,7 @@ export const SysAuthApiFp = function(configuration?: Configuration) {
};
},
/**
* /superadmin/123456
*
* @summary 🔖
* @param {LoginInput} body
* @param {*} [options] Override http request option.
@ -644,7 +644,7 @@ export const SysAuthApiFactory = function (configuration?: Configuration, basePa
return SysAuthApiFp(configuration).apiSysAuthLoginPhonePost(body, options).then((request) => request(axios, basePath));
},
/**
* /superadmin/123456
*
* @summary 🔖
* @param {LoginInput} body
* @param {*} [options] Override http request option.
@ -745,7 +745,7 @@ export class SysAuthApi extends BaseAPI {
return SysAuthApiFp(this.configuration).apiSysAuthLoginPhonePost(body, options).then((request) => request(this.axios, this.basePath));
}
/**
* /superadmin/123456
*
* @summary 🔖
* @param {LoginInput} body
* @param {*} [options] Override http request option.

View File

@ -424,6 +424,49 @@ export const SysRegionApiAxiosParamCreator = function (configuration?: Configura
options: localVarRequestOptions,
};
},
/**
*
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysRegionSyncRegionMzbPost: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysRegion/syncRegionMzb`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication Bearer required
// http bearer authentication required
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
}
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
query.set(key, localVarQueryParameter[key]);
}
for (const key in options.params) {
query.set(key, options.params[key]);
}
localVarUrlObj.search = (new URLSearchParams(query)).toString();
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
};
},
/**
*
* @summary 🔖
@ -641,6 +684,19 @@ export const SysRegionApiFp = function(configuration?: Configuration) {
return axios.request(axiosRequestArgs);
};
},
/**
*
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysRegionSyncRegionMzbPost(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
const localVarAxiosArgs = await SysRegionApiAxiosParamCreator(configuration).apiSysRegionSyncRegionMzbPost(options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
};
},
/**
*
* @summary 🔖
@ -758,6 +814,15 @@ export const SysRegionApiFactory = function (configuration?: Configuration, base
async apiSysRegionSyncRegionMcaCodePost(code: number, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultInt32>> {
return SysRegionApiFp(configuration).apiSysRegionSyncRegionMcaCodePost(code, options).then((request) => request(axios, basePath));
},
/**
*
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysRegionSyncRegionMzbPost(options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
return SysRegionApiFp(configuration).apiSysRegionSyncRegionMzbPost(options).then((request) => request(axios, basePath));
},
/**
*
* @summary 🔖
@ -876,6 +941,16 @@ export class SysRegionApi extends BaseAPI {
public async apiSysRegionSyncRegionMcaCodePost(code: number, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultInt32>> {
return SysRegionApiFp(this.configuration).apiSysRegionSyncRegionMcaCodePost(code, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary 🔖
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysRegionApi
*/
public async apiSysRegionSyncRegionMzbPost(options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
return SysRegionApiFp(this.configuration).apiSysRegionSyncRegionMzbPost(options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary 🔖

View File

@ -18,6 +18,7 @@ import { Configuration } from '../configuration';
// @ts-ignore
import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } from '../base';
import { AddUserInput } from '../models';
import { AdminResultBoolean } from '../models';
import { AdminResultGrantRoleOutput } from '../models';
import { AdminResultInt32 } from '../models';
import { AdminResultInt64 } from '../models';
@ -656,6 +657,49 @@ export const SysUserApiAxiosParamCreator = function (configuration?: Configurati
const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json';
localVarRequestOptions.data = needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || "");
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
};
},
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysUserVerifyPwdExpirationTimePost: async (options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysUser/verifyPwdExpirationTime`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication Bearer required
// http bearer authentication required
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
}
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
query.set(key, localVarQueryParameter[key]);
}
for (const key in options.params) {
query.set(key, options.params[key]);
}
localVarUrlObj.search = (new URLSearchParams(query)).toString();
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
@ -851,6 +895,19 @@ export const SysUserApiFp = function(configuration?: Configuration) {
return axios.request(axiosRequestArgs);
};
},
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysUserVerifyPwdExpirationTimePost(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultBoolean>>> {
const localVarAxiosArgs = await SysUserApiAxiosParamCreator(configuration).apiSysUserVerifyPwdExpirationTimePost(options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
};
},
}
};
@ -989,6 +1046,15 @@ export const SysUserApiFactory = function (configuration?: Configuration, basePa
async apiSysUserUpdatePost(body?: UpdateUserInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
return SysUserApiFp(configuration).apiSysUserUpdatePost(body, options).then((request) => request(axios, basePath));
},
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysUserVerifyPwdExpirationTimePost(options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultBoolean>> {
return SysUserApiFp(configuration).apiSysUserVerifyPwdExpirationTimePost(options).then((request) => request(axios, basePath));
},
};
};
@ -1141,4 +1207,14 @@ export class SysUserApi extends BaseAPI {
public async apiSysUserUpdatePost(body?: UpdateUserInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
return SysUserApiFp(this.configuration).apiSysUserUpdatePost(body, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysUserApi
*/
public async apiSysUserVerifyPwdExpirationTimePost(options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultBoolean>> {
return SysUserApiFp(this.configuration).apiSysUserVerifyPwdExpirationTimePost(options).then((request) => request(this.axios, this.basePath));
}
}

View File

@ -125,7 +125,7 @@ export interface AddPosInput {
status?: StatusEnum;
/**
*
*
*
* @type {Array<SysUser>}
* @memberof AddPosInput

View File

@ -46,6 +46,7 @@ export enum DbType {
NUMBER_25 = 25,
NUMBER_26 = 26,
NUMBER_27 = 27,
NUMBER_28 = 28,
NUMBER_900 = 900
}

View File

@ -35,7 +35,7 @@ export interface LoginInput {
*
* @type {string}
* @memberof LoginInput
* @example 123456
* @example 12345678
*/
password: string;

View File

@ -35,7 +35,7 @@ export interface LoginPhoneInput {
*
* @type {string}
* @memberof LoginPhoneInput
* @example 123456
* @example 1234
*/
code: string;

View File

@ -133,7 +133,7 @@ export interface PagePosOutput {
status?: StatusEnum;
/**
*
*
*
* @type {Array<SysUser>}
* @memberof PagePosOutput

View File

@ -133,7 +133,7 @@ export interface PosOutput {
status?: StatusEnum;
/**
*
*
*
* @type {Array<SysUser>}
* @memberof PosOutput

View File

@ -125,7 +125,7 @@ export interface UpdatePosInput {
status?: StatusEnum;
/**
*
*
*
* @type {Array<SysUser>}
* @memberof UpdatePosInput

View File

@ -104,7 +104,7 @@ import { signalR } from '/@/views/system/onlineUser/signalR';
import { Avatar, CircleCloseFilled, Loading, Lock } from '@element-plus/icons-vue';
import { clearAccessTokens, getAPI } from '/@/utils/axios-utils';
import { SysAuthApi, SysNoticeApi } from '/@/api-services/api';
import { SysAuthApi, SysNoticeApi, SysUserApi } from '/@/api-services/api';
//
const UserNews = defineAsyncComponent(() => import('/@/layout/navBars/topBar/userNews.vue'));
@ -262,8 +262,8 @@ onMounted(async () => {
// notice.readStatus = 1;
// });
//
forceChangePassword();
//
await changePassword();
});
// //
// onUnmounted(() => {
@ -281,18 +281,28 @@ const receiveNotice = (msg: any) => {
});
Push.create('提示', {
body: '你有一条新的消息',
icon: 'logo.png', //public
icon: 'logo.png', // public
timeout: 4500, //
});
};
//
const forceChangePassword = () => {
var forceChangePasswordEnabled = themeConfig.value.sysForceChangePassword ?? true;
if (!forceChangePasswordEnabled) return;
//
const changePassword = async () => {
//
var enabledForceChangePassword = themeConfig.value.forceChangePassword ?? true;
if (enabledForceChangePassword) {
if (userInfos.value.lastChangePasswordTime == null || userInfos.value.lastChangePasswordTime == undefined) {
changePasswordRef.value?.openDialog();
}
}
if (userInfos.value.lastChangePasswordTime == null || userInfos.value.lastChangePasswordTime == undefined) {
changePasswordRef.value?.openDialog();
//
var enabledPasswordExpirationTime = themeConfig.value.passwordExpirationTime ?? true;
if (enabledPasswordExpirationTime) {
var res = await getAPI(SysUserApi).apiSysUserVerifyPwdExpirationTimePost();
if (!res.data.result) {
changePasswordRef.value?.openDialog();
}
}
};
</script>

View File

@ -100,6 +100,7 @@ declare interface ThemeConfigState {
icpUrl: string; // Icp地址
secondVer: boolean; // 是否开启二级验证
captcha: boolean; // 是否开启验证码
sysForceChangePassword: boolean; // 是否开启强制修改密码
forceChangePassword: boolean; // 是否开启强制修改密码
passwordExpirationTime: boolean; // 是否验证密码有效期
};
}