接入 AD 密码验证与直接所属组,保留待 MFA 边界
This commit is contained in:
+2
-2
@@ -4,11 +4,11 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="color-scheme" content="light dark" />
|
||||
<title>登录体验预览 · IAM</title>
|
||||
<title>登录 · IAM</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<noscript>此预览使用 React 渲染页面,请启用 JavaScript。</noscript>
|
||||
<noscript>本页使用 React 渲染页面,请启用 JavaScript。</noscript>
|
||||
<script id="login-context" type="application/json">
|
||||
__IAM_PAGE_CONTEXT__
|
||||
</script>
|
||||
|
||||
+37
-4
@@ -3,7 +3,8 @@ import { useState, useLayoutEffect, type ReactNode } from "react";
|
||||
import "./style.css";
|
||||
|
||||
type PageContext = {
|
||||
step: "identity" | "verification" | "complete";
|
||||
step: "identity" | "verification" | "complete" | "password" | "mfa-pending";
|
||||
identity?: { username: string; objectGuid: string; email: string; groups: string[]; groupDns: string[] };
|
||||
name: string;
|
||||
error: string;
|
||||
action: string;
|
||||
@@ -32,8 +33,8 @@ function Form({ children }: { children: ReactNode }) {
|
||||
<button className="primary" type="submit" disabled={pending}>
|
||||
{pending
|
||||
? "正在继续…"
|
||||
: context.step === "complete"
|
||||
? "重新体验"
|
||||
: (context.step === "complete" || context.step === "mfa-pending")
|
||||
? (context.step === "mfa-pending" ? "退出并重新验证" : "重新体验")
|
||||
: "继续"}
|
||||
</button>
|
||||
</form>
|
||||
@@ -156,4 +157,36 @@ function App() {
|
||||
);
|
||||
}
|
||||
|
||||
createRoot(document.getElementById("root")!).render(<App />);
|
||||
function SignIn() {
|
||||
useLayoutEffect(() => { performance.mark("iam-page-ready"); }, []);
|
||||
const identity = context.identity;
|
||||
return <main>
|
||||
<header><a href="/signin" className="brand">i<span>am</span></a></header>
|
||||
<section className="card" aria-labelledby="title">
|
||||
<div className="eyebrow">AD 登录验证</div>
|
||||
<h1 id="title">{context.step === "password" ? "登录你的账号" : "密码已验证,等待 MFA"}</h1>
|
||||
<p className="intro">{context.step === "password"
|
||||
? "使用 AD 用户名或完整 UPN 登录。"
|
||||
: `${context.name},目录验证成功。第二因素尚未接入,本次没有完成登录或向应用授权。`}</p>
|
||||
{context.error && <p className="error" role="alert">{context.error}</p>}
|
||||
{identity && <div className="directory-result">
|
||||
<dl><dt>账号</dt><dd>{identity.username}</dd>
|
||||
<dt>目录标识</dt><dd>{identity.objectGuid}</dd>
|
||||
<dt>邮箱</dt><dd>{identity.email || "未设置"}</dd></dl>
|
||||
<h2>直接所属组</h2>
|
||||
{identity.groups.length ? <ul>{identity.groups.map(group => <li key={group}>{group}</li>)}</ul> : <p>没有直接所属组。</p>}
|
||||
<details><summary>组 DN</summary><ul>{identity.groupDns.map(dn => <li key={dn}>{dn}</li>)}</ul></details>
|
||||
<p>当前仅读取 memberOf,不展开嵌套组,也不包含主组。</p>
|
||||
</div>}
|
||||
<Form>{context.step === "password" && <>
|
||||
<label>用户名<input name="username" autoComplete="username" autoFocus required maxLength={256} defaultValue={context.name} /></label>
|
||||
<label>密码<input name="password" type="password" autoComplete="current-password" required maxLength={1024} /></label>
|
||||
</>}</Form>
|
||||
</section>
|
||||
<footer>独立 IAM · AD 接入验证</footer>
|
||||
</main>;
|
||||
}
|
||||
|
||||
createRoot(document.getElementById("root")!).render(
|
||||
context.step === "password" || context.step === "mfa-pending" ? <SignIn /> : <App />,
|
||||
);
|
||||
|
||||
@@ -238,3 +238,7 @@ button:focus-visible {
|
||||
color: #ffc3b9;
|
||||
}
|
||||
}
|
||||
|
||||
.directory-result { overflow-wrap: anywhere; }
|
||||
.directory-result dd { margin: 0 0 1rem; }
|
||||
.directory-result h2 { font-size: 1rem; }
|
||||
|
||||
Reference in New Issue
Block a user