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
+53 -38
View File
@@ -17,15 +17,16 @@ import (
// adminApplicationRow 為應用程式管理頁表格的單列視圖。
type adminApplicationRow struct {
ID uint
ClientID string
Name string
Type string // confidential / public
RedirectURIs string // 以換行分隔(模板以 whitespace-pre-line 呈現)
GrantTypes string // 以頓號分隔
Scope string
CreatedAt string // 本地時間顯示
Confidential bool // 機密式才可輪替 client secret
ID uint
ClientID string
Name string
Type string // confidential / public
RedirectURIs string // 以換行分隔(模板以 whitespace-pre-line 呈現)
PostLogoutRedirectURIs string // 同上;空時模板顯示 —
GrantTypes string // 以頓號分隔
Scope string
CreatedAt string // 本地時間顯示
Confidential bool // 機密式才可輪替 client secret
}
// newAdminApplicationRows 將應用程式模型轉為表格視圖。純函式,便於單元測試。
@@ -37,15 +38,16 @@ func newAdminApplicationRows(apps []application.Application) []adminApplicationR
grants[i] = string(g)
}
rows = append(rows, adminApplicationRow{
ID: a.ID,
ClientID: a.ClientID,
Name: a.Name,
Type: string(a.Type),
RedirectURIs: strings.Join(a.RedirectURIs, "\n"),
GrantTypes: strings.Join(grants, "、"),
Scope: a.Scope,
CreatedAt: a.CreatedAt.Local().Format("2006-01-02 15:04:05 MST"),
Confidential: !a.IsPublic(),
ID: a.ID,
ClientID: a.ClientID,
Name: a.Name,
Type: string(a.Type),
RedirectURIs: strings.Join(a.RedirectURIs, "\n"),
PostLogoutRedirectURIs: strings.Join(a.PostLogoutRedirectURIs, "\n"),
GrantTypes: strings.Join(grants, "、"),
Scope: a.Scope,
CreatedAt: a.CreatedAt.Local().Format("2006-01-02 15:04:05 MST"),
Confidential: !a.IsPublic(),
})
}
return rows
@@ -54,13 +56,14 @@ func newAdminApplicationRows(apps []application.Application) []adminApplicationR
// applicationForm 為註冊表單的視圖狀態:驗證失敗重繪時保留使用者輸入
// (含核取方塊),初次顯示(GET)採 newApplicationForm 的預設值。
type applicationForm struct {
Name string
Type string // confidential / public
RedirectURIs string // textarea 原始內容(每行一個 URI)
Scope string // 留空時使用預設
GrantAuthCode bool
GrantRefresh bool
GrantClientCred bool
Name string
Type string // confidential / public
RedirectURIs string // textarea 原始內容(每行一個 URI)
PostLogoutRedirectURIs string // 同上(選填)
Scope string // 留空時使用預設
GrantAuthCode bool
GrantRefresh bool
GrantClientCred bool
}
// newApplicationForm 回傳註冊表單的預設狀態:機密式、勾選授權碼流程。
@@ -72,10 +75,11 @@ func newApplicationForm() applicationForm {
// 其餘一律回復為 confidential;grant type 僅接受已知值。
func applicationFormFromPost(r *http.Request) applicationForm {
f := applicationForm{
Name: r.PostFormValue("name"),
Type: r.PostFormValue("type"),
RedirectURIs: r.PostFormValue("redirect_uris"),
Scope: r.PostFormValue("scope"),
Name: r.PostFormValue("name"),
Type: r.PostFormValue("type"),
RedirectURIs: r.PostFormValue("redirect_uris"),
PostLogoutRedirectURIs: r.PostFormValue("post_logout_redirect_uris"),
Scope: r.PostFormValue("scope"),
}
if f.Type != string(application.ClientPublic) {
f.Type = string(application.ClientConfidential)
@@ -97,10 +101,11 @@ func applicationFormFromPost(r *http.Request) applicationForm {
// redirect URI 以每行一個還原為 textarea 內容。
func applicationFormFromApp(a *application.Application) applicationForm {
f := applicationForm{
Name: a.Name,
Type: string(a.Type),
RedirectURIs: strings.Join(a.RedirectURIs, "\n"),
Scope: a.Scope,
Name: a.Name,
Type: string(a.Type),
RedirectURIs: strings.Join(a.RedirectURIs, "\n"),
PostLogoutRedirectURIs: strings.Join(a.PostLogoutRedirectURIs, "\n"),
Scope: a.Scope,
}
for _, g := range a.GrantTypes {
switch g {
@@ -115,11 +120,21 @@ func applicationFormFromApp(a *application.Application) applicationForm {
return f
}
// redirectURIList 解析 textarea 內容:每行一個 URI,去首尾空白(含瀏覽器
// 送出的 \r)後略過空行。
// redirectURIList 解析 redirect URI textarea 內容:每行一個 URI,去首尾
// 空白(含瀏覽器送出的 \r)後略過空行。
func (f applicationForm) redirectURIList() []string {
return uriLines(f.RedirectURIs)
}
// postLogoutURIList 解析登出後返回 URI textarea 內容(同 redirectURIList)。
func (f applicationForm) postLogoutURIList() []string {
return uriLines(f.PostLogoutRedirectURIs)
}
// uriLines 將 textarea 內容拆為非空行清單。
func uriLines(raw string) []string {
var uris []string
for _, line := range strings.Split(f.RedirectURIs, "\n") {
for _, line := range strings.Split(raw, "\n") {
if u := strings.TrimSpace(line); u != "" {
uris = append(uris, u)
}
@@ -322,7 +337,7 @@ func ApplicationsCreateHandler(db *gorm.DB) http.HandlerFunc {
return
}
form := applicationFormFromPost(r)
app, secret, err := application.NewApplication(form.Name, application.ClientType(form.Type), form.redirectURIList(), form.grantTypeList(), form.Scope)
app, secret, err := application.NewApplication(form.Name, application.ClientType(form.Type), form.redirectURIList(), form.grantTypeList(), form.Scope, form.postLogoutURIList()...)
if err != nil {
renderAdminApplicationNewPage(w, r, http.StatusBadRequest, s, err.Error(), form, nil)
return
@@ -362,7 +377,7 @@ func ApplicationUpdateHandler(db *gorm.DB) http.HandlerFunc {
return
}
form := applicationFormFromPost(r)
if err := app.Update(form.Name, application.ClientType(form.Type), form.redirectURIList(), form.grantTypeList(), form.Scope); err != nil {
if err := app.Update(form.Name, application.ClientType(form.Type), form.redirectURIList(), form.grantTypeList(), form.Scope, form.postLogoutURIList()...); err != nil {
renderAdminApplicationEditPage(w, r, http.StatusBadRequest, s, err.Error(), "", app, form)
return
}