M3: Casdoor 账号账权全量接管
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (java-kotlin) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
CodeQL Advanced / Analyze (python) (push) Canceled after 0s
Docker Image Build & Push / manifest (push) Canceled after 0s
Docker Image Build & Push / build-and-push-arm (push) Canceled after 0s
Docker Image Build & Push / build-and-push-amd (push) Canceled after 0s
Docker Image Build & Push / manifest (push) Canceled after 0s
Docker Image Build & Push / build-and-push-arm (push) Canceled after 0s
Docker Image Build & Push / build-and-push-amd (push) Canceled after 0s
Frontend Docker Image CI / Build and Push Frontend Docker Image (push) Canceled after 0s
Gateway Docker Image CI / Build and Push Gateway Docker Image (push) Canceled after 0s

- accountOnly 时本地登录/注册 403,前端隐藏入口
- validateToken 增加用户存在+启用校验,禁用账号存量 JWT 立即失效
- 新增 CasdoorAdminClient(password grant 管理令牌)+ 全量账号同步服务(5 分钟定时+手动端点)
- /sso/casdoor/config 暴露 accountOnly; POST /sso/casdoor/sync 手动同步(admin)
This commit is contained in:
figmar
2026-08-31 13:57:58 +08:00
parent 76e537cf34
commit ab1255a1eb
9 changed files with 586 additions and 25 deletions
+27 -15
View File
@@ -46,6 +46,14 @@ export function Header() {
const [currentUser, setCurrentUser] = useState<UserResponse | null>(null);
const [authMode, setAuthMode] = useState<'SSO' | 'JWT' | 'NONE'>('NONE');
const [userLoading, setUserLoading] = useState(true);
// M3:accountOnly(Casdoor 为账号唯一数据源)时隐藏注册入口,登录统一走登录弹窗(仅 Casdoor SSO)
const [accountOnly, setAccountOnly] = useState(false);
useEffect(() => {
get("/sso/casdoor/config")
.then((res: any) => setAccountOnly(!!res?.data?.accountOnly))
.catch(() => {});
}, []);
const handleLogin = async (values: { username: string; password: string }) => {
try {
@@ -250,7 +258,8 @@ export function Header() {
: t('user.actions.login'),
icon: <LogIn className="h-4 w-4" />,
onClick: () => {
if (authMode === 'SSO' || isSSOAvailable()) {
// M3:accountOnly 时始终打开登录弹窗(内含 Casdoor 单点登录按钮),不走旧 OMS 登录页
if (!accountOnly && (authMode === 'SSO' || isSSOAvailable())) {
// SSO 模式:跳转到 ME 登录
window.location.href = `${ME_LOGIN_URL}?redirect=${encodeURIComponent(window.location.href)}`;
} else {
@@ -259,21 +268,24 @@ export function Header() {
}
},
},
{
type: 'divider',
},
{
key: 'register',
label: t('user.actions.register'),
icon: <UserPlus className="h-4 w-4" />,
onClick: () => {
if (authMode === 'SSO' || isSSOAvailable()) {
message.info(t('user.messages.useSSO'));
} else {
setSignupOpen(true);
}
// M3:accountOnly 时隐藏「注册」入口(后端 /api/user/signup 亦已 403)
...(accountOnly ? [] : [
{
type: 'divider',
},
},
{
key: 'register',
label: t('user.actions.register'),
icon: <UserPlus className="h-4 w-4" />,
onClick: () => {
if (authMode === 'SSO' || isSSOAvailable()) {
message.info(t('user.messages.useSSO'));
} else {
setSignupOpen(true);
}
},
},
]),
];
return (
+17 -4
View File
@@ -14,6 +14,7 @@ interface LoginDialogProps {
interface SsoConfig {
enabled?: boolean;
accountOnly?: boolean;
loginUrl?: string;
logoutUrl?: string;
issuer?: string;
@@ -43,6 +44,8 @@ export function LoginDialog({ open, onOpenChange, onLogin, loading, onSignupClic
const [form] = Form.useForm()
const [ssoEnabled, setSsoEnabled] = useState(false)
const [ssoLoginUrl, setSsoLoginUrl] = useState("")
// M3:accountOnly 时后端已 403 本地登录/注册,前端只保留 Casdoor 单点登录
const [accountOnly, setAccountOnly] = useState(false)
useEffect(() => {
let alive = true;
@@ -50,6 +53,7 @@ export function LoginDialog({ open, onOpenChange, onLogin, loading, onSignupClic
if (!alive) return;
setSsoEnabled(!!cfg.enabled && !!cfg.loginUrl);
if (cfg.loginUrl) setSsoLoginUrl(cfg.loginUrl);
setAccountOnly(!!cfg.accountOnly);
});
return () => {
alive = false;
@@ -89,19 +93,27 @@ export function LoginDialog({ open, onOpenChange, onLogin, loading, onSignupClic
<div className="mb-4">
<Button
type="primary"
ghost
block
icon={<ShieldCheck className="w-4 h-4" />}
onClick={handleCasdoorLogin}
>
{t('user.loginDialog.casdoorLogin')}
</Button>
<Divider plain style={{ margin: '12px 0' }}>
{t('user.loginDialog.or')}
</Divider>
{!accountOnly && (
<Divider plain style={{ margin: '12px 0' }}>
{t('user.loginDialog.or')}
</Divider>
)}
</div>
)}
{accountOnly && !ssoEnabled && (
<div className="mb-4 text-sm text-amber-600">
本地登录已关闭,且 Casdoor 单点登录入口不可用,请联系管理员。
</div>
)}
{!accountOnly && (
<Form
form={form}
layout="vertical"
@@ -148,6 +160,7 @@ export function LoginDialog({ open, onOpenChange, onLogin, loading, onSignupClic
</div>
</Form.Item>
</Form>
)}
</Modal>
)
}