This commit is contained in:
2026-10-03 12:37:38 +08:00
parent bcf3d3769c
commit 5fc1755c17
22 changed files with 1845 additions and 100 deletions
@@ -88,6 +88,12 @@
class="w-full rounded-lg border border-neutral-300 px-3 py-2 font-mono text-xs dark:border-neutral-600 dark:bg-neutral-900">{{.Form.RedirectURIs}}</textarea>
<p class="mt-1 text-xs text-neutral-500 dark:text-neutral-400">須為絕對 URI;http 僅允許 localhost/127.0.0.1/::1,其餘請使用 https;原生應用可用自訂 scheme(如 com.example.app:/cb)。</p>
</div>
<div>
<label for="app-post-logout-uris" class="mb-1 block text-sm font-medium">登出後返回 URI(每行一個,選填)</label>
<textarea id="app-post-logout-uris" name="post_logout_redirect_uris" rows="2"
class="w-full rounded-lg border border-neutral-300 px-3 py-2 font-mono text-xs dark:border-neutral-600 dark:bg-neutral-900">{{.Form.PostLogoutRedirectURIs}}</textarea>
<p class="mt-1 text-xs text-neutral-500 dark:text-neutral-400">RP-Initiated Logout 的 post_logout_redirect_uri 白名單(精確比對,格式規則同 redirect URI);留空表示不接受登出後重導回應用程式。</p>
</div>
<fieldset>
<legend class="mb-1 text-sm font-medium">允許的 grant type</legend>
<div class="space-y-1.5 text-sm">
@@ -75,6 +75,12 @@
class="w-full rounded-lg border border-neutral-300 px-3 py-2 font-mono text-xs dark:border-neutral-600 dark:bg-neutral-900">{{.Form.RedirectURIs}}</textarea>
<p class="mt-1 text-xs text-neutral-500 dark:text-neutral-400">須為絕對 URI;http 僅允許 localhost/127.0.0.1/::1,其餘請使用 https;原生應用可用自訂 scheme(如 com.example.app:/cb)。</p>
</div>
<div>
<label for="app-post-logout-uris" class="mb-1 block text-sm font-medium">登出後返回 URI(每行一個,選填)</label>
<textarea id="app-post-logout-uris" name="post_logout_redirect_uris" rows="2"
class="w-full rounded-lg border border-neutral-300 px-3 py-2 font-mono text-xs dark:border-neutral-600 dark:bg-neutral-900">{{.Form.PostLogoutRedirectURIs}}</textarea>
<p class="mt-1 text-xs text-neutral-500 dark:text-neutral-400">RP-Initiated Logout 的 post_logout_redirect_uri 白名單(精確比對,格式規則同 redirect URI);留空表示不接受登出後重導回應用程式。</p>
</div>
<fieldset>
<legend class="mb-1 text-sm font-medium">允許的 grant type</legend>
<div class="space-y-1.5 text-sm">
@@ -64,6 +64,7 @@
<th scope="col" class="px-3 py-2 text-xs font-medium tracking-wide text-neutral-500 uppercase dark:text-neutral-400">client_id</th>
<th scope="col" class="px-3 py-2 text-xs font-medium tracking-wide text-neutral-500 uppercase dark:text-neutral-400">類型</th>
<th scope="col" class="px-3 py-2 text-xs font-medium tracking-wide text-neutral-500 uppercase dark:text-neutral-400">redirect URI</th>
<th scope="col" class="px-3 py-2 text-xs font-medium tracking-wide text-neutral-500 uppercase dark:text-neutral-400">登出後返回 URI</th>
<th scope="col" class="px-3 py-2 text-xs font-medium tracking-wide text-neutral-500 uppercase dark:text-neutral-400">grant type</th>
<th scope="col" class="px-3 py-2 text-xs font-medium tracking-wide text-neutral-500 uppercase dark:text-neutral-400">scope</th>
<th scope="col" class="px-3 py-2 text-xs font-medium tracking-wide text-neutral-500 uppercase dark:text-neutral-400">建立時間</th>
@@ -83,6 +84,7 @@
{{end}}
</td>
<td class="px-3 py-3 font-mono text-xs break-all whitespace-pre-line">{{.RedirectURIs}}</td>
<td class="px-3 py-3 font-mono text-xs break-all whitespace-pre-line">{{if .PostLogoutRedirectURIs}}{{.PostLogoutRedirectURIs}}{{else}}<span class="font-sans text-neutral-400 dark:text-neutral-500">—</span>{{end}}</td>
<td class="px-3 py-3 text-xs">{{.GrantTypes}}</td>
<td class="px-3 py-3 font-mono text-xs break-all">{{.Scope}}</td>
<td class="px-3 py-3 whitespace-nowrap text-neutral-500 dark:text-neutral-400">{{.CreatedAt}}</td>
+9
View File
@@ -17,6 +17,15 @@
<dt class="text-sm text-neutral-500 dark:text-neutral-400">Session 到期</dt>
<dd class="mt-0.5 mb-3.5 text-[15px] break-all">{{.ExpiresAt}}</dd>
</dl>
<div class="mt-6 flex flex-wrap gap-3">
<a href="/password"
class="flex items-center gap-2 rounded-lg border border-neutral-300 px-4 py-2.5 text-sm font-semibold hover:bg-neutral-100 dark:border-neutral-600 dark:hover:bg-neutral-700">
<svg class="size-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 1 0-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 0 0 2.25-2.25v-6.75a2.25 2.25 0 0 0-2.25-2.25H6.75a2.25 2.25 0 0 0-2.25 2.25v6.75a2.25 2.25 0 0 0 2.25 2.25Z"/>
</svg>
更新密碼
</a>
</div>
<p class="mt-4 text-sm text-neutral-500 dark:text-neutral-400">授權流程(/authorize)完成後,登入將自動導回應用程式。</p>
</section>
{{end}}
+19
View File
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="referrer" content="no-referrer">
<title>已登出 - alterminal</title>
<link rel="stylesheet" href="/static/css/main.css">
</head>
<body class="flex min-h-screen items-center justify-center bg-neutral-100 font-sans text-neutral-900 antialiased dark:bg-neutral-900 dark:text-neutral-100">
<main class="m-4 w-full max-w-88 rounded-xl bg-white p-8 shadow-lg dark:bg-neutral-800 dark:shadow-black/40">
<h1 class="mb-1 text-xl font-semibold">您已登出</h1>
<p class="mb-6 text-sm text-neutral-500 dark:text-neutral-400">單一登入服務</p>
{{if .Warning}}<p class="mb-4 rounded-lg bg-amber-500/10 px-3 py-2.5 text-sm text-amber-700 dark:text-amber-400" role="alert">{{.Warning}}</p>{{end}}
<a href="/login"
class="block w-full rounded-lg border border-neutral-300 py-2.5 text-center text-base font-semibold hover:bg-neutral-100 dark:border-neutral-600 dark:hover:bg-neutral-700">重新登入</a>
</main>
</body>
</html>
@@ -0,0 +1,28 @@
{{/* 登出確認頁(GET /logout)。以 layout.html(側邊導覽欄版面)為根模板
組合渲染,本檔僅定義區塊。RP-Initiated Logout 1.0 §2:未提供
id_token_hint、或提示的 ID token 不屬於目前 Session 時,OP 必須先
詢問 End-User 是否登出——使用者直接造訪 /logout 亦同。原始請求的
每個參數以隱藏欄位原封帶回 POST /logout(decision=logout 確認登出;
decision=cancel 維持登入並返回帳號首頁)。 */}}
{{define "title"}}登出確認 - alterminal{{end}}
{{define "content"}}
<section class="rounded-xl bg-white p-8 shadow-lg dark:bg-neutral-800 dark:shadow-black/40">
<h1 class="mb-1 text-xl font-semibold">您確定要登出嗎?</h1>
<p class="mb-6 text-sm text-neutral-500 dark:text-neutral-400">
{{if .AppName}}應用程式 <strong class="text-neutral-900 dark:text-neutral-100">{{.AppName}}</strong> 要求登出您在本服務的帳號。{{else}}登出將結束您在本服務的 Session。{{end}}
</p>
{{if .Error}}<p class="mb-4 rounded-lg bg-red-500/10 px-3 py-2.5 text-sm text-red-600 dark:text-red-400" role="alert">{{.Error}}</p>{{end}}
<form method="post" action="/logout">
{{range $k, $vs := .Params}}{{range $vs}}<input type="hidden" name="{{$k}}" value="{{.}}">{{end}}{{end}}
<input type="hidden" name="csrf_token" value="{{.CSRF}}">
<div class="flex flex-col gap-3 sm:flex-row">
<button type="submit" name="decision" value="logout"
class="rounded-lg bg-brand px-5 py-2.5 text-sm font-semibold text-white hover:bg-brand-strong">登出</button>
<button type="submit" name="decision" value="cancel"
class="rounded-lg border border-neutral-300 px-5 py-2.5 text-sm font-semibold hover:bg-neutral-100 dark:border-neutral-600 dark:hover:bg-neutral-700">取消</button>
</div>
</form>
<p class="mt-4 text-xs text-neutral-400 dark:text-neutral-500">登出後,所有以本帳號單一登入的應用程式都需要重新登入。</p>
</section>
{{end}}
+69
View File
@@ -0,0 +1,69 @@
{{/* 更新密碼頁(登入者自助變更,GET/POST /password)。以 layout.html
(側邊導覽欄版面)為根模板組合渲染,本檔僅定義區塊,不應單獨解析
執行。導覽覆寫版面預設:「帳號資訊」不標記 aria-current(本頁非
帳號首頁),admin 另顯示管理頁連結。密碼欄位一律不預填——驗證失敗
重繪亦同;成功後 PRG 回本頁以 ?saved=1 顯示成功訊息。 */}}
{{define "title"}}更新密碼 - alterminal{{end}}
{{define "navitems"}}
<li>
<a href="/"
class="flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium text-neutral-600 hover:bg-neutral-100 dark:text-neutral-300 dark:hover:bg-neutral-700/60">
<svg class="size-5 shrink-0" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z"/>
</svg>
帳號資訊
</a>
</li>
{{if .IsAdmin}}
<li>
<a href="/admin/keys"
class="flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium text-neutral-600 hover:bg-neutral-100 dark:text-neutral-300 dark:hover:bg-neutral-700/60">
<svg class="size-5 shrink-0" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 5.25a3 3 0 0 1 3 3m3 0a6 6 0 0 1-7.029 5.912c-.563-.097-1.159.026-1.563.43L10.5 17.25H8.25v2.25H6v2.25H2.25v-2.818c0-.597.237-1.17.659-1.591l6.499-6.499c.404-.404.527-1 .43-1.563A6 6 0 1 1 21.75 8.25Z"/>
</svg>
金鑰管理
</a>
</li>
<li>
<a href="/admin/applications"
class="flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium text-neutral-600 hover:bg-neutral-100 dark:text-neutral-300 dark:hover:bg-neutral-700/60">
<svg class="size-5 shrink-0" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M21 7.5l-9-5.25L3 7.5m18 0l-9 5.25m9-5.25v9l-9 5.25M3 7.5l9 5.25M3 7.5v9l9 5.25m0-9v9"/>
</svg>
應用程式管理
</a>
</li>
{{end}}
{{end}}
{{define "content"}}
<section class="rounded-xl bg-white p-8 shadow-lg dark:bg-neutral-800 dark:shadow-black/40">
<h1 class="mb-1 text-xl font-semibold">更新密碼</h1>
<p class="mb-6 text-sm text-neutral-500 dark:text-neutral-400">驗證目前的密碼後設定新密碼</p>
{{if .Error}}<p class="mb-4 rounded-lg bg-red-500/10 px-3 py-2.5 text-sm text-red-600 dark:text-red-400" role="alert">{{.Error}}</p>{{end}}
{{if .Success}}<p class="mb-4 rounded-lg bg-emerald-500/10 px-3 py-2.5 text-sm text-emerald-700 dark:text-emerald-400" role="status">{{.Success}}</p>{{end}}
<form method="post" action="/password" class="space-y-4">
<input type="hidden" name="csrf_token" value="{{.CSRF}}">
<div>
<label for="current-password" class="mb-1 block text-sm font-medium">目前的密碼</label>
<input type="password" id="current-password" name="current_password" autocomplete="current-password" autofocus required
class="w-full rounded-lg border border-neutral-300 px-3 py-2 text-sm dark:border-neutral-600 dark:bg-neutral-900">
</div>
<div>
<label for="new-password" class="mb-1 block text-sm font-medium">新密碼</label>
<input type="password" id="new-password" name="new_password" autocomplete="new-password" minlength="8" required
class="w-full rounded-lg border border-neutral-300 px-3 py-2 text-sm dark:border-neutral-600 dark:bg-neutral-900">
<p class="mt-1 text-xs text-neutral-500 dark:text-neutral-400">至少 8 字元。</p>
</div>
<div>
<label for="confirm-password" class="mb-1 block text-sm font-medium">確認新密碼</label>
<input type="password" id="confirm-password" name="confirm_password" autocomplete="new-password" minlength="8" required
class="w-full rounded-lg border border-neutral-300 px-3 py-2 text-sm dark:border-neutral-600 dark:bg-neutral-900">
</div>
<button type="submit"
class="rounded-lg bg-brand px-4 py-2.5 text-sm font-semibold text-white hover:bg-brand-strong">更新密碼</button>
</form>
<p class="mt-4 text-xs text-neutral-400 dark:text-neutral-500">更新成功後,其他裝置的登入將全部登出;本瀏覽器會保持登入狀態。</p>
</section>
{{end}}