feature/v0.1.3 代码版本逻辑

This commit is contained in:
c
2025-11-09 10:57:06 +07:00
parent 01963bd14d
commit 36a2cdd794
15 changed files with 828 additions and 184 deletions

View File

@@ -465,22 +465,24 @@ accessToken, _ := oauth2Server.ExchangeCodeForToken(
Listen to authentication and authorization events for audit logging, security monitoring, etc:
```go
// Create event manager
eventMgr := core.NewEventManager()
storage := memory.NewStorage()
manager := core.NewBuilder().
Storage(storage).
Build()
// Listen to login events
eventMgr.RegisterFunc(core.EventLogin, func(data *core.EventData) {
manager.RegisterFunc(core.EventLogin, func(data *core.EventData) {
fmt.Printf("[LOGIN] User: %s, Token: %s\n", data.LoginID, data.Token)
// Log audit, send notifications, etc.
})
// Listen to logout events
eventMgr.RegisterFunc(core.EventLogout, func(data *core.EventData) {
manager.RegisterFunc(core.EventLogout, func(data *core.EventData) {
fmt.Printf("[LOGOUT] User: %s\n", data.LoginID)
})
// Advanced: priority and sync execution
eventMgr.RegisterWithConfig(core.EventLogin,
manager.RegisterWithConfig(core.EventLogin,
core.ListenerFunc(auditLogger),
core.ListenerConfig{
Priority: 100, // High priority
@@ -489,9 +491,15 @@ eventMgr.RegisterWithConfig(core.EventLogin,
)
// Listen to all events (wildcard)
eventMgr.RegisterFunc(core.EventAll, func(data *core.EventData) {
manager.RegisterFunc(core.EventAll, func(data *core.EventData) {
log.Printf("[%s] %s", data.Event, data.LoginID)
})
// Access advanced controls via the underlying EventManager
manager.GetEventManager().SetPanicHandler(customPanicHandler)
// Use the manager globally
stputil.SetManager(manager)
```
**Available events:**

View File

@@ -466,22 +466,25 @@ accessToken, _ := oauth2Server.ExchangeCodeForToken(
监听认证和授权事件,实现审计日志、安全监控等功能:
```go
// 创建事件管理器
eventMgr := core.NewEventManager()
storage := memory.NewStorage()
manager := core.NewBuilder().
Storage(storage).
Build()
// 监听登录事件
eventMgr.RegisterFunc(core.EventLogin, func(data *core.EventData) {
manager.RegisterFunc(core.EventLogin, func(data *core.EventData) {
fmt.Printf("[LOGIN] User: %s, Token: %s\n", data.LoginID, data.Token)
// 记录审计日志、发送通知等
})
// 监听注销事件
eventMgr.RegisterFunc(core.EventLogout, func(data *core.EventData) {
// 监听登出事件
manager.RegisterFunc(core.EventLogout, func(data *core.EventData) {
fmt.Printf("[LOGOUT] User: %s\n", data.LoginID)
})
// 高级特性:优先级、同步执行
eventMgr.RegisterWithConfig(core.EventLogin,
manager.RegisterWithConfig(core.EventLogin,
core.ListenerFunc(auditLogger),
core.ListenerConfig{
Priority: 100, // 高优先级
@@ -490,9 +493,15 @@ eventMgr.RegisterWithConfig(core.EventLogin,
)
// 监听所有事件(通配符)
eventMgr.RegisterFunc(core.EventAll, func(data *core.EventData) {
manager.RegisterFunc(core.EventAll, func(data *core.EventData) {
log.Printf("[%s] %s", data.Event, data.LoginID)
})
// 可通过底层 EventManager 访问更多控制能力
manager.GetEventManager().SetPanicHandler(customPanicHandler)
// 设置全局管理器
stputil.SetManager(manager)
```
**可用事件:**

View File

@@ -7,6 +7,7 @@ import (
"github.com/click33/sa-token-go/core/adapter"
"github.com/click33/sa-token-go/core/config"
"github.com/click33/sa-token-go/core/listener"
"github.com/click33/sa-token-go/core/oauth2"
"github.com/click33/sa-token-go/core/security"
"github.com/click33/sa-token-go/core/session"
@@ -63,6 +64,7 @@ type Manager struct {
nonceManager *security.NonceManager
refreshManager *security.RefreshTokenManager
oauth2Server *oauth2.OAuth2Server
eventManager *listener.Manager
}
// NewManager Creates a new manager | 创建管理器
@@ -85,6 +87,7 @@ func NewManager(storage adapter.Storage, cfg *config.Config) *Manager {
nonceManager: security.NewNonceManager(storage, prefix, DefaultNonceTTL),
refreshManager: security.NewRefreshTokenManager(storage, prefix, cfg),
oauth2Server: oauth2.NewOAuth2Server(storage, prefix),
eventManager: listener.NewManager(),
}
}
@@ -154,6 +157,16 @@ func (m *Manager) Login(loginID string, device ...string) (string, error) {
sess.Set(SessionKeyDevice, deviceType)
sess.Set(SessionKeyLoginTime, time.Now().Unix())
// Trigger login event | 触发登录事件
if m.eventManager != nil {
m.eventManager.Trigger(&listener.EventData{
Event: listener.EventLogin,
LoginID: loginID,
Token: tokenValue,
Device: deviceType,
})
}
return tokenValue, nil
}
@@ -194,6 +207,15 @@ func (m *Manager) Logout(loginID string, device ...string) error {
// Delete account mapping | 删除账号映射
m.storage.Delete(accountKey)
// Trigger logout event | 触发登出事件
if m.eventManager != nil {
m.eventManager.Trigger(&listener.EventData{
Event: listener.EventLogout,
LoginID: loginID,
Device: deviceType,
})
}
return nil
}
@@ -202,8 +224,23 @@ func (m *Manager) LogoutByToken(tokenValue string) error {
if tokenValue == "" {
return nil
}
// Get loginID before deletion for event | 删除前获取loginID用于事件
loginID, _ := m.getLoginIDByToken(tokenValue)
tokenKey := m.getTokenKey(tokenValue)
return m.storage.Delete(tokenKey)
err := m.storage.Delete(tokenKey)
// Trigger logout event | 触发登出事件
if m.eventManager != nil && loginID != "" {
m.eventManager.Trigger(&listener.EventData{
Event: listener.EventLogout,
LoginID: loginID,
Token: tokenValue,
})
}
return err
}
// kickout Kick user offline (private) | 踢人下线(私有)
@@ -220,6 +257,17 @@ func (m *Manager) kickout(loginID string, device string) error {
}
tokenKey := m.getTokenKey(tokenStr)
// Trigger kickout event | 触发踢出事件
if m.eventManager != nil {
m.eventManager.Trigger(&listener.EventData{
Event: listener.EventKickout,
LoginID: loginID,
Token: tokenStr,
Device: device,
})
}
return m.storage.Delete(tokenKey)
}
@@ -638,6 +686,58 @@ func (m *Manager) toStringSlice(v any) []string {
}
}
// ============ Event Management | 事件管理 ============
// RegisterFunc registers a function as an event listener | 注册函数作为事件监听器
func (m *Manager) RegisterFunc(event listener.Event, fn func(*listener.EventData)) {
if m.eventManager != nil {
m.eventManager.RegisterFunc(event, fn)
}
}
// Register registers an event listener | 注册事件监听器
func (m *Manager) Register(event listener.Event, listener listener.Listener) string {
if m.eventManager != nil {
return m.eventManager.Register(event, listener)
}
return ""
}
// RegisterWithConfig registers an event listener with config | 注册带配置的事件监听器
func (m *Manager) RegisterWithConfig(event listener.Event, listener listener.Listener, config listener.ListenerConfig) string {
if m.eventManager != nil {
return m.eventManager.RegisterWithConfig(event, listener, config)
}
return ""
}
// Unregister removes an event listener by ID | 根据ID移除事件监听器
func (m *Manager) Unregister(id string) bool {
if m.eventManager != nil {
return m.eventManager.Unregister(id)
}
return false
}
// TriggerEvent manually triggers an event | 手动触发事件
func (m *Manager) TriggerEvent(data *listener.EventData) {
if m.eventManager != nil {
m.eventManager.Trigger(data)
}
}
// WaitEvents waits for all async event listeners to complete | 等待所有异步事件监听器完成
func (m *Manager) WaitEvents() {
if m.eventManager != nil {
m.eventManager.Wait()
}
}
// GetEventManager gets the event manager | 获取事件管理器
func (m *Manager) GetEventManager() *listener.Manager {
return m.eventManager
}
// ============ Public Getters | 公共获取器 ============
// GetConfig Gets configuration | 获取配置

