feat(admin): 添加管理员页面用户认证功能- 在 admin.html 中添加用户登出组件显示区域

- 新增 sign_in.html 模板用于用户登录界面- 实现 SignOutHandler 处理用户登出逻辑
- 创建 AuthenticationHandler 处理用户登录验证
- 添加 user_widget.html 模板显示登出按钮
- 更新配置文件添加认证失败跳转地址
- 调整模板中 handler 调用的缩进格式
This commit is contained in:
2025-11-09 18:58:31 +08:00
parent 9fdfcdd6e7
commit 3daf76dbb0
6 changed files with 116 additions and 1 deletions

View File

@@ -0,0 +1,24 @@
package admin
import (
"platform/authorization/identity"
"platform/http/actionresults"
"platform/http/handing"
"sportstore/store"
)
type SignOutHandler struct {
identity.User
handing.URLGenerator
}
func (handler SignOutHandler) GetUserWidget() actionresults.ActionResult {
context := struct {
identity.User
SignOutUrl string
}{
User: handler.User,
SignOutUrl: store.MustGenerateUrl(handler.URLGenerator, AuthenticationHandler.PostSignOut),
}
return actionresults.NewTemplateAction("user_widget.html", context)
}

View File

@@ -0,0 +1,56 @@
package admin
import (
"platform/authorization/identity"
"platform/config"
"platform/http/actionresults"
"platform/http/handing"
"platform/sessions"
"sportstore/store"
)
type AuthenticationHandler struct {
identity.User
identity.SignInManager
identity.UserStore
sessions.Session
config.Configuration
handing.URLGenerator
}
type Credentials struct {
UserName string
Password string
}
const SignInMsgKey string = "sign_in_message"
func (handler AuthenticationHandler) GetSignIn() actionresults.ActionResult {
message := handler.Session.GetValueDefault(SignInMsgKey, "").(string)
return actionresults.NewTemplateAction("sign_in.html", message)
}
func (handler AuthenticationHandler) PostSignIn(cred Credentials) actionresults.ActionResult {
if cred.Password == "123456" {
user, ok := handler.UserStore.GetUserByName(cred.UserName)
if ok {
handler.Session.SetValue(SignInMsgKey, "")
err := handler.SignInManager.SignIn(user)
if err != nil {
handler.Session.SetValue(SignInMsgKey, "Sign in failed:"+err.Error())
return actionresults.NewRedirectAction(store.MustGenerateUrl(handler.URLGenerator, AuthenticationHandler.GetSignIn))
}
return actionresults.NewRedirectAction("/admin/section/")
}
}
handler.Session.SetValue(SignInMsgKey, "Invalid username or password")
return actionresults.NewRedirectAction(store.MustGenerateUrl(handler.URLGenerator, AuthenticationHandler.GetSignIn))
}
func (handler AuthenticationHandler) PostSignOut() actionresults.ActionResult {
err := handler.SignInManager.SignOut(handler.User)
if err != nil {
return actionresults.NewRedirectAction("/")
}
return actionresults.NewRedirectAction("/")
}

View File

@@ -38,5 +38,8 @@
"SaveCategory": "sql/save_category.sql",
"UpdateCategory": "sql/update_category.sql"
}
},
"authorization": {
"failUrl": "/signin"
}
}

View File

@@ -12,6 +12,9 @@
<div class="container-fluid">
<div class="row">
<div class="col navbar-brand">Sports Store Administration</div>
<div class="col-6 navbar-text text-end">
{{ handler "SignOut" "GetUserWidget" }}
</div>
</div>
</div>
</div>
@@ -35,7 +38,7 @@
Welcome to the SportStore Administrations Features
</h6>
{{ else }}
{{ handler $context.ActiveSection "GetData" }}
{{ handler $context.ActiveSection "GetData" }}
{{ end }}
</div>
</div>

View File

@@ -0,0 +1,20 @@
{{ layout "simple_layout.html" }}
{{ if ne . "" }}
<h3 class="text-danger p-2">{{ . }}</h3>
{{ end }}
<form method="POST" class="m-2">
<div class="form-group">
<label for="username">Username:</label>
<input type="text" class="form-control" id="username" name="username" placeholder="Enter username" />
</div>
<div class="form-group">
<label for="password">Password:</label>
<input type="password" class="form-control" id="password" name="password" placeholder="Enter password">
</div>
<div class="m-2">
<button type="submit" class="btn btn-secondary">Sign In</button>
</div>
</form>

View File

@@ -0,0 +1,9 @@
{{ $context := . }}
{{ if $context.User.IsAuthenticated }}
<form method="post" action="{{ $context.SignOutUrl }}">
<button class="btn btn-sm btn-outline-secondary text-white" type="submit">
Sign Out
</button>
</form>
{{ end }}