Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 48 additions & 7 deletions backend/apps/system/api/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,29 @@
from fastapi import APIRouter, Depends, HTTPException, Request
from fastapi.security import OAuth2PasswordRequestForm
from apps.system.schemas.logout_schema import LogoutSchema
from apps.system.schemas.system_schema import BaseUserDTO
from apps.system.schemas.system_schema import BaseUserDTO, LoginPwdEditor
from common.core.deps import SessionDep, Trans
from common.utils.crypto import sqlbot_decrypt
from ..crud.user import authenticate
from common.core.security import create_access_token
from ..crud.user import authenticate, check_pwd_format, clean_user_cache, get_db_user
from common.core.security import create_access_token, default_pwd, md5pwd, verify_md5pwd
from datetime import timedelta
from common.core.config import settings
from common.core.schemas import Token
from sqlbot_xpack.authentication.manage import logout as xpack_logout
from sqlbot_xpack.config.arg_manage import get_group_args

from common.audit.models.log_model import OperationType, OperationModules
from common.audit.schemas.logger_decorator import system_log, LogConfig

router = APIRouter(tags=["login"], prefix="/login")


async def initial_pwd_disabled(session) -> bool:
login_args = await get_group_args(session=session, flag='login')
disabled_arg = next((a for a in login_args if a.pkey == 'login.initial_pwd_disabled'), None)
return bool(disabled_arg and str(disabled_arg.pval).strip().lower() == 'true')