View File

@@ -3,6 +3,7 @@ package security
import (
"crypto/rand"
"encoding/hex"
"encoding/json"
"fmt"
"time"
@@ -42,12 +43,22 @@ var (
// RefreshTokenInfo refresh token information | 刷新令牌信息
type RefreshTokenInfo struct {
RefreshToken string // Refresh token (long-lived) | 刷新令牌(长期有效)
AccessToken string // Access token (short-lived) | 访问令牌(短期有效)
LoginID string // User login ID | 用户登录ID
Device string // Device type | 设备类型
CreateTime int64 // Creation timestamp | 创建时间戳
ExpireTime int64 // Expiration timestamp | 过期时间戳
RefreshToken string `json:"refreshToken"` // Refresh token (long-lived) | 刷新令牌(长期有效)
AccessToken string `json:"accessToken"` // Access token (short-lived) | 访问令牌(短期有效)
LoginID string `json:"loginID"` // User login ID | 用户登录ID
Device string `json:"device"` // Device type | 设备类型
CreateTime int64 `json:"createTime"` // Creation timestamp | 创建时间戳
ExpireTime int64 `json:"expireTime"` // Expiration timestamp | 过期时间戳
}
// MarshalBinary implements encoding.BinaryMarshaler for Redis storage | 实现encoding.BinaryMarshaler接口用于Redis存储
func (r *RefreshTokenInfo) MarshalBinary() ([]byte, error) {
return json.Marshal(r)
}
// UnmarshalBinary implements encoding.BinaryUnmarshaler for Redis storage | 实现encoding.BinaryUnmarshaler接口用于Redis存储
func (r *RefreshTokenInfo) UnmarshalBinary(data []byte) error {
return json.Unmarshal(data, r)
}
// RefreshTokenManager Refresh token manager | 刷新令牌管理器

View File

@@ -22,24 +22,32 @@ Sa-Token-Go provides a powerful event system for monitoring authentication and a
## Basic Usage
### Create Event Manager
### Create Manager with Event Support
```go
import "github.com/click33/sa-token-go/core"
import (
"github.com/click33/sa-token-go/core"
"github.com/click33/sa-token-go/storage/memory"
)
eventMgr := core.NewEventManager()
manager := core.NewBuilder().
Storage(memory.NewStorage()).
Build()
// Optional: direct access to advanced controls
eventMgr := manager.GetEventManager()
```
### Register Listener (Function)
```go
// Listen to login event
eventMgr.RegisterFunc(core.EventLogin, func(data *core.EventData) {
manager.RegisterFunc(core.EventLogin, func(data *core.EventData) {
fmt.Printf("[LOGIN] User: %s, Token: %s\n", data.LoginID, data.Token)
})
// Listen to logout event
eventMgr.RegisterFunc(core.EventLogout, func(data *core.EventData) {
manager.RegisterFunc(core.EventLogout, func(data *core.EventData) {
fmt.Printf("[LOGOUT] User: %s\n", data.LoginID)
})
```
@@ -54,7 +62,7 @@ func (a *AuditLogger) OnEvent(data *core.EventData) {
fmt.Printf("[AUDIT] Event: %s, User: %s\n", data.Event, data.LoginID)
}
eventMgr.Register(core.EventLogin, &AuditLogger{})
manager.Register(core.EventLogin, &AuditLogger{})
```
## Advanced Features
@@ -63,7 +71,7 @@ eventMgr.Register(core.EventLogin, &AuditLogger{})
```go
// Higher priority listeners execute first
eventMgr.RegisterWithConfig(
manager.RegisterWithConfig(
core.EventLogin,
myListener,
core.ListenerConfig{
@@ -76,7 +84,7 @@ eventMgr.RegisterWithConfig(
```go
// Execute synchronously (blocking)
eventMgr.RegisterWithConfig(
manager.RegisterWithConfig(
core.EventLogin,
myListener,
core.ListenerConfig{
@@ -89,7 +97,7 @@ eventMgr.RegisterWithConfig(
```go
// Listen to all events
eventMgr.RegisterFunc(core.EventAll, func(data *core.EventData) {
manager.RegisterFunc(core.EventAll, func(data *core.EventData) {
fmt.Printf("[ALL] Event: %s, User: %s\n", data.Event, data.LoginID)
})
```
@@ -98,7 +106,7 @@ eventMgr.RegisterFunc(core.EventAll, func(data *core.EventData) {
```go
// Register and get ID
id := eventMgr.RegisterWithConfig(
id := manager.RegisterWithConfig(
core.EventLogin,
myListener,
core.ListenerConfig{
@@ -107,7 +115,7 @@ id := eventMgr.RegisterWithConfig(
)
// Unregister by ID
eventMgr.Unregister(id)
manager.Unregister(id)
```
## Use Cases
@@ -115,7 +123,7 @@ eventMgr.Unregister(id)
### Audit Logging
```go
eventMgr.RegisterFunc(core.EventAll, func(data *core.EventData) {
manager.RegisterFunc(core.EventAll, func(data *core.EventData) {
log.Printf("[AUDIT] %s - User: %s, IP: %s, Time: %d",
data.Event, data.LoginID, data.Extra["ip"], data.Timestamp)
})
@@ -124,7 +132,7 @@ eventMgr.RegisterFunc(core.EventAll, func(data *core.EventData) {
### Security Monitoring
```go
eventMgr.RegisterFunc(core.EventLogin, func(data *core.EventData) {
manager.RegisterFunc(core.EventLogin, func(data *core.EventData) {
// Check for suspicious login
// Send alert if needed
})
@@ -133,7 +141,7 @@ eventMgr.RegisterFunc(core.EventLogin, func(data *core.EventData) {
### Session Analytics
```go
eventMgr.RegisterFunc(core.EventLogin, func(data *core.EventData) {
manager.RegisterFunc(core.EventLogin, func(data *core.EventData) {
// Track active users
// Update analytics
})

View File

@@ -39,35 +39,32 @@ The event system allows you to:
## Basic Usage
### 1. Create an Event Manager
### 1. 创建带事件功能的 Manager
```go
import "github.com/click33/sa-token-go/core"
import (
"github.com/click33/sa-token-go/core"
"github.com/click33/sa-token-go/storage/memory"
)
eventManager := core.NewEventManager()
```
### 2. Register a Simple Listener
```go
// Function-based listener
eventManager.RegisterFunc(core.EventLogin, func(data *core.EventData) {
fmt.Printf("User logged in: %s\n", data.LoginID)
})
```
### 3. Register with the Manager
```go
manager := core.NewBuilder().
Storage(memory.NewStorage()).
Build()
// Set event manager (if your Manager supports it)
// Note: You may need to integrate this into your Manager initialization
// 如需高级控制,可以获取底层事件管理器
eventMgr := manager.GetEventManager()
```
### 4. Complete Example
### 2. 注册简单监听器
```go
// 基于函数的监听器
manager.RegisterFunc(core.EventLogin, func(data *core.EventData) {
fmt.Printf("User logged in: %s\n", data.LoginID)
})
```
### 3. 完整示例
```go
package main
@@ -80,26 +77,24 @@ import (
)
func main() {
// Create event manager
eventMgr := core.NewEventManager()
// Create manager with default event support
manager := core.NewBuilder().
Storage(memory.NewStorage()).
Build()
// Register login listener
eventMgr.RegisterFunc(core.EventLogin, func(data *core.EventData) {
manager.RegisterFunc(core.EventLogin, func(data *core.EventData) {
fmt.Printf("[LOGIN] User: %s, Token: %s, Device: %s\n",
data.LoginID, data.Token, data.Device)
})
// Register logout listener
eventMgr.RegisterFunc(core.EventLogout, func(data *core.EventData) {
manager.RegisterFunc(core.EventLogout, func(data *core.EventData) {
fmt.Printf("[LOGOUT] User: %s\n", data.LoginID)
})
// Initialize StpUtil
stputil.SetManager(
core.NewBuilder().
Storage(memory.NewStorage()).
Build(),
)
stputil.SetManager(manager)
// Perform login (will trigger event)
token, _ := stputil.Login(1000)
@@ -118,7 +113,7 @@ Control the execution order of listeners using priorities:
```go
// High priority listener (executes first)
eventMgr.RegisterWithConfig(core.EventLogin,
manager.RegisterWithConfig(core.EventLogin,
core.ListenerFunc(func(data *core.EventData) {
fmt.Println("High priority listener")
}),
@@ -129,7 +124,7 @@ eventMgr.RegisterWithConfig(core.EventLogin,
)
// Low priority listener (executes later)
eventMgr.RegisterWithConfig(core.EventLogin,
manager.RegisterWithConfig(core.EventLogin,
core.ListenerFunc(func(data *core.EventData) {
fmt.Println("Low priority listener")
}),
@@ -144,7 +139,7 @@ eventMgr.RegisterWithConfig(core.EventLogin,
```go
// Synchronous listener (blocks until complete)
eventMgr.RegisterWithConfig(core.EventLogin,
manager.RegisterWithConfig(core.EventLogin,
core.ListenerFunc(func(data *core.EventData) {
// Critical operation that must complete before continuing
saveToDatabase(data)
@@ -155,7 +150,7 @@ eventMgr.RegisterWithConfig(core.EventLogin,
)
// Asynchronous listener (non-blocking)
eventMgr.RegisterWithConfig(core.EventLogin,
manager.RegisterWithConfig(core.EventLogin,
core.ListenerFunc(func(data *core.EventData) {
// Non-critical operation (logging, analytics)
sendToAnalytics(data)
@@ -170,7 +165,7 @@ eventMgr.RegisterWithConfig(core.EventLogin,
```go
// Register with a custom ID
listenerID := eventMgr.RegisterWithConfig(core.EventLogin,
listenerID := manager.RegisterWithConfig(core.EventLogin,
core.ListenerFunc(func(data *core.EventData) {
fmt.Println("Temporary listener")
}),
@@ -180,7 +175,7 @@ listenerID := eventMgr.RegisterWithConfig(core.EventLogin,
)
// Later, unregister by ID
eventMgr.Unregister(listenerID)
manager.Unregister(listenerID)
```
### Wildcard Listeners
@@ -189,7 +184,7 @@ Listen to all events:
```go
// Listen to all events
eventMgr.RegisterFunc(core.EventAll, func(data *core.EventData) {
manager.RegisterFunc(core.EventAll, func(data *core.EventData) {
fmt.Printf("[%s] LoginID: %s\n", data.Event, data.LoginID)
})
```
@@ -230,7 +225,7 @@ stputil.Login(1000)
stputil.Login(2000)
// Wait for all async listeners to complete
eventMgr.Wait()
manager.WaitEvents()
```
## Best Practices
@@ -239,7 +234,7 @@ eventMgr.Wait()
```go
// ✅ Good: Async for logging
eventMgr.RegisterWithConfig(core.EventLogin,
manager.RegisterWithConfig(core.EventLogin,
core.ListenerFunc(func(data *core.EventData) {
logToFile(data) // Can be async
}),
@@ -247,7 +242,7 @@ eventMgr.RegisterWithConfig(core.EventLogin,
)
// ❌ Avoid: Sync for slow operations
eventMgr.RegisterWithConfig(core.EventLogin,
manager.RegisterWithConfig(core.EventLogin,
core.ListenerFunc(func(data *core.EventData) {
sendEmail(data) // Slow operation blocks login
}),
@@ -259,12 +254,12 @@ eventMgr.RegisterWithConfig(core.EventLogin,
```go
// ✅ Good: Quick processing
eventMgr.RegisterFunc(core.EventLogin, func(data *core.EventData) {
manager.RegisterFunc(core.EventLogin, func(data *core.EventData) {
counter.Increment("login_count")
})
// ❌ Avoid: Heavy processing
eventMgr.RegisterFunc(core.EventLogin, func(data *core.EventData) {
manager.RegisterFunc(core.EventLogin, func(data *core.EventData) {
processLargeDataset() // This should be in a background job
})
```
@@ -273,13 +268,13 @@ eventMgr.RegisterFunc(core.EventLogin, func(data *core.EventData) {
```go
// Validation (high priority)
eventMgr.RegisterWithConfig(core.EventLogin,
manager.RegisterWithConfig(core.EventLogin,
validationListener,
core.ListenerConfig{Priority: 100},
)
// Logging (low priority)
eventMgr.RegisterWithConfig(core.EventLogin,
manager.RegisterWithConfig(core.EventLogin,
loggingListener,
core.ListenerConfig{Priority: 10},
)
@@ -288,7 +283,7 @@ eventMgr.RegisterWithConfig(core.EventLogin,
### 4. Handle Errors Gracefully
```go
eventMgr.RegisterFunc(core.EventLogin, func(data *core.EventData) {
manager.RegisterFunc(core.EventLogin, func(data *core.EventData) {
defer func() {
if r := recover(); r != nil {
log.Printf("Listener error: %v", r)
@@ -317,7 +312,7 @@ func (a *AuditLogger) OnEvent(data *core.EventData) {
// Usage
logger := &AuditLogger{file: logFile}
eventMgr.Register(core.EventAll, logger)
manager.Register(core.EventAll, logger)
```
### Example 2: Security Monitor
@@ -338,14 +333,14 @@ func (s *SecurityMonitor) OnEvent(data *core.EventData) {
// Usage
monitor := &SecurityMonitor{alertChan: make(chan string, 100)}
eventMgr.Register(core.EventKickout, monitor)
eventMgr.Register(core.EventDisable, monitor)
manager.Register(core.EventKickout, monitor)
manager.Register(core.EventDisable, monitor)
```
### Example 3: Login Counter with Redis
```go
eventMgr.RegisterFunc(core.EventLogin, func(data *core.EventData) {
manager.RegisterFunc(core.EventLogin, func(data *core.EventData) {
// Increment daily login counter
key := fmt.Sprintf("login:count:%s", time.Now().Format("2006-01-02"))
redisClient.Incr(ctx, key)
@@ -360,7 +355,7 @@ eventMgr.RegisterFunc(core.EventLogin, func(data *core.EventData) {
### Example 4: Multi-Factor Authentication
```go
eventMgr.RegisterWithConfig(core.EventLogin,
manager.RegisterWithConfig(core.EventLogin,
core.ListenerFunc(func(data *core.EventData) {
// Check if MFA is required
if requiresMFA(data.LoginID) {
@@ -404,8 +399,8 @@ func (s *SessionAnalytics) OnEvent(data *core.EventData) {
// Usage
analytics := &SessionAnalytics{sessions: make(map[string]time.Time)}
eventMgr.Register(core.EventCreateSession, analytics)
eventMgr.Register(core.EventDestroySession, analytics)
manager.Register(core.EventCreateSession, analytics)
manager.Register(core.EventDestroySession, analytics)
```
## EventData Structure
@@ -424,7 +419,7 @@ type EventData struct {
### Accessing Extra Data
```go
eventMgr.RegisterFunc(core.EventLogin, func(data *core.EventData) {
manager.RegisterFunc(core.EventLogin, func(data *core.EventData) {
if ipAddr, ok := data.Extra["ip_address"].(string); ok {
fmt.Printf("Login from IP: %s\n", ipAddr)
}
@@ -441,8 +436,8 @@ All event manager operations are thread-safe:
```go
// Safe to call from multiple goroutines
go eventMgr.RegisterFunc(core.EventLogin, handler1)
go eventMgr.RegisterFunc(core.EventLogin, handler2)
go manager.RegisterFunc(core.EventLogin, handler1)
go manager.RegisterFunc(core.EventLogin, handler2)
go eventMgr.Trigger(&core.EventData{Event: core.EventLogin})
```

View File

@@ -289,7 +289,7 @@ if REFRESH_TOKEN_ROTATION {
```go
// Log refresh events
eventMgr.RegisterFunc(core.EventRefresh, func(data *core.EventData) {
manager.RegisterFunc(core.EventRefresh, func(data *core.EventData) {
// Detect abnormal refresh patterns
if isAbnormalRefreshPattern(data.LoginID) {
alert("Possible token leak")

View File

@@ -289,7 +289,7 @@ if REFRESH_TOKEN_ROTATION {
```go
// 记录刷新事件
eventMgr.RegisterFunc(core.EventRefresh, func(data *core.EventData) {
manager.RegisterFunc(core.EventRefresh, func(data *core.EventData) {
// 检测异常刷新模式
if isAbnormalRefreshPattern(data.LoginID) {
alert("可能的令牌泄露")

View File

@@ -59,12 +59,22 @@ Remaining listeners: 4
## Key Concepts
In this example the authentication manager automatically owns an internal event manager:
```go
manager := core.NewBuilder().
Storage(memory.NewStorage()).
Build()
eventMgr := manager.GetEventManager() // Advanced controls (stats, enable/disable, panic handler, ...)
```
### Function Listeners
The simplest way to register an event handler:
```go
eventMgr.RegisterFunc(core.EventLogin, func(data *core.EventData) {
manager.RegisterFunc(core.EventLogin, func(data *core.EventData) {
fmt.Printf("User %s logged in\n", data.LoginID)
})
```
@@ -74,7 +84,7 @@ eventMgr.RegisterFunc(core.EventLogin, func(data *core.EventData) {
Control execution order with priorities:
```go
eventMgr.RegisterWithConfig(core.EventLogin,
manager.RegisterWithConfig(core.EventLogin,
myListener,
core.ListenerConfig{
Priority: 100, // Higher = executes first
@@ -88,7 +98,7 @@ eventMgr.RegisterWithConfig(core.EventLogin,
Listen to all events:
```go
eventMgr.RegisterFunc(core.EventAll, func(data *core.EventData) {
manager.RegisterFunc(core.EventAll, func(data *core.EventData) {
// This will be called for every event
})
```
@@ -99,12 +109,12 @@ Add and remove listeners at runtime:
```go
// Register with custom ID
id := eventMgr.RegisterWithConfig(event, listener, core.ListenerConfig{
id := manager.RegisterWithConfig(event, listener, core.ListenerConfig{
ID: "my-listener",
})
// Later, unregister
eventMgr.Unregister(id)
manager.Unregister(id)
```
## Use Cases
@@ -112,7 +122,7 @@ eventMgr.Unregister(id)
### 1. Audit Logging
```go
eventMgr.RegisterFunc(core.EventAll, func(data *core.EventData) {
manager.RegisterFunc(core.EventAll, func(data *core.EventData) {
auditLog.Write(fmt.Sprintf("[%s] %s - %s",
data.Event, data.LoginID, time.Unix(data.Timestamp, 0)))
})
@@ -121,7 +131,7 @@ eventMgr.RegisterFunc(core.EventAll, func(data *core.EventData) {
### 2. Security Monitoring
```go
eventMgr.RegisterFunc(core.EventKickout, func(data *core.EventData) {
manager.RegisterFunc(core.EventKickout, func(data *core.EventData) {
alertSystem.Send(fmt.Sprintf("User %s was kicked out", data.LoginID))
})
```
@@ -129,7 +139,7 @@ eventMgr.RegisterFunc(core.EventKickout, func(data *core.EventData) {
### 3. Analytics
```go
eventMgr.RegisterFunc(core.EventLogin, func(data *core.EventData) {
manager.RegisterFunc(core.EventLogin, func(data *core.EventData) {
analytics.Track("user_login", map[string]interface{}{
"user_id": data.LoginID,
"device": data.Device,
@@ -140,7 +150,7 @@ eventMgr.RegisterFunc(core.EventLogin, func(data *core.EventData) {
### 4. Cache Invalidation
```go
eventMgr.RegisterFunc(core.EventLogout, func(data *core.EventData) {
manager.RegisterFunc(core.EventLogout, func(data *core.EventData) {
cache.Delete("user:" + data.LoginID)
})
```

View File

@@ -12,26 +12,29 @@ import (
func main() {
fmt.Println("=== Sa-Token-Go Event Listener Example ===\n")
// Create event manager
eventMgr := core.NewEventManager()
// 1. Simple function listener
eventMgr.RegisterFunc(core.EventLogin, func(data *core.EventData) {
manager := core.NewBuilder().
Storage(memory.NewStorage()).
TokenName("Authorization").
Timeout(7200).
Build()
manager.RegisterFunc(core.EventLogin, func(data *core.EventData) {
fmt.Printf("[LOGIN] User %s logged in with token %s\n", data.LoginID, data.Token[:20]+"...")
})
// 2. Logout listener
eventMgr.RegisterFunc(core.EventLogout, func(data *core.EventData) {
manager.RegisterFunc(core.EventLogout, func(data *core.EventData) {
fmt.Printf("[LOGOUT] User %s logged out\n", data.LoginID)
})
// 3. Kickout listener
eventMgr.RegisterFunc(core.EventKickout, func(data *core.EventData) {
manager.RegisterFunc(core.EventKickout, func(data *core.EventData) {
fmt.Printf("[KICKOUT] User %s was forcibly logged out\n", data.LoginID)
})
// 4. High-priority synchronous listener
eventMgr.RegisterWithConfig(core.EventLogin,
auditListenerID := manager.RegisterWithConfig(core.EventLogin,
core.ListenerFunc(func(data *core.EventData) {
fmt.Printf("[AUDIT] Login audit - User: %s, Time: %d\n",
data.LoginID, data.Timestamp)
@@ -44,23 +47,19 @@ func main() {
)
// 5. Wildcard listener (all events)
eventMgr.RegisterFunc(core.EventAll, func(data *core.EventData) {
manager.RegisterFunc(core.EventAll, func(data *core.EventData) {
fmt.Printf("[ALL EVENTS] %s\n", data.String())
})
eventMgr := manager.GetEventManager()
// 6. Custom panic handler
eventMgr.SetPanicHandler(func(event core.Event, data *core.EventData, recovered interface{}) {
fmt.Printf("[PANIC RECOVERED] Event: %s, Error: %v\n", event, recovered)
})
// Initialize Sa-Token
stputil.SetManager(
core.NewBuilder().
Storage(memory.NewStorage()).
TokenName("Authorization").
Timeout(7200).
Build(),
)
stputil.SetManager(manager)
fmt.Println("\n--- Triggering Events ---\n")
@@ -80,7 +79,7 @@ func main() {
time.Sleep(100 * time.Millisecond)
// Wait for all async listeners to complete
eventMgr.Wait()
manager.WaitEvents()
fmt.Println("\n--- Listener Statistics ---")
fmt.Printf("Total listeners: %d\n", eventMgr.Count())
@@ -89,7 +88,7 @@ func main() {
// Unregister a listener
fmt.Println("\n--- Unregistering audit logger ---")
if eventMgr.Unregister("audit-logger") {
if manager.Unregister(auditListenerID) {
fmt.Println("Audit logger unregistered successfully")
}

View File

@@ -0,0 +1,131 @@
package chi
import (
"net/http"
"strings"
"github.com/click33/sa-token-go/core"
"github.com/click33/sa-token-go/stputil"
)
// Annotation annotation structure | 注解结构体
type Annotation struct {
CheckLogin bool `json:"checkLogin"`
CheckRole []string `json:"checkRole"`
CheckPermission []string `json:"checkPermission"`
CheckDisable bool `json:"checkDisable"`
Ignore bool `json:"ignore"`
}
// GetHandler gets handler with annotations | 获取带注解的处理器
func GetHandler(handler http.Handler, annotations ...*Annotation) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Check if authentication should be ignored | 检查是否忽略认证
if len(annotations) > 0 && annotations[0].Ignore {
if handler != nil {
handler.ServeHTTP(w, r)
}
return
}
// Get token from context using configured TokenName | 从上下文获取Token使用配置的TokenName
ctx := NewChiContext(w, r)
saCtx := core.NewContext(ctx, stputil.GetManager())
token := saCtx.GetTokenValue()
if token == "" {
writeErrorResponse(w, core.NewNotLoginError())
return
}
// Check login | 检查登录
if !stputil.IsLogin(token) {
writeErrorResponse(w, core.NewNotLoginError())
return
}
// Get login ID | 获取登录ID
loginID, err := stputil.GetLoginID(token)
if err != nil {
writeErrorResponse(w, err)
return
}
// Check if account is disabled | 检查是否被封禁
if len(annotations) > 0 && annotations[0].CheckDisable {
if stputil.IsDisable(loginID) {
writeErrorResponse(w, core.NewAccountDisabledError(loginID))
return
}
}
// Check permission | 检查权限
if len(annotations) > 0 && len(annotations[0].CheckPermission) > 0 {
hasPermission := false
for _, perm := range annotations[0].CheckPermission {
if stputil.HasPermission(loginID, strings.TrimSpace(perm)) {
hasPermission = true
break
}
}
if !hasPermission {
writeErrorResponse(w, core.NewPermissionDeniedError(strings.Join(annotations[0].CheckPermission, ",")))
return
}
}
// Check role | 检查角色
if len(annotations) > 0 && len(annotations[0].CheckRole) > 0 {
hasRole := false
for _, role := range annotations[0].CheckRole {
if stputil.HasRole(loginID, strings.TrimSpace(role)) {
hasRole = true
break
}
}
if !hasRole {
writeErrorResponse(w, core.NewRoleDeniedError(strings.Join(annotations[0].CheckRole, ",")))
return
}
}
// All checks passed, execute original handler | 所有检查通过,执行原函数
if handler != nil {
handler.ServeHTTP(w, r)
}
})
}
// CheckLoginMiddleware decorator for login checking | 检查登录装饰器
func CheckLoginMiddleware() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return GetHandler(next, &Annotation{CheckLogin: true})
}
}
// CheckRoleMiddleware decorator for role checking | 检查角色装饰器
func CheckRoleMiddleware(roles ...string) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return GetHandler(next, &Annotation{CheckRole: roles})
}
}
// CheckPermissionMiddleware decorator for permission checking | 检查权限装饰器
func CheckPermissionMiddleware(perms ...string) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return GetHandler(next, &Annotation{CheckPermission: perms})
}
}
// CheckDisableMiddleware decorator for checking if account is disabled | 检查是否被封禁装饰器
func CheckDisableMiddleware() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return GetHandler(next, &Annotation{CheckDisable: true})
}
}
// IgnoreMiddleware decorator to ignore authentication | 忽略认证装饰器
func IgnoreMiddleware() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return GetHandler(next, &Annotation{Ignore: true})
}
}

View File

@@ -0,0 +1,126 @@
package echo
import (
"strings"
"github.com/click33/sa-token-go/core"
"github.com/click33/sa-token-go/stputil"
"github.com/labstack/echo/v4"
)
// Annotation annotation structure | 注解结构体
type Annotation struct {
CheckLogin bool `json:"checkLogin"`
CheckRole []string `json:"checkRole"`
CheckPermission []string `json:"checkPermission"`
CheckDisable bool `json:"checkDisable"`
Ignore bool `json:"ignore"`
}
// GetHandler gets handler with annotations | 获取带注解的处理器
func GetHandler(handler echo.HandlerFunc, annotations ...*Annotation) echo.HandlerFunc {
return func(c echo.Context) error {
// Check if authentication should be ignored | 检查是否忽略认证
if len(annotations) > 0 && annotations[0].Ignore {
if handler != nil {
return handler(c)
}
return nil
}
// Get token from context using configured TokenName | 从上下文获取Token使用配置的TokenName
ctx := NewEchoContext(c)
saCtx := core.NewContext(ctx, stputil.GetManager())
token := saCtx.GetTokenValue()
if token == "" {
return writeErrorResponse(c, core.NewNotLoginError())
}
// Check login | 检查登录
if !stputil.IsLogin(token) {
return writeErrorResponse(c, core.NewNotLoginError())
}
// Get login ID | 获取登录ID
loginID, err := stputil.GetLoginID(token)
if err != nil {
return writeErrorResponse(c, err)
}
// Check if account is disabled | 检查是否被封禁
if len(annotations) > 0 && annotations[0].CheckDisable {
if stputil.IsDisable(loginID) {
return writeErrorResponse(c, core.NewAccountDisabledError(loginID))
}
}
// Check permission | 检查权限
if len(annotations) > 0 && len(annotations[0].CheckPermission) > 0 {
hasPermission := false
for _, perm := range annotations[0].CheckPermission {
if stputil.HasPermission(loginID, strings.TrimSpace(perm)) {
hasPermission = true
break
}
}
if !hasPermission {
return writeErrorResponse(c, core.NewPermissionDeniedError(strings.Join(annotations[0].CheckPermission, ",")))
}
}
// Check role | 检查角色
if len(annotations) > 0 && len(annotations[0].CheckRole) > 0 {
hasRole := false
for _, role := range annotations[0].CheckRole {
if stputil.HasRole(loginID, strings.TrimSpace(role)) {
hasRole = true
break
}
}
if !hasRole {
return writeErrorResponse(c, core.NewRoleDeniedError(strings.Join(annotations[0].CheckRole, ",")))
}
}
// All checks passed, execute original handler | 所有检查通过,执行原函数
if handler != nil {
return handler(c)
}
return nil
}
}
// CheckLoginMiddleware decorator for login checking | 检查登录装饰器
func CheckLoginMiddleware() echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return GetHandler(next, &Annotation{CheckLogin: true})
}
}
// CheckRoleMiddleware decorator for role checking | 检查角色装饰器
func CheckRoleMiddleware(roles ...string) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return GetHandler(next, &Annotation{CheckRole: roles})
}
}
// CheckPermissionMiddleware decorator for permission checking | 检查权限装饰器
func CheckPermissionMiddleware(perms ...string) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return GetHandler(next, &Annotation{CheckPermission: perms})
}
}
// CheckDisableMiddleware decorator for checking if account is disabled | 检查是否被封禁装饰器
func CheckDisableMiddleware() echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return GetHandler(next, &Annotation{CheckDisable: true})
}
}
// IgnoreMiddleware decorator to ignore authentication | 忽略认证装饰器
func IgnoreMiddleware() echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return GetHandler(next, &Annotation{Ignore: true})
}
}

View File

@@ -0,0 +1,116 @@
package fiber
import (
"strings"
"github.com/click33/sa-token-go/core"
"github.com/click33/sa-token-go/stputil"
"github.com/gofiber/fiber/v2"
)
// Annotation annotation structure | 注解结构体
type Annotation struct {
CheckLogin bool `json:"checkLogin"`
CheckRole []string `json:"checkRole"`
CheckPermission []string `json:"checkPermission"`
CheckDisable bool `json:"checkDisable"`
Ignore bool `json:"ignore"`
}
// GetHandler gets handler with annotations | 获取带注解的处理器
func GetHandler(handler fiber.Handler, annotations ...*Annotation) fiber.Handler {
return func(c *fiber.Ctx) error {
// Check if authentication should be ignored | 检查是否忽略认证
if len(annotations) > 0 && annotations[0].Ignore {
if handler != nil {
return handler(c)
}
return c.Next()
}
// Get token from context using configured TokenName | 从上下文获取Token使用配置的TokenName
ctx := NewFiberContext(c)
saCtx := core.NewContext(ctx, stputil.GetManager())
token := saCtx.GetTokenValue()
if token == "" {
return writeErrorResponse(c, core.NewNotLoginError())
}
// Check login | 检查登录
if !stputil.IsLogin(token) {
return writeErrorResponse(c, core.NewNotLoginError())
}
// Get login ID | 获取登录ID
loginID, err := stputil.GetLoginID(token)
if err != nil {
return writeErrorResponse(c, err)
}
// Check if account is disabled | 检查是否被封禁
if len(annotations) > 0 && annotations[0].CheckDisable {
if stputil.IsDisable(loginID) {
return writeErrorResponse(c, core.NewAccountDisabledError(loginID))
}
}
// Check permission | 检查权限
if len(annotations) > 0 && len(annotations[0].CheckPermission) > 0 {
hasPermission := false
for _, perm := range annotations[0].CheckPermission {
if stputil.HasPermission(loginID, strings.TrimSpace(perm)) {
hasPermission = true
break
}
}
if !hasPermission {
return writeErrorResponse(c, core.NewPermissionDeniedError(strings.Join(annotations[0].CheckPermission, ",")))
}
}
// Check role | 检查角色
if len(annotations) > 0 && len(annotations[0].CheckRole) > 0 {
hasRole := false
for _, role := range annotations[0].CheckRole {
if stputil.HasRole(loginID, strings.TrimSpace(role)) {
hasRole = true
break
}
}
if !hasRole {
return writeErrorResponse(c, core.NewRoleDeniedError(strings.Join(annotations[0].CheckRole, ",")))
}
}
// All checks passed, execute original handler | 所有检查通过,执行原函数
if handler != nil {
return handler(c)
}
return c.Next()
}
}
// CheckLoginMiddleware decorator for login checking | 检查登录装饰器
func CheckLoginMiddleware() fiber.Handler {
return GetHandler(nil, &Annotation{CheckLogin: true})
}
// CheckRoleMiddleware decorator for role checking | 检查角色装饰器
func CheckRoleMiddleware(roles ...string) fiber.Handler {
return GetHandler(nil, &Annotation{CheckRole: roles})
}
// CheckPermissionMiddleware decorator for permission checking | 检查权限装饰器
func CheckPermissionMiddleware(perms ...string) fiber.Handler {
return GetHandler(nil, &Annotation{CheckPermission: perms})
}
// CheckDisableMiddleware decorator for checking if account is disabled | 检查是否被封禁装饰器
func CheckDisableMiddleware() fiber.Handler {
return GetHandler(nil, &Annotation{CheckDisable: true})
}
// IgnoreMiddleware decorator to ignore authentication | 忽略认证装饰器
func IgnoreMiddleware() fiber.Handler {
return GetHandler(nil, &Annotation{Ignore: true})
}

View File

@@ -0,0 +1,125 @@
package gf
import (
"strings"
"github.com/click33/sa-token-go/core"
"github.com/click33/sa-token-go/stputil"
"github.com/gogf/gf/v2/net/ghttp"
)
// Annotation annotation structure | 注解结构体
type Annotation struct {
CheckLogin bool `json:"checkLogin"`
CheckRole []string `json:"checkRole"`
CheckPermission []string `json:"checkPermission"`
CheckDisable bool `json:"checkDisable"`
Ignore bool `json:"ignore"`
}
// GetHandler gets handler with annotations | 获取带注解的处理器
func GetHandler(handler ghttp.HandlerFunc, annotations ...*Annotation) ghttp.HandlerFunc {
return func(r *ghttp.Request) {
// Check if authentication should be ignored | 检查是否忽略认证
if len(annotations) > 0 && annotations[0].Ignore {
if handler != nil {
handler(r)
} else {
r.Middleware.Next()
}
return
}
// Get token from context using configured TokenName | 从上下文获取Token使用配置的TokenName
ctx := NewGFContext(r)
saCtx := core.NewContext(ctx, stputil.GetManager())
token := saCtx.GetTokenValue()
if token == "" {
writeErrorResponse(r, core.NewNotLoginError())
return
}
// Check login | 检查登录
if !stputil.IsLogin(token) {
writeErrorResponse(r, core.NewNotLoginError())
return
}
// Get login ID | 获取登录ID
loginID, err := stputil.GetLoginID(token)
if err != nil {
writeErrorResponse(r, err)
return
}
// Check if account is disabled | 检查是否被封禁
if len(annotations) > 0 && annotations[0].CheckDisable {
if stputil.IsDisable(loginID) {
writeErrorResponse(r, core.NewAccountDisabledError(loginID))
return
}
}
// Check permission | 检查权限
if len(annotations) > 0 && len(annotations[0].CheckPermission) > 0 {
hasPermission := false
for _, perm := range annotations[0].CheckPermission {
if stputil.HasPermission(loginID, strings.TrimSpace(perm)) {
hasPermission = true
break
}
}
if !hasPermission {
writeErrorResponse(r, core.NewPermissionDeniedError(strings.Join(annotations[0].CheckPermission, ",")))
return
}
}
// Check role | 检查角色
if len(annotations) > 0 && len(annotations[0].CheckRole) > 0 {
hasRole := false
for _, role := range annotations[0].CheckRole {
if stputil.HasRole(loginID, strings.TrimSpace(role)) {
hasRole = true
break
}
}
if !hasRole {
writeErrorResponse(r, core.NewRoleDeniedError(strings.Join(annotations[0].CheckRole, ",")))
return
}
}
// All checks passed, execute original handler | 所有检查通过,执行原函数
if handler != nil {
handler(r)
} else {
r.Middleware.Next()
}
}
}
// CheckLoginMiddleware decorator for login checking | 检查登录装饰器
func CheckLoginMiddleware() ghttp.HandlerFunc {
return GetHandler(nil, &Annotation{CheckLogin: true})
}
// CheckRoleMiddleware decorator for role checking | 检查角色装饰器
func CheckRoleMiddleware(roles ...string) ghttp.HandlerFunc {
return GetHandler(nil, &Annotation{CheckRole: roles})
}
// CheckPermissionMiddleware decorator for permission checking | 检查权限装饰器
func CheckPermissionMiddleware(perms ...string) ghttp.HandlerFunc {
return GetHandler(nil, &Annotation{CheckPermission: perms})
}
// CheckDisableMiddleware decorator for checking if account is disabled | 检查是否被封禁装饰器
func CheckDisableMiddleware() ghttp.HandlerFunc {
return GetHandler(nil, &Annotation{CheckDisable: true})
}
// IgnoreMiddleware decorator to ignore authentication | 忽略认证装饰器
func IgnoreMiddleware() ghttp.HandlerFunc {
return GetHandler(nil, &Annotation{Ignore: true})
}

View File

@@ -1,10 +1,10 @@
package gin
import (
"net/http"
"reflect"
"strings"
"github.com/click33/sa-token-go/core"
"github.com/click33/sa-token-go/stputil"
ginfw "github.com/gin-gonic/gin"
)
@@ -92,53 +92,43 @@ func GetHandler(handler interface{}, annotations ...*Annotation) ginfw.HandlerFu
return func(c *ginfw.Context) {
// Check if authentication should be ignored | 检查是否忽略认证
if len(annotations) > 0 && annotations[0].Ignore {
if handler != nil {
handler.(func(*ginfw.Context))(c)
} else {
c.Next()
if callHandler(handler, c) {
return
}
c.Next()
return
}
// Get token | 获取Token
token := c.GetHeader("Authorization")
// Get token from context using configured TokenName | 从上下文获取Token使用配置的TokenName
ctx := NewGinContext(c)
saCtx := core.NewContext(ctx, stputil.GetManager())
token := saCtx.GetTokenValue()
if token == "" {
token = c.GetHeader("satoken")
}
if token == "" {
c.AbortWithStatusJSON(http.StatusUnauthorized, ginfw.H{
"code": 401,
"message": "未登录",
})
writeErrorResponse(c, core.NewNotLoginError())
c.Abort()
return
}
// Check login | 检查登录
if !stputil.IsLogin(token) {
c.AbortWithStatusJSON(http.StatusUnauthorized, ginfw.H{
"code": 401,
"message": "未登录",
})
writeErrorResponse(c, core.NewNotLoginError())
c.Abort()
return
}
// Get login ID | 获取登录ID
loginID, err := stputil.GetLoginID(token)
if err != nil {
c.AbortWithStatusJSON(http.StatusUnauthorized, ginfw.H{
"code": 401,
"message": "登录状态无效",
})
writeErrorResponse(c, err)
c.Abort()
return
}
// Check if account is disabled | 检查是否被封禁
if len(annotations) > 0 && annotations[0].CheckDisable {
if stputil.IsDisable(loginID) {
c.AbortWithStatusJSON(http.StatusForbidden, ginfw.H{
"code": 403,
"message": "账号已被封禁",
})
writeErrorResponse(c, core.NewAccountDisabledError(loginID))
c.Abort()
return
}
}
@@ -153,10 +143,8 @@ func GetHandler(handler interface{}, annotations ...*Annotation) ginfw.HandlerFu
}
}
if !hasPermission {
c.AbortWithStatusJSON(http.StatusForbidden, ginfw.H{
"code": 403,
"message": "权限不足",
})
writeErrorResponse(c, core.NewPermissionDeniedError(strings.Join(annotations[0].CheckPermission, ",")))
c.Abort()
return
}
}
@@ -171,23 +159,54 @@ func GetHandler(handler interface{}, annotations ...*Annotation) ginfw.HandlerFu
}
}
if !hasRole {
c.AbortWithStatusJSON(http.StatusForbidden, ginfw.H{
"code": 403,
"message": "角色不足",
})
writeErrorResponse(c, core.NewRoleDeniedError(strings.Join(annotations[0].CheckRole, ",")))
c.Abort()
return
}
}
// All checks passed, execute original handler or continue | 所有检查通过,执行原函数或继续
if handler != nil {
handler.(func(*ginfw.Context))(c)
} else {
c.Next()
if callHandler(handler, c) {
return
}
c.Next()
}
}
func callHandler(handler interface{}, c *ginfw.Context) bool {
if handler == nil {
return false
}
switch h := handler.(type) {
case func(*ginfw.Context):
if h == nil {
return false
}
h(c)
return true
case ginfw.HandlerFunc:
if h == nil {
return false
}
h(c)
return true
}
hv := reflect.ValueOf(handler)
if hv.Kind() != reflect.Func || hv.IsNil() || hv.Type().NumIn() != 1 {
return false
}
argType := hv.Type().In(0)
if !argType.AssignableTo(reflect.TypeOf(c)) {
return false
}
hv.Call([]reflect.Value{reflect.ValueOf(c)})
return true
}
// Decorator functions | 装饰器函数
// CheckLogin decorator for login checking | 检查登录装饰器
@@ -277,45 +296,36 @@ func Middleware(annotations ...*Annotation) ginfw.HandlerFunc {
return
}
// 获取Token
token := c.GetHeader("Authorization")
// 获取Token使用配置的TokenName
ctx := NewGinContext(c)
saCtx := core.NewContext(ctx, stputil.GetManager())
token := saCtx.GetTokenValue()
if token == "" {
token = c.GetHeader("satoken")
}
if token == "" {
c.AbortWithStatusJSON(http.StatusUnauthorized, ginfw.H{
"code": 401,
"message": "未登录",
})
writeErrorResponse(c, core.NewNotLoginError())
c.Abort()
return
}
// 检查登录
if !stputil.IsLogin(token) {
c.AbortWithStatusJSON(http.StatusUnauthorized, ginfw.H{
"code": 401,
"message": "未登录",
})
writeErrorResponse(c, core.NewNotLoginError())
c.Abort()
return
}
// 获取登录ID
loginID, err := stputil.GetLoginID(token)
if err != nil {
c.AbortWithStatusJSON(http.StatusUnauthorized, ginfw.H{
"code": 401,
"message": "登录状态无效",
})
writeErrorResponse(c, err)
c.Abort()
return
}
// 检查是否被封禁
if len(annotations) > 0 && annotations[0].CheckDisable {
if stputil.IsDisable(loginID) {
c.AbortWithStatusJSON(http.StatusForbidden, ginfw.H{
"code": 403,
"message": "账号已被封禁",
})
writeErrorResponse(c, core.NewAccountDisabledError(loginID))
c.Abort()
return
}
}
@@ -330,10 +340,8 @@ func Middleware(annotations ...*Annotation) ginfw.HandlerFunc {
}
}
if !hasPermission {
c.AbortWithStatusJSON(http.StatusForbidden, ginfw.H{
"code": 403,
"message": "权限不足",
})
writeErrorResponse(c, core.NewPermissionDeniedError(strings.Join(annotations[0].CheckPermission, ",")))
c.Abort()
return
}
}
@@ -348,10 +356,8 @@ func Middleware(annotations ...*Annotation) ginfw.HandlerFunc {
}
}
if !hasRole {
c.AbortWithStatusJSON(http.StatusForbidden, ginfw.H{
"code": 403,
"message": "角色不足",
})
writeErrorResponse(c, core.NewRoleDeniedError(strings.Join(annotations[0].CheckRole, ",")))
c.Abort()
return
}
}