fix:修复Linux DO授权登录不显示默认密码弹窗
This commit is contained in:
+45
-4
@@ -250,10 +250,10 @@ async def _handle_callback(
|
|||||||
trust_level=trust_level
|
trust_level=trust_level
|
||||||
)
|
)
|
||||||
|
|
||||||
# 3.1. 自动绑定密码(如果还没有设置)
|
# 3.1. 检查是否是首次登录(没有密码记录)
|
||||||
if not await password_manager.has_password(user.user_id):
|
is_first_login = not await password_manager.has_password(user.user_id)
|
||||||
default_password = await password_manager.set_password(user.user_id, username)
|
if is_first_login:
|
||||||
logger.info(f"用户 {user.user_id} ({username}) 自动绑定默认密码: {default_password}")
|
logger.info(f"用户 {user.user_id} ({username}) 首次登录,需要初始化密码")
|
||||||
|
|
||||||
# Settings 将在首次访问设置页面时自动创建(延迟初始化)
|
# Settings 将在首次访问设置页面时自动创建(延迟初始化)
|
||||||
|
|
||||||
@@ -289,6 +289,17 @@ async def _handle_callback(
|
|||||||
samesite="lax"
|
samesite="lax"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 如果是首次登录,设置标记 Cookie(5分钟有效,仅用于前端显示初始密码提示)
|
||||||
|
if is_first_login:
|
||||||
|
redirect_response.set_cookie(
|
||||||
|
key="first_login",
|
||||||
|
value="true",
|
||||||
|
max_age=300, # 5分钟有效
|
||||||
|
httponly=False, # 前端需要读取
|
||||||
|
samesite="lax"
|
||||||
|
)
|
||||||
|
logger.info(f"✅ [OAuth登录] 用户 {user.user_id} 首次登录,已设置 first_login 标记")
|
||||||
|
|
||||||
return redirect_response
|
return redirect_response
|
||||||
|
|
||||||
|
|
||||||
@@ -446,6 +457,36 @@ async def set_user_password(request: Request, password_req: SetPasswordRequest):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/password/initialize", response_model=SetPasswordResponse)
|
||||||
|
async def initialize_user_password(request: Request, password_req: SetPasswordRequest):
|
||||||
|
"""
|
||||||
|
初始化首次登录用户的密码
|
||||||
|
|
||||||
|
用于首次通过 Linux DO 授权登录的用户,可以选择设置自定义密码或使用默认密码
|
||||||
|
"""
|
||||||
|
if not hasattr(request.state, "user") or not request.state.user:
|
||||||
|
raise HTTPException(status_code=401, detail="未登录")
|
||||||
|
|
||||||
|
user = request.state.user
|
||||||
|
|
||||||
|
# 检查是否已经有密码(防止重复初始化)
|
||||||
|
if await password_manager.has_password(user.user_id):
|
||||||
|
raise HTTPException(status_code=400, detail="密码已经初始化,请使用密码修改功能")
|
||||||
|
|
||||||
|
# 验证密码强度(至少6个字符)
|
||||||
|
if len(password_req.password) < 6:
|
||||||
|
raise HTTPException(status_code=400, detail="密码长度至少为6个字符")
|
||||||
|
|
||||||
|
# 设置密码
|
||||||
|
await password_manager.set_password(user.user_id, user.username, password_req.password)
|
||||||
|
logger.info(f"用户 {user.user_id} ({user.username}) 初始化密码成功")
|
||||||
|
|
||||||
|
return SetPasswordResponse(
|
||||||
|
success=True,
|
||||||
|
message="密码初始化成功"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/bind/login", response_model=LocalLoginResponse)
|
@router.post("/bind/login", response_model=LocalLoginResponse)
|
||||||
async def bind_account_login(request: LocalLoginRequest, response: Response):
|
async def bind_account_login(request: LocalLoginRequest, response: Response):
|
||||||
"""使用绑定的账号密码登录(LinuxDO授权后绑定的账号)"""
|
"""使用绑定的账号密码登录(LinuxDO授权后绑定的账号)"""
|
||||||
|
|||||||
@@ -20,23 +20,35 @@ export default function AuthCallback() {
|
|||||||
try {
|
try {
|
||||||
// 后端会通过 Cookie 自动设置认证信息
|
// 后端会通过 Cookie 自动设置认证信息
|
||||||
// 这里只需要验证登录状态
|
// 这里只需要验证登录状态
|
||||||
await authApi.getCurrentUser();
|
const currentUser = await authApi.getCurrentUser();
|
||||||
|
|
||||||
// 检查密码状态
|
|
||||||
const pwdStatus = await authApi.getPasswordStatus();
|
|
||||||
setPasswordStatus(pwdStatus);
|
|
||||||
|
|
||||||
|
// 检查是否是首次登录(通过 Cookie 标记)
|
||||||
|
const isFirstLogin = document.cookie.includes('first_login=true');
|
||||||
|
|
||||||
setStatus('success');
|
setStatus('success');
|
||||||
|
|
||||||
// 只有在用户完全没有密码时才显示密码设置提示
|
if (isFirstLogin) {
|
||||||
// 如果已经有密码(无论是默认密码还是自定义密码),都不再提示
|
// 首次登录:生成默认密码并显示提示
|
||||||
if (!pwdStatus.has_password) {
|
const defaultPassword = `${currentUser.username}@666`;
|
||||||
|
const pwdStatus = {
|
||||||
|
has_password: false,
|
||||||
|
has_custom_password: false,
|
||||||
|
username: currentUser.username,
|
||||||
|
default_password: defaultPassword
|
||||||
|
};
|
||||||
|
setPasswordStatus(pwdStatus);
|
||||||
|
|
||||||
|
// 清除首次登录标记 Cookie
|
||||||
|
document.cookie = 'first_login=; path=/; max-age=0';
|
||||||
|
|
||||||
|
// 显示密码初始化弹窗
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setShowPasswordModal(true);
|
setShowPasswordModal(true);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 非首次登录:正常流程
|
||||||
// 从 sessionStorage 获取重定向地址
|
// 从 sessionStorage 获取重定向地址
|
||||||
const redirect = sessionStorage.getItem('login_redirect') || '/';
|
const redirect = sessionStorage.getItem('login_redirect') || '/';
|
||||||
sessionStorage.removeItem('login_redirect');
|
sessionStorage.removeItem('login_redirect');
|
||||||
@@ -129,23 +141,33 @@ export default function AuthCallback() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSetPassword = async () => {
|
const handleSetPassword = async () => {
|
||||||
if (!newPassword) {
|
// 如果没有输入新密码,使用默认密码
|
||||||
|
const passwordToSet = newPassword || passwordStatus?.default_password;
|
||||||
|
|
||||||
|
if (!passwordToSet) {
|
||||||
message.error('请输入新密码');
|
message.error('请输入新密码');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (newPassword.length < 6) {
|
if (passwordToSet.length < 6) {
|
||||||
message.error('密码长度至少为6个字符');
|
message.error('密码长度至少为6个字符');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (newPassword !== confirmPassword) {
|
if (newPassword && newPassword !== confirmPassword) {
|
||||||
message.error('两次输入的密码不一致');
|
message.error('两次输入的密码不一致');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setSettingPassword(true);
|
setSettingPassword(true);
|
||||||
try {
|
try {
|
||||||
await authApi.setPassword(newPassword);
|
// 首次登录使用初始化接口,后续使用修改接口
|
||||||
message.success('密码设置成功');
|
const isFirstLogin = !passwordStatus?.has_password;
|
||||||
|
if (isFirstLogin) {
|
||||||
|
await authApi.initializePassword(passwordToSet);
|
||||||
|
message.success('密码初始化成功');
|
||||||
|
} else {
|
||||||
|
await authApi.setPassword(passwordToSet);
|
||||||
|
message.success('密码设置成功');
|
||||||
|
}
|
||||||
setShowPasswordModal(false);
|
setShowPasswordModal(false);
|
||||||
|
|
||||||
// 继续后续流程
|
// 继续后续流程
|
||||||
@@ -172,7 +194,17 @@ export default function AuthCallback() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSkipPasswordSetting = () => {
|
const handleSkipPasswordSetting = async () => {
|
||||||
|
// 首次登录时,如果跳过设置,使用默认密码初始化
|
||||||
|
const isFirstLogin = !passwordStatus?.has_password;
|
||||||
|
if (isFirstLogin && passwordStatus?.default_password) {
|
||||||
|
try {
|
||||||
|
await authApi.initializePassword(passwordStatus.default_password);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('初始化默认密码失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setShowPasswordModal(false);
|
setShowPasswordModal(false);
|
||||||
|
|
||||||
// 继续后续流程
|
// 继续后续流程
|
||||||
|
|||||||
@@ -148,6 +148,9 @@ export const authApi = {
|
|||||||
setPassword: (password: string) =>
|
setPassword: (password: string) =>
|
||||||
api.post<unknown, { success: boolean; message: string }>('/auth/password/set', { password }),
|
api.post<unknown, { success: boolean; message: string }>('/auth/password/set', { password }),
|
||||||
|
|
||||||
|
initializePassword: (password: string) =>
|
||||||
|
api.post<unknown, { success: boolean; message: string }>('/auth/password/initialize', { password }),
|
||||||
|
|
||||||
refreshSession: () => api.post<unknown, { message: string; expire_at: number; remaining_minutes: number }>('/auth/refresh'),
|
refreshSession: () => api.post<unknown, { message: string; expire_at: number; remaining_minutes: number }>('/auth/refresh'),
|
||||||
|
|
||||||
logout: () => api.post('/auth/logout'),
|
logout: () => api.post('/auth/logout'),
|
||||||
|
|||||||
Reference in New Issue
Block a user