MVP: 按 07 风格重写前端 + Go 后端落地(长文/短文、编辑器、后台管理)
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Sessions are stateless: base64("user:expiryUnix") + "." + HMAC-SHA256.
|
||||
// They survive restarts as long as ONE_SECRET stays the same.
|
||||
type Sessions struct {
|
||||
secret []byte
|
||||
ttl time.Duration
|
||||
}
|
||||
|
||||
func NewSessions(secret string, ttl time.Duration) *Sessions {
|
||||
if ttl <= 0 {
|
||||
ttl = 7 * 24 * time.Hour
|
||||
}
|
||||
return &Sessions{secret: []byte(secret), ttl: ttl}
|
||||
}
|
||||
|
||||
var ErrBadSession = errors.New("invalid session")
|
||||
|
||||
func (s *Sessions) Issue(user string) (string, time.Time) {
|
||||
exp := time.Now().Add(s.ttl)
|
||||
payload := base64.RawURLEncoding.EncodeToString([]byte(user + ":" + strconv.FormatInt(exp.Unix(), 10)))
|
||||
return payload + "." + s.sign(payload), exp
|
||||
}
|
||||
|
||||
func (s *Sessions) Verify(token string) (string, error) {
|
||||
parts := strings.Split(token, ".")
|
||||
if len(parts) != 2 {
|
||||
return "", ErrBadSession
|
||||
}
|
||||
if !hmac.Equal([]byte(s.sign(parts[0])), []byte(parts[1])) {
|
||||
return "", ErrBadSession
|
||||
}
|
||||
raw, err := base64.RawURLEncoding.DecodeString(parts[0])
|
||||
if err != nil {
|
||||
return "", ErrBadSession
|
||||
}
|
||||
i := strings.LastIndex(string(raw), ":")
|
||||
if i <= 0 {
|
||||
return "", ErrBadSession
|
||||
}
|
||||
user := string(raw)[:i]
|
||||
expUnix, err := strconv.ParseInt(string(raw)[i+1:], 10, 64)
|
||||
if err != nil {
|
||||
return "", ErrBadSession
|
||||
}
|
||||
if time.Now().After(time.Unix(expUnix, 0)) {
|
||||
return "", ErrBadSession
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (s *Sessions) sign(payload string) string {
|
||||
mac := hmac.New(sha256.New, s.secret)
|
||||
mac.Write([]byte(payload))
|
||||
return base64.RawURLEncoding.EncodeToString(mac.Sum(nil))
|
||||
}
|
||||
|
||||
func (s *Sessions) TTL() int { return int(s.ttl.Seconds()) }
|
||||
|
||||
func (s *Sessions) String() string { return fmt.Sprintf("sessions(ttl=%s)", s.ttl) }
|
||||
Reference in New Issue
Block a user