feat: 完善、优化登录控制逻辑

This commit is contained in:
JXDN
2025-09-08 16:24:25 +08:00
parent c4e095a3ee
commit a3a55242fa
14 changed files with 24 additions and 155 deletions
@@ -524,46 +524,4 @@ export class AuthService extends BaseService<User> {
throw HttpExceptionFactory.internal("退出登录失败", BusinessCode.OPERATION_FAILED);
}
}
/**
* 设置多端登录开关
*
* @param enabled 是否启用
* @returns 设置结果
*/
async setMultiLoginEnabled(enabled: boolean): Promise<{ success: boolean; message: string }> {
try {
const result = await this.userTokenService.setMultiLoginEnabled(enabled);
return {
success: result,
message: result ? "设置成功" : "设置失败",
};
} catch (error) {
this.logger.error(`设置多端登录开关失败: ${error.message}`);
throw HttpExceptionFactory.internal("设置失败", BusinessCode.OPERATION_FAILED);
}
}
/**
* 设置单终端登录开关
*
* @param enabled 是否启用
* @returns 设置结果
*/
async setSingleTerminalLoginEnabled(
enabled: boolean,
): Promise<{ success: boolean; message: string }> {
try {
const result = await this.userTokenService.setSingleTerminalLoginEnabled(enabled);
return {
success: result,
message: result ? "设置成功" : "设置失败",
};
} catch (error) {
this.logger.error(`设置单终端登录开关失败: ${error.message}`);
throw HttpExceptionFactory.internal("设置失败", BusinessCode.OPERATION_FAILED);
}
}
}
@@ -25,16 +25,6 @@ export class UserTokenService extends BaseService<UserToken> {
*/
private readonly TOKEN_CONFIG_KEY = "token";
/**
* 多端登录配置键
*/
private readonly MULTI_LOGIN_CONFIG_KEY = "multi_login";
/**
* 单终端登录配置键
*/
private readonly SINGLE_TERMINAL_LOGIN_CONFIG_KEY = "single_terminal_login";
/**
* 令牌缓存前缀
*/
@@ -77,11 +67,11 @@ export class UserTokenService extends BaseService<UserToken> {
// 获取令牌配置
const tokenConfig = await this.getTokenConfig();
// 获取单终端登录配置
const isSingleTerminalLoginEnabled = await this.isSingleTerminalLoginEnabled();
// 获取登录设置配置
const loginSettings = await this.getLoginSettings();
// 如果启用单终端登录,则撤销该用户在同一终端的所有其他令牌
if (isSingleTerminalLoginEnabled) {
// 如果不允许多处登录,则撤销该用户在同一终端的所有其他令牌
if (!loginSettings.allowMultipleLogin) {
await this.revokeTokensByTerminal(userId, terminal);
}
@@ -403,74 +393,22 @@ export class UserTokenService extends BaseService<UserToken> {
}
/**
* 检查是否启用多端登录
* 获取登录设置配置
*
* @returns 是否启用多端登录
* @returns 登录设置配置
*/
async isMultiLoginEnabled(): Promise<boolean> {
private async getLoginSettings(): Promise<{ allowMultipleLogin: boolean }> {
try {
return await this.dictService.get<boolean>(this.MULTI_LOGIN_CONFIG_KEY, false, "auth");
} catch (error) {
this.logger.warn(`获取多端登录配置失败,使用默认配置: ${error.message}`);
return false;
}
}
/**
* 设置是否启用多端登录
*
* @param enabled 是否启用
* @returns 设置结果
*/
async setMultiLoginEnabled(enabled: boolean): Promise<boolean> {
try {
await this.dictService.set(this.MULTI_LOGIN_CONFIG_KEY, enabled, {
group: "auth", // 明确指定分组为 auth
description: "是否允许用户在同一终端多处登录",
});
return true;
} catch (error) {
this.logger.error(`设置多端登录配置失败: ${error.message}`);
return false;
}
}
/**
* 检查是否启用单终端登录
*
* @returns 是否启用单终端登录
*/
async isSingleTerminalLoginEnabled(): Promise<boolean> {
try {
return await this.dictService.get<boolean>(
this.SINGLE_TERMINAL_LOGIN_CONFIG_KEY,
true,
const config = await this.dictService.get<{ allowMultipleLogin: boolean }>(
"login_settings",
{ allowMultipleLogin: false }, // 默认不允许多处登录
"auth",
);
} catch (error) {
this.logger.warn(`获取单终端登录配置失败,使用默认配置: ${error.message}`);
return true; // 默认启用单终端登录
}
}
/**
* 设置是否启用单终端登录
*
* @param enabled 是否启用
* @returns 设置结果
*/
async setSingleTerminalLoginEnabled(enabled: boolean): Promise<boolean> {
try {
await this.dictService.set(this.SINGLE_TERMINAL_LOGIN_CONFIG_KEY, enabled, {
group: "auth", // 明确指定分组为 auth
description: "是否启用单终端登录(同一类型终端登录时挤掉对方)",
});
return true;
return config;
} catch (error) {
this.logger.error(`设置单终端登录配置失败: ${error.message}`);
return false;
this.logger.warn(`获取登录设置配置失败,使用默认配置: ${error.message}`);
return { allowMultipleLogin: false }; // 默认不允许多处登录
}
}
}
@@ -434,8 +434,8 @@ export class UserController extends BaseController {
*/
private getDefaultLoginSettings(): LoginSettingsConfig {
return {
allowedLoginMethods: [LOGIN_TYPE.ACCOUNT, LOGIN_TYPE.PHONE, LOGIN_TYPE.WECHAT],
allowedRegisterMethods: [LOGIN_TYPE.ACCOUNT, LOGIN_TYPE.PHONE],
allowedLoginMethods: [LOGIN_TYPE.ACCOUNT, LOGIN_TYPE.WECHAT],
allowedRegisterMethods: [LOGIN_TYPE.ACCOUNT, LOGIN_TYPE.WECHAT],
defaultLoginMethod: LOGIN_TYPE.ACCOUNT,
allowMultipleLogin: false,
showPolicyAgreement: true,
@@ -127,31 +127,6 @@ export class AuthController extends BaseController {
return this.authService.logout(token);
}
/**
* 设置多端登录开关
*
* @param enabled 是否启用
* @returns 设置结果
*/
@Post("multi-login")
async setMultiLoginEnabled(@Body("enabled") enabled: boolean) {
return this.authService.setMultiLoginEnabled(enabled);
}
/**
* 获取多端登录开关状态
*
* @returns 多端登录开关状态
*/
@Get("multi-login")
async getMultiLoginStatus() {
// 从用户令牌服务中获取多端登录状态
const isEnabled = await this.authService.userTokenService.isMultiLoginEnabled();
return {
enabled: isEnabled,
};
}
/**
* 获取微信二维码
*
@@ -336,8 +336,8 @@ export class UserController extends BaseController {
*/
private getDefaultLoginSettings() {
return {
allowedLoginMethods: [LOGIN_TYPE.ACCOUNT, LOGIN_TYPE.PHONE, LOGIN_TYPE.WECHAT],
allowedRegisterMethods: [LOGIN_TYPE.ACCOUNT, LOGIN_TYPE.PHONE],
allowedLoginMethods: [LOGIN_TYPE.ACCOUNT, LOGIN_TYPE.WECHAT],
allowedRegisterMethods: [LOGIN_TYPE.ACCOUNT, LOGIN_TYPE.WECHAT],
defaultLoginMethod: LOGIN_TYPE.ACCOUNT,
allowMultipleLogin: false,
showPolicyAgreement: true,
-1
View File
@@ -9,7 +9,6 @@ export declare const LOGIN_TYPE: {
/** 账号登录 */
readonly ACCOUNT: 1;
/** 手机号登录 */
readonly PHONE: 2;
/** 微信登录 */
readonly WECHAT: 3;
};
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,eAAO,MAAM,UAAU;IACnB,WAAW;;IAEX,YAAY;;IAEZ,WAAW;;CAEL,CAAC;AACX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC"}
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,eAAO,MAAM,UAAU;IACnB,WAAW;;IAEX,YAAY;IAEZ,WAAW;;CAEL,CAAC;AACX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC"}
+1 -1
View File
@@ -9,7 +9,7 @@ export const LOGIN_TYPE = {
/** 账号登录 */
ACCOUNT: 1,
/** 手机号登录 */
PHONE: 2,
// PHONE: 2,
/** 微信登录 */
WECHAT: 3,
};
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACtB,WAAW;IACX,OAAO,EAAE,CAAC;IACV,YAAY;IACZ,KAAK,EAAE,CAAC;IACR,WAAW;IACX,MAAM,EAAE,CAAC;CACH,CAAC"}
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACtB,WAAW;IACX,OAAO,EAAE,CAAC;IACV,YAAY;IACZ,YAAY;IACZ,WAAW;IACX,MAAM,EAAE,CAAC;CACH,CAAC"}
-1
View File
@@ -9,7 +9,6 @@ export declare const LOGIN_TYPE: {
/** 账号登录 */
readonly ACCOUNT: 1;
/** 手机号登录 */
readonly PHONE: 2;
/** 微信登录 */
readonly WECHAT: 3;
};
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,eAAO,MAAM,UAAU;IACnB,WAAW;;IAEX,YAAY;;IAEZ,WAAW;;CAEL,CAAC;AACX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC"}
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,eAAO,MAAM,UAAU;IACnB,WAAW;;IAEX,YAAY;IAEZ,WAAW;;CAEL,CAAC;AACX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC"}
+1 -1
View File
@@ -12,7 +12,7 @@ exports.LOGIN_TYPE = {
/** 账号登录 */
ACCOUNT: 1,
/** 手机号登录 */
PHONE: 2,
// PHONE: 2,
/** 微信登录 */
WECHAT: 3,
};
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH;;GAEG;AACU,QAAA,UAAU,GAAG;IACtB,WAAW;IACX,OAAO,EAAE,CAAC;IACV,YAAY;IACZ,KAAK,EAAE,CAAC;IACR,WAAW;IACX,MAAM,EAAE,CAAC;CACH,CAAC"}
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH;;GAEG;AACU,QAAA,UAAU,GAAG;IACtB,WAAW;IACX,OAAO,EAAE,CAAC;IACV,YAAY;IACZ,YAAY;IACZ,WAAW;IACX,MAAM,EAAE,CAAC;CACH,CAAC"}
+1 -1
View File
@@ -10,7 +10,7 @@ export const LOGIN_TYPE = {
/** 账号登录 */
ACCOUNT: 1,
/** 手机号登录 */
PHONE: 2,
// PHONE: 2,
/** 微信登录 */
WECHAT: 3,
} as const;