Skip to content

Commit 49aa39a

Browse files
Zuoqiu-Yingyileolee9086
authored andcommitted
🎨 Add cookie-based auth in publish proxy (siyuan-note#15692)
* chore(publish-auth): Add TODO for cookie-based auth in publish proxy A TODO comment was added to indicate future implementation of authentication using cookies in the PublishServiceTransport RoundTrip method. * 🎨 Add session-based authentication for publish proxy Introduces session management using cookies for the publish reverse proxy server. Adds session ID generation, storage, and validation in kernel/model/auth.go, and updates the proxy transport to check for valid sessions before falling back to basic authentication. Sets a session cookie upon successful basic auth login. * 🐛 Fixed the issue of repeatedly setting cookies * 🎨 Dynamically remove invalid session IDs * ♻️ Revert changes in pnpm-lock.yaml
1 parent 6c7feca commit 49aa39a

3 files changed

Lines changed: 67 additions & 7 deletions

File tree

kernel/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ require (
3737
github.com/go-ole/go-ole v1.3.0
3838
github.com/gofrs/flock v0.12.1
3939
github.com/golang-jwt/jwt/v5 v5.2.2
40+
github.com/google/uuid v1.6.0
4041
github.com/gorilla/css v1.0.1
4142
github.com/gorilla/websocket v1.5.3
4243
github.com/imroc/req/v3 v3.54.2
@@ -129,7 +130,6 @@ require (
129130
github.com/goccy/go-json v0.10.5 // indirect
130131
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
131132
github.com/google/pprof v0.0.0-20250607225305-033d6d78b36a // indirect
132-
github.com/google/uuid v1.6.0 // indirect
133133
github.com/gopherjs/gopherjs v1.17.2 // indirect
134134
github.com/gorilla/context v1.1.2 // indirect
135135
github.com/gorilla/securecookie v1.1.2 // indirect

kernel/model/auth.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ package model
1919
import (
2020
"crypto/rand"
2121
"net/http"
22+
"sync"
2223

2324
"github.com/golang-jwt/jwt/v5"
25+
"github.com/google/uuid"
2426
"github.com/siyuan-note/logging"
2527
)
2628

@@ -29,12 +31,15 @@ type Account struct {
2931
Password string
3032
Token string
3133
}
32-
type AccountsMap map[string]*Account
34+
type AccountsMap map[string]*Account // username -> account
35+
type SessionsMap map[string]string // sessionID -> username
3336
type ClaimsKeyType string
3437

3538
const (
3639
XAuthTokenKey = "X-Auth-Token"
3740

41+
SessionIdCookieName = "publish-visitor-session-id"
42+
3843
ClaimsContextKey = "claims"
3944

4045
iss = "siyuan-publish-reverse-proxy-server"
@@ -46,13 +51,37 @@ const (
4651

4752
var (
4853
accountsMap = AccountsMap{}
49-
jwtKey = make([]byte, 32)
54+
sessionsMap = SessionsMap{}
55+
sessionLock = sync.Mutex{}
56+
57+
jwtKey = make([]byte, 32)
5058
)
5159

5260
func GetBasicAuthAccount(username string) *Account {
5361
return accountsMap[username]
5462
}
5563

64+
func GetBasicAuthUsernameBySessionID(sessionID string) string {
65+
return sessionsMap[sessionID]
66+
}
67+
68+
func GetNewSessionID() string {
69+
sessionID := uuid.New().String()
70+
return sessionID
71+
}
72+
73+
func AddSession(sessionID, username string) {
74+
sessionLock.Lock()
75+
defer sessionLock.Unlock()
76+
sessionsMap[sessionID] = username
77+
}
78+
79+
func DeleteSession(sessionID string) {
80+
sessionLock.Lock()
81+
defer sessionLock.Unlock()
82+
delete(sessionsMap, sessionID)
83+
}
84+
5685
func InitAccounts() {
5786
accountsMap = AccountsMap{
5887
"": &Account{}, // 匿名用户

kernel/server/proxy/publish.go

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,28 @@ func rewrite(r *httputil.ProxyRequest) {
125125

126126
func (PublishServiceTransport) RoundTrip(request *http.Request) (response *http.Response, err error) {
127127
if model.Conf.Publish.Auth.Enable {
128+
// Session Auth
129+
sessionIdCookie, cookieErr := request.Cookie(model.SessionIdCookieName)
130+
if cookieErr == nil {
131+
// Check session ID
132+
sessionID := sessionIdCookie.Value
133+
if username := model.GetBasicAuthUsernameBySessionID(sessionID); username != "" {
134+
// Valid session
135+
if account := model.GetBasicAuthAccount(username); account != nil {
136+
// Valid account
137+
request.Header.Set(model.XAuthTokenKey, account.Token)
138+
response, err = http.DefaultTransport.RoundTrip(request)
139+
return
140+
} else {
141+
// Invalid account, remove session
142+
model.DeleteSession(sessionID)
143+
}
144+
}
145+
}
146+
128147
// Basic Auth
129148
username, password, ok := request.BasicAuth()
130149
account := model.GetBasicAuthAccount(username)
131-
132150
if !ok ||
133151
account == nil ||
134152
account.Username == "" || // 匿名用户
@@ -149,13 +167,26 @@ func (PublishServiceTransport) RoundTrip(request *http.Request) (response *http.
149167
ContentLength: -1,
150168
}, nil
151169
} else {
170+
// set session cookie
171+
sessionID := model.GetNewSessionID()
172+
cookie := &http.Cookie{
173+
Name: model.SessionIdCookieName,
174+
Value: sessionID,
175+
Path: "/",
176+
HttpOnly: true,
177+
}
178+
model.AddSession(sessionID, username)
179+
152180
// set JWT
153181
request.Header.Set(model.XAuthTokenKey, account.Token)
182+
response, err = http.DefaultTransport.RoundTrip(request)
183+
184+
response.Header.Add("Set-Cookie", cookie.String())
185+
return
154186
}
155187
} else {
156188
request.Header.Set(model.XAuthTokenKey, model.GetBasicAuthAccount("").Token)
189+
response, err = http.DefaultTransport.RoundTrip(request)
190+
return
157191
}
158-
159-
response, err = http.DefaultTransport.RoundTrip(request)
160-
return
161192
}

0 commit comments

Comments
 (0)