58 lines
1.1 KiB
Go
58 lines
1.1 KiB
Go
package ws
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"net/url"
|
|
"time"
|
|
)
|
|
|
|
const wsTicketTTL = 60 * time.Second
|
|
|
|
type wsTicket struct {
|
|
userID string
|
|
username string
|
|
role string
|
|
expiresAt time.Time
|
|
used bool
|
|
}
|
|
|
|
// IssueTicket 签发一次性 WebSocket ticket,避免长期 JWT 进入 URL。
|
|
func (h *Hub) IssueTicket(userID, username, role string) string {
|
|
buf := make([]byte, 32)
|
|
if _, err := rand.Read(buf); err != nil {
|
|
return ""
|
|
}
|
|
ticket := hex.EncodeToString(buf)
|
|
|
|
h.ticketsMu.Lock()
|
|
h.tickets[ticket] = &wsTicket{
|
|
userID: userID,
|
|
username: username,
|
|
role: role,
|
|
expiresAt: time.Now().Add(wsTicketTTL),
|
|
}
|
|
h.ticketsMu.Unlock()
|
|
return ticket
|
|
}
|
|
|
|
func (h *Hub) consumeTicket(ticket string) (wsTicket, bool) {
|
|
h.ticketsMu.Lock()
|
|
defer h.ticketsMu.Unlock()
|
|
|
|
info, ok := h.tickets[ticket]
|
|
if !ok || info.used || time.Now().After(info.expiresAt) {
|
|
return wsTicket{}, false
|
|
}
|
|
info.used = true
|
|
return *info, true
|
|
}
|
|
|
|
func (h *Hub) ticketFromQuery(rawQuery string) string {
|
|
values, err := url.ParseQuery(rawQuery)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return values.Get("ticket")
|
|
}
|