feat(auth): implement user and device authentication

This commit is contained in:
QiuSW
2026-07-26 15:18:48 +08:00
parent c5d3b215ff
commit 49db5b8305
66 changed files with 6216 additions and 271 deletions
@@ -0,0 +1,55 @@
{{define "login"}}
<!doctype html>
<html lang="zh-CN">
<head>
<title>{{.Page.Title}} - 采购任务管理</title>
{{template "document-head" .}}
</head>
<body class="login-body">
<main id="main-content" class="login-page">
<a class="login-brand" href="/login" aria-label="采购任务管理登录">
<span class="brand-mark" aria-hidden="true">采</span>
<span>采购任务管理</span>
</a>
<section class="login-panel" aria-labelledby="login-title">
<h1 id="login-title">管理端登录</h1>
<p class="subtitle">使用采购管理员账号继续</p>
{{if .Message}}
<div class="notice notice-error" role="alert" tabindex="-1" data-error-summary>
{{.Message}}
</div>
{{end}}
<form method="post" action="/login" novalidate data-loading-form>
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
<input type="hidden" name="next" value="{{.Next}}">
<div class="field">
<label for="username">账号</label>
<input id="username" name="username" value="{{.Username}}"
autocomplete="username" autofocus required
aria-describedby="username-error"
{{if .UsernameError}}aria-invalid="true" data-error-field{{end}}>
<p id="username-error" class="field-error">{{.UsernameError}}</p>
</div>
<div class="field">
<label for="login-password">密码</label>
<div class="password-field">
<input id="login-password" name="password" type="password"
autocomplete="current-password" required
aria-describedby="password-error"
{{if .PasswordError}}aria-invalid="true" data-error-field{{end}}>
<button class="button password-toggle" type="button"
aria-controls="login-password" aria-pressed="false"
data-password-toggle>显示</button>
</div>
<p id="password-error" class="field-error">{{.PasswordError}}</p>
</div>
<button class="button primary login-submit" type="submit"
data-loading-label="正在登录…">登录</button>
</form>
</section>
</main>
</body>
</html>
{{end}}
@@ -18,5 +18,11 @@
<a href="/tasks" {{if .Page.TasksCurrent}}aria-current="page"{{end}}>任务列表</a>
<a href="/tasks/new" {{if .Page.NewCurrent}}aria-current="page"{{end}}>新建任务</a>
</nav>
{{if .Page.CSRFToken}}
<form class="logout-form" method="post" action="/logout">
<input type="hidden" name="csrf_token" value="{{.Page.CSRFToken}}">
<button class="logout-button" type="submit">退出</button>
</form>
{{end}}
</header>
{{end}}