@router.post("/access-token")
@system_log(LogConfig(
operation_type=OperationType.LOGIN,
Expand All @@ -39,13 +47,46 @@ async def local_login(
raise HTTPException(status_code=400, detail=trans('i18n_login.user_disable', msg = trans('i18n_concat_admin')))
if user.origin is not None and user.origin != 0:
raise HTTPException(status_code=400, detail=trans('i18n_login.origin_error'))
if (
user.id != 1
and await initial_pwd_disabled(session)
and verify_md5pwd(default_pwd(), user.password)
):
return Token(access_token='', need_change_pwd=True)
access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
user_dict = user.to_dict()
return Token(access_token=create_access_token(
user_dict, expires_delta=access_token_expires
))
return Token(
access_token=create_access_token(user_dict, expires_delta=access_token_expires),
need_change_pwd=False,
)


@router.post("/change-pwd")
@system_log(LogConfig(
operation_type=OperationType.UPDATE_PWD,
module=OperationModules.USER,
result_id_expr="id"
))
async def login_change_pwd(session: SessionDep, trans: Trans, editor: LoginPwdEditor):
origin_account = await sqlbot_decrypt(editor.account)
origin_pwd = await sqlbot_decrypt(editor.pwd)
new_pwd = await sqlbot_decrypt(editor.new_pwd)
user: BaseUserDTO = authenticate(session=session, account=origin_account, password=origin_pwd)
if not user:
raise HTTPException(status_code=400, detail=trans('i18n_login.account_pwd_error'))
if user.origin is not None and user.origin != 0:
raise HTTPException(status_code=400, detail=trans('i18n_login.origin_error'))
if not check_pwd_format(new_pwd):
raise HTTPException(status_code=400, detail=trans('i18n_format_invalid', key = trans('i18n_user.password')))
if await initial_pwd_disabled(session) and new_pwd == default_pwd():
raise HTTPException(status_code=400, detail=trans('i18n_login.new_pwd_is_initial'))
db_user = get_db_user(session=session, user_id=user.id)
db_user.password = md5pwd(new_pwd)
session.add(db_user)
await clean_user_cache(user.id)
return db_user

@router.post("/logout")
@router.post("/logout")
async def logout(session: SessionDep, request: Request, dto: LogoutSchema):
if dto.origin != 0:
return await xpack_logout(session, request, dto)
Expand Down
7 changes: 6 additions & 1 deletion backend/apps/system/api/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from common.core.sqlbot_cache import clear_cache
from common.core.config import settings
from apps.swagger.i18n import PLACEHOLDER_PREFIX
from sqlbot_xpack.config.arg_manage import get_group_args

router = APIRouter(tags=["system_user"], prefix="/user")

Expand Down Expand Up @@ -45,7 +46,11 @@ async def user_info(current_user: CurrentUser) -> UserInfoDTO:

@router.get("/defaultPwd", include_in_schema=False)
@require_permissions(permission=SqlbotPermission(role=['admin']))
async def default_pwd() -> str:
async def default_pwd(session: SessionDep) -> str:
login_args = await get_group_args(session=session, flag='login')
hidden_arg = next((a for a in login_args if a.pkey == 'login.initial_pwd_hidden'), None)
if hidden_arg and str(hidden_arg.pval).strip().lower() == 'true':
return ''
return settings.DEFAULT_PWD

@router.get("/pager/{pageNum}/{pageSize}", response_model=PaginatedResponse[UserGrid], summary=f"{PLACEHOLDER_PREFIX}system_user_grid", description=f"{PLACEHOLDER_PREFIX}system_user_grid")
Expand Down
6 changes: 6 additions & 0 deletions backend/apps/system/schemas/system_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ class PwdEditor(BaseModel):
new_pwd: str = Field(description=f"{PLACEHOLDER_PREFIX}new_pwd")


class LoginPwdEditor(BaseModel):
account: str = Field(description=f"{PLACEHOLDER_PREFIX}user_account")
pwd: str = Field(description=f"{PLACEHOLDER_PREFIX}origin_pwd")
new_pwd: str = Field(description=f"{PLACEHOLDER_PREFIX}new_pwd")


class UserWsBase(BaseModel):
uid_list: list[int] = Field(description=f"{PLACEHOLDER_PREFIX}uid")
oid: Optional[int] = Field(default=None, description=f"{PLACEHOLDER_PREFIX}oid")
Expand Down
1 change: 1 addition & 0 deletions backend/common/core/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class Token(SQLModel):
access_token: str
token_type: str = "bearer"
platform_info: Optional[dict] = None
need_change_pwd: Optional[bool] = None

class XOAuth2PasswordBearer(OAuth2PasswordBearer):
async def __call__(self, request: Request) -> Optional[str]:
Expand Down
3 changes: 2 additions & 1 deletion backend/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"user_disable": "Account is disabled, {msg}",
"origin_error": "Invalid login method",
"prohibit_auto_create": "Automatically creating users is prohibited. Please synchronize users first",
"no_platform_user": "Account does not exist. Please sync the user first."
"no_platform_user": "Account does not exist. Please sync the user first.",
"new_pwd_is_initial": "The new password cannot be the initial password"
},
"i18n_user": {
"account": "Account",
Expand Down
3 changes: 2 additions & 1 deletion backend/locales/ko-KR.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"user_disable": "계정이 비활성화되었습니다, {msg}",
"origin_error": "잘못된 로그인 방식입니다",
"prohibit_auto_create": "사용자 자동 생성이 금지되어 있습니다. 먼저 사용자를 동기화해 주세요",
"no_platform_user": "계정이 존재하지 않습니다. 먼저 사용자를 동기화하세요."
"no_platform_user": "계정이 존재하지 않습니다. 먼저 사용자를 동기화하세요.",
"new_pwd_is_initial": "새 비밀번호는 초기 비밀번호로 설정할 수 없습니다"
},
"i18n_user": {
"account": "계정",
Expand Down
3 changes: 2 additions & 1 deletion backend/locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"user_disable": "账号已禁用,{msg}",
"origin_error": "登录方式错误",
"prohibit_auto_create": "禁止自动创建用户,请先同步用户",
"no_platform_user": "账号不存在,请先同步用户"
"no_platform_user": "账号不存在,请先同步用户",
"new_pwd_is_initial": "新密码不能为初始密码"
},
"i18n_user": {
"account": "账号",
Expand Down
3 changes: 2 additions & 1 deletion backend/locales/zh-TW.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"user_disable": "帳號已禁用,{msg}",
"origin_error": "登入方式錯誤",
"prohibit_auto_create": "禁止自動建立用戶,請先同步用戶",
"no_platform_user": "帳號不存在,請先同步用戶"
"no_platform_user": "帳號不存在,請先同步用戶",
"new_pwd_is_initial": "新密碼不能為初始密碼"
},
"i18n_user": {
"account": "帳號",
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/api/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ export const AuthApi = {
},
})
},
changePwd: (data: { account: string; pwd: string; new_pwd: string }) => {
const entry = {
account: LicenseGenerator.sqlbotEncrypt(data.account),
pwd: LicenseGenerator.sqlbotEncrypt(data.pwd),
new_pwd: LicenseGenerator.sqlbotEncrypt(data.new_pwd),
}
return request.post('/login/change-pwd', entry)
},
logout: (data: any) => request.post('/login/logout', data),
info: () => request.get('/user/info'),
}
7 changes: 6 additions & 1 deletion frontend/src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@
"closed_by_default": "In the Question Count window, control whether the model thinking process is expanded or closed by default.",
"and_platform_integration": "Authentication-related",
"login_settings": "Login Settings",
"default_login": "Default Login Method"
"default_login": "Default Login Method",
"disable_initial_password": "Disable Initial Password",
"hide_initial_password": "Hide Initial Password on Page"
},
"prompt": {
"default_password": "Default password:{msg}",
Expand Down Expand Up @@ -932,6 +934,9 @@
"default_login": "Default",
"ldap_login": "LDAP Login",
"account_login": "Account Login",
"force_change_pwd_title": "Change Initial Password",
"force_change_pwd_tips": "Your current password is the system initial password. Please change it and log in again.",
"force_change_pwd_success": "Password changed successfully",
"other_login": "Other Login Methods",
"pwd_invalid_error": "Password has expired, please contact administrator to modify or reset",
"pwd_exp_tips": "Password will expire in {0} days, please change it as soon as possible",
Expand Down
7 changes: 6 additions & 1 deletion frontend/src/i18n/ko-KR.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@
"closed_by_default": "질문 수 창에서 모델 사고 프로세스를 기본적으로 확장할지 또는 닫을지 여부를 제어합니다.",
"and_platform_integration": "인증 관련",
"login_settings": "로그인 설정",
"default_login": "기본 로그인 방식"
"default_login": "기본 로그인 방식",
"disable_initial_password": "초기 비밀번호 비활성화",
"hide_initial_password": "페이지에서 초기 비밀번호 숨기기"
},
"prompt": {
"default_password:": "기본 비밀번호:{msg}",
Expand Down Expand Up @@ -932,6 +934,9 @@
"default_login": "기본값",
"ldap_login": "LDAP 로그인",
"account_login": "계정 로그인",
"force_change_pwd_title": "초기 비밀번호 변경",
"force_change_pwd_tips": "현재 비밀번호는 시스템 초기 비밀번호입니다. 비밀번호를 변경한 후 로그인해 주세요.",
"force_change_pwd_success": "비밀번호가 변경되었습니다",
"other_login": "기타 로그인 방식",
"pwd_invalid_error": "비밀번호가 만료되었습니다. 관리자에게 문의하여 수정 또는 재설정해 주세요",
"pwd_exp_tips": "비밀번호가 {0}일 후에 만료됩니다.尽快尽快 비밀번호를 변경해 주세요",
Expand Down
7 changes: 6 additions & 1 deletion frontend/src/i18n/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@
"closed_by_default": "在问数窗口中,控制模型思考过程默认展开或者关闭",
"and_platform_integration": "登录认证相关",
"login_settings": "登录设置",
"default_login": "默认登录方式"
"default_login": "默认登录方式",
"disable_initial_password": "禁用初始密码",
"hide_initial_password": "页面隐藏初始密码"
},
"prompt": {
"default_password": "默认密码:{msg}",
Expand Down Expand Up @@ -932,6 +934,9 @@
"default_login": "默认",
"ldap_login": "LDAP 登录",
"account_login": "账号登录",
"force_change_pwd_title": "修改初始密码",
"force_change_pwd_tips": "当前密码为系统初始密码,请修改密码后再登录",
"force_change_pwd_success": "密码修改成功",
"other_login": "其他登录方式",
"pwd_invalid_error": "密码已过期请联系管理员修改或重置",
"pwd_exp_tips": "密码在 {0} 天后过期,请尽快修改密码",
Expand Down
7 changes: 6 additions & 1 deletion frontend/src/i18n/zh-TW.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@
"closed_by_default": "在問數視窗中,控制模型思考過程預設展開或者關閉",
"and_platform_integration": "登入認證相關",
"login_settings": "登入設定",
"default_login": "預設登入方式"
"default_login": "預設登入方式",
"disable_initial_password": "禁用初始密碼",
"hide_initial_password": "頁面隱藏初始密碼"
},
"prompt": {
"default_password": "預設密碼:{msg}",
Expand Down Expand Up @@ -932,6 +934,9 @@
"default_login": "預設",
"ldap_login": "LDAP 登入",
"account_login": "帳號登入",
"force_change_pwd_title": "修改初始密碼",
"force_change_pwd_tips": "目前密碼為系統初始密碼,請修改密碼後再登入",
"force_change_pwd_success": "密碼修改成功",
"other_login": "其他登入方式",
"pwd_invalid_error": "密碼已過期請聯繫管理員修改或重設",
"pwd_exp_tips": "密碼在 {0} 天後過期,請盡快修改密碼",
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/stores/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ export const UserStore = defineStore('user', {
actions: {
async login(formData: { username: string; password: string }) {
const res: any = await AuthApi.login(formData)
this.setToken(res.access_token)
if (res.access_token) {
this.setToken(res.access_token)
}
return res
},

async logout() {
Expand Down
Loading
Loading