English | 中文
A lightweight, high-performance Go authentication and authorization framework, inspired by sa-token.
- 🔐 Authentication - Multi-device login, Token management
- 🛡️ Authorization - Fine-grained permission control, wildcard support (
*,user:*,user:*:view) - 👥 Role Management - Flexible role authorization mechanism
- 🚫 Account Ban - Temporary/permanent account disabling
- 👢 Kickout - Force user logout, multi-device mutual exclusion
- 💾 Session Management - Complete Session management
- ⏰ Active Detection - Automatic token activity detection
- 🔄 Auto Renewal - Asynchronous token auto-renewal (400% performance improvement)
- 🎨 Annotation Support -
@SaCheckLogin,@SaCheckRole,@SaCheckPermission - 🎧 Event System - Powerful event system with priority and async execution
- 📦 Modular Design - Import only what you need, minimal dependencies
- 🔒 Nonce Anti-Replay - Prevent replay attacks with one-time tokens
- 🔄 Refresh Token - Refresh token mechanism with seamless refresh
- 🔐 OAuth2 - Complete OAuth2 authorization code flow implementation
Import only one framework integration package, which automatically includes core and stputil!
# Import only the framework integration (includes core + stputil automatically)
go get github.com/click33/sa-token-go/integrations/gin@v0.1.2 # Gin framework
# or
go get github.com/click33/sa-token-go/integrations/echo@v0.1.2 # Echo framework
# or
go get github.com/click33/sa-token-go/integrations/fiber@v0.1.2 # Fiber framework
# or
go get github.com/click33/sa-token-go/integrations/chi@v0.1.2 # Chi framework
# or
go get github.com/click33/sa-token-go/integrations/gf@v0.1.2 # GoFrame framework
# Storage module (choose one)
go get github.com/click33/sa-token-go/storage/memory@v0.1.2 # Memory storage (dev)
go get github.com/click33/sa-token-go/storage/redis@v0.1.2 # Redis storage (prod)# Core modules
go get github.com/click33/sa-token-go/core@v0.1.2
go get github.com/click33/sa-token-go/stputil@v0.1.2
# Storage module (choose one)
go get github.com/click33/sa-token-go/storage/memory@v0.1.2 # Memory storage (dev)
go get github.com/click33/sa-token-go/storage/redis@v0.1.2 # Redis storage (prod)
# Framework integration (optional)
go get github.com/click33/sa-token-go/integrations/gin@v0.1.2 # Gin framework
go get github.com/click33/sa-token-go/integrations/echo@v0.1.2 # Echo framework
go get github.com/click33/sa-token-go/integrations/fiber@v0.1.2 # Fiber framework
go get github.com/click33/sa-token-go/integrations/chi@v0.1.2 # Chi frameworkpackage main
import (
"github.com/click33/sa-token-go/core"
"github.com/click33/sa-token-go/stputil"
"github.com/click33/sa-token-go/storage/memory"
)
func init() {
// One-line initialization! Shows startup banner
stputil.SetManager(
core.NewBuilder().
Storage(memory.NewStorage()).
TokenName("Authorization").
Timeout(86400). // 24 hours
TokenStyle(core.TokenStyleRandom64). // Token style
IsPrintBanner(true). // Show startup banner
Build(),
)
}Startup banner will be displayed:
_____ ______ __ ______
/ ___/____ _ /_ __/___ / /_____ ____ / ____/____
\__ \/ __ | / / / __ \/ //_/ _ \/ __ \_____/ / __/ __ \
___/ / /_/ / / / / /_/ / ,< / __/ / / /_____/ /_/ / /_/ /
/____/\__,_/ /_/ \____/_/|_|\___/_/ /_/ \____/\____/
:: Sa-Token-Go :: (v0.1.2)
:: Go Version :: go1.21.0
:: GOOS/GOARCH :: linux/amd64
┌─────────────────────────────────────────────────────────┐
│ Token Style : random64 │
│ Token Timeout : 86400 seconds │
│ Auto Renew : true │
└─────────────────────────────────────────────────────────┘
func main() {
// Use StpUtil directly without passing manager
token, _ := stputil.Login(1000)
println("Login successful, Token:", token)
// Set permissions
stputil.SetPermissions(1000, []string{"user:read", "user:write"})
// Check permissions
if stputil.HasPermission(1000, "user:read") {
println("Has permission!")
}
// Logout
stputil.Logout(1000)
}// Login
token, _ := stputil.Login(1000)
token, _ := stputil.Login("user123")
token, _ := stputil.Login(1000, "mobile") // Specify device
// Check login status
isLogin := stputil.IsLogin(token)
// Get login ID
loginID, _ := stputil.GetLoginID(token)
// Logout
stputil.Logout(1000)
stputil.LogoutByToken(token)
// Kickout
stputil.Kickout(1000)
stputil.Kickout(1000, "mobile")// Set permissions
stputil.SetPermissions(1000, []string{
"user:read",
"user:write",
"admin:*", // Wildcard: matches all admin permissions
})
// Check single permission
hasPermission := stputil.HasPermission(1000, "user:read")
hasPermission := stputil.HasPermission(1000, "admin:delete") // Wildcard match
// Check multiple permissions
hasAll := stputil.HasPermissionsAnd(1000, []string{"user:read", "user:write"}) // AND logic
hasAny := stputil.HasPermissionsOr(1000, []string{"admin", "super"}) // OR logic// Set roles
stputil.SetRoles(1000, []string{"admin", "manager"})
// Check role
hasRole := stputil.HasRole(1000, "admin")
// Check multiple roles
hasAll := stputil.HasRolesAnd(1000, []string{"admin", "manager"})
hasAny := stputil.HasRolesOr(1000, []string{"admin", "super"})// Get session
sess, _ := stputil.GetSession(1000)
// Set data
sess.Set("nickname", "John")
sess.Set("age", 25)
// Get data
nickname := sess.GetString("nickname")
age := sess.GetInt("age")
// Delete data
sess.Delete("nickname")
// Delete session
stputil.DeleteSession(1000)// Disable for 1 hour
stputil.Disable(1000, 1*time.Hour)
// Permanent disable
stputil.Disable(1000, 0)
// Enable account
stputil.Untie(1000)
// Check if disabled
isDisabled := stputil.IsDisable(1000)
// Get remaining disable time
remainingTime, _ := stputil.GetDisableTime(1000)New way: Import only integrations/gin to use all features!
import (
"github.com/gin-gonic/gin"
sagin "github.com/click33/sa-token-go/integrations/gin" // Only this import needed!
"github.com/click33/sa-token-go/storage/memory"
)
func main() {
// Initialize (all features in sagin package)
storage := memory.NewStorage()
config := sagin.DefaultConfig()
manager := sagin.NewManager(storage, config)
sagin.SetManager(manager)
r := gin.Default()
// Login endpoint
r.POST("/login", func(c *gin.Context) {
userID := c.PostForm("user_id")
token, _ := sagin.Login(userID)
c.JSON(200, gin.H{"token": token})
})
// Use annotation-style decorators (like Java)
r.GET("/public", sagin.Ignore(), publicHandler) // Public access
r.GET("/user", sagin.CheckLogin(), userHandler) // Login required
r.GET("/admin", sagin.CheckPermission("admin:*"), adminHandler) // Permission required
r.GET("/manager", sagin.CheckRole("manager"), managerHandler) // Role required
r.GET("/sensitive", sagin.CheckDisable(), sensitiveHandler) // Check if disabled
r.Run(":8080")
}Supported annotations:
| Annotation | Description | Example |
|---|---|---|
@SaIgnore |
Ignore authentication | sagin.Ignore() |
@SaCheckLogin |
Check login | sagin.CheckLogin() |
@SaCheckRole |
Check role | sagin.CheckRole("admin") |
@SaCheckPermission |
Check permission | sagin.CheckPermission("admin:*") |
@SaCheckDisable |
Check if disabled | sagin.CheckDisable() |
Usage example:
import sagin "github.com/click33/sa-token-go/integrations/gin"
func main() {
r := gin.Default()
// Public access - ignore authentication
r.GET("/public", sagin.Ignore(), publicHandler)
// Login required
r.GET("/user/info", sagin.CheckLogin(), userInfoHandler)
// Admin permission required
r.GET("/admin", sagin.CheckPermission("admin:*"), adminHandler)
// Any of multiple permissions (OR logic)
r.GET("/user-or-admin",
sagin.CheckPermission("user:read", "admin:*"),
userOrAdminHandler)
// Admin role required
r.GET("/manager", sagin.CheckRole("admin"), managerHandler)
// Check if account is disabled
r.GET("/sensitive", sagin.CheckDisable(), sensitiveHandler)
r.Run(":8080")
}GoFrame framework integration with full feature support!
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
sagf "github.com/click33/sa-token-go/integrations/gf" // Only this import needed!
"github.com/click33/sa-token-go/storage/memory"
)
func main() {
// Initialize (all features in sagf package)
storage := memory.NewStorage()
config := sagf.DefaultConfig()
manager := sagf.NewManager(storage, config)
sagf.SetManager(manager)
s := g.Server()
// Login endpoint
s.BindHandler("POST:/login", func(r *ghttp.Request) {
userID := r.Get("user_id").String()
token, _ := sagf.Login(userID)
r.Response.WriteJson(g.Map{"token": token})
})
// Use annotation-style decorators (like Java)
s.BindHandler("GET:/public", sagf.Ignore(), publicHandler) // Public access
s.BindHandler("GET:/user", sagf.CheckLogin(), userHandler) // Login required
s.BindHandler("GET:/admin", sagf.CheckPermission("admin:*"), adminHandler) // Permission required
s.BindHandler("GET:/manager", sagf.CheckRole("manager"), managerHandler) // Role required
s.BindHandler("GET:/sensitive", sagf.CheckDisable(), sensitiveHandler) // Check if disabled
s.SetPort(8080)
s.Run()
}Echo / Fiber / Chi also support annotation decorators:
// Echo
import saecho "github.com/click33/sa-token-go/integrations/echo"
e.GET("/user", saecho.CheckLogin(), handler)
// Fiber
import safiber "github.com/click33/sa-token-go/integrations/fiber"
app.Get("/user", safiber.CheckLogin(), handler)
// Chi
import sachi "github.com/click33/sa-token-go/integrations/chi"
r.Get("/user", sachi.CheckLogin(), handler)Sa-Token-Go supports 9 token generation styles:
| Style | Format Example | Length | Use Case |
|---|---|---|---|
| UUID | 550e8400-e29b-41d4-... |
36 | General purpose |
| Simple | aB3dE5fG7hI9jK1l |
16 | Compact tokens |
| Random32/64/128 | Random string | 32/64/128 | High security |
| JWT | eyJhbGciOiJIUzI1... |
Variable | Stateless auth |
| Hash 🆕 | a3f5d8b2c1e4f6a9... |
64 | SHA256 hash |
| Timestamp 🆕 | 1700000000123_user1000_... |
Variable | Time traceable |
| Tik 🆕 | 7Kx9mN2pQr4 |
11 | Short ID (like TikTok) |
JWT Token Support:
// Use JWT Token
stputil.SetManager(
core.NewBuilder().
Storage(memory.NewStorage()).
TokenStyle(core.TokenStyleJWT). // Use JWT
JwtSecretKey("your-256-bit-secret"). // JWT secret
Timeout(3600). // 1 hour expiration
Build(),
)
// Login to get JWT Token
token, _ := stputil.Login(1000)
// Format: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...// Generate nonce
nonce, _ := stputil.GenerateNonce()
// Verify nonce (one-time use)
valid := stputil.VerifyNonce(nonce) // true
valid = stputil.VerifyNonce(nonce) // false (prevents replay)// Login to get access token and refresh token
tokenInfo, _ := stputil.LoginWithRefreshToken(1000, "web")
fmt.Println("Access Token:", tokenInfo.AccessToken)
fmt.Println("Refresh Token:", tokenInfo.RefreshToken)
// Refresh access token
newInfo, _ := stputil.RefreshAccessToken(tokenInfo.RefreshToken)// Create OAuth2 server
oauth2Server := stputil.GetOAuth2Server()
// Register client
oauth2Server.RegisterClient(&core.OAuth2Client{
ClientID: "webapp",
ClientSecret: "secret123",
RedirectURIs: []string{"http://localhost:8080/callback"},
GrantTypes: []core.OAuth2GrantType{core.GrantTypeAuthorizationCode},
Scopes: []string{"read", "write"},
})
// Generate authorization code
authCode, _ := oauth2Server.GenerateAuthorizationCode(
"webapp", "http://localhost:8080/callback", "user123", []string{"read"},
)
// Exchange authorization code for access token
accessToken, _ := oauth2Server.ExchangeCodeForToken(
authCode.Code, "webapp", "secret123", "http://localhost:8080/callback",
)👉 View Complete OAuth2 Example
Listen to authentication and authorization events for audit logging, security monitoring, etc:
// Create event manager
eventMgr := core.NewEventManager()
// Listen to login events
eventMgr.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) {
fmt.Printf("[LOGOUT] User: %s\n", data.LoginID)
})
// Advanced: priority and sync execution
eventMgr.RegisterWithConfig(core.EventLogin,
core.ListenerFunc(auditLogger),
core.ListenerConfig{
Priority: 100, // High priority
Async: false, // Sync execution
},
)
// Listen to all events (wildcard)
eventMgr.RegisterFunc(core.EventAll, func(data *core.EventData) {
log.Printf("[%s] %s", data.Event, data.LoginID)
})Available events:
EventLogin- User loginEventLogout- User logoutEventKickout- Force logoutEventDisable- Account banEventPermissionCheck- Permission checkEventRoleCheck- Role checkEventAll- All events (wildcard)
→ View Event System Documentation
sa-token-go/
├── core/ # Core module
│ ├── adapter/ # Adapter interfaces
│ ├── builder/ # Builder pattern
│ ├── config/ # Configuration
│ ├── context/ # Context
│ ├── listener/ # Event listener
│ ├── manager/ # Authentication manager
│ ├── oauth2/ # OAuth2 implementation 🆕
│ ├── security/ # Security features (Nonce, RefreshToken) 🆕
│ ├── session/ # Session management
│ ├── token/ # Token generator
│ └── utils/ # Utility functions
│
├── stputil/ # Global utility
│
├── storage/ # Storage modules
│ ├── memory/ # Memory storage
│ └── redis/ # Redis storage
│
├── integrations/ # Framework integrations
│ ├── gin/ # Gin integration (with annotations)
│ ├── echo/ # Echo integration
│ ├── fiber/ # Fiber integration
│ └── chi/ # Chi integration
│
├── examples/ # Example projects
│ ├── quick-start/ # Quick start
│ ├── token-styles/ # Token style demos 🆕
│ ├── security-features/ # Security features demos 🆕
│ ├── oauth2-example/ # Complete OAuth2 example 🆕
│ ├── annotation/ # Annotation usage
│ ├── jwt-example/ # JWT example
│ ├── redis-example/ # Redis example
│ ├── listener-example/ # Event listener example
│ └── gin/echo/fiber/chi/ # Framework integration examples
│
└── docs/ # Documentation
├── tutorial/ # Tutorials
├── guide/ # Usage guides
├── api/ # API documentation
└── design/ # Design documents
- Quick Start - Get started in 5 minutes
- Authentication - Authentication guide
- Permission - Permission system
- Annotations - Decorator pattern guide
- Event Listener - Event system guide
- JWT Integration - JWT token guide
- Redis Storage - Redis storage configuration
- Nonce Anti-Replay - Nonce anti-replay attack
- Refresh Token - Refresh token mechanism
- OAuth2 - OAuth2 authorization guide
- StpUtil API - Complete global utility API reference
- Architecture Design - System architecture and data flow
- Auto-Renewal Design - Asynchronous renewal mechanism
- Modular Design - Module organization strategy
| Example | Description | Path |
|---|---|---|
| ⚡ Quick Start | Builder+StpUtil minimal usage | examples/quick-start/ |
| 🎨 Token Styles | 9 token style demonstrations | examples/token-styles/ |
| 🔒 Security Features | Nonce/RefreshToken/OAuth2 | examples/security-features/ |
| 🔐 OAuth2 Example | Complete OAuth2 implementation | examples/oauth2-example/ |
| 📝 Annotations | Annotation usage example | examples/annotation/ |
| 🔑 JWT Example | JWT token usage | examples/jwt-example/ |
| 💾 Redis Example | Redis storage example | examples/redis-example/ |
| 🎧 Event Listener | Event system usage | examples/listener-example/ |
| 🌐 Gin Integration | Complete Gin integration | examples/gin/ |
| 🌐 Echo Integration | Echo framework integration | examples/echo/ |
| 🌐 Fiber Integration | Fiber framework integration | examples/fiber/ |
| 🌐 Chi Integration | Chi framework integration | examples/chi/ |
| 🌐 GoFrame Integration | GoFrame framework integration | examples/gf/ |
- Memory Storage - For development environment
- Redis Storage - For production environment
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
- Inspired by sa-token - A powerful Java authentication framework
- Built with ❤️ using Go
- 📧 Email: support@sa-token-go.dev
- 💬 Issues: GitHub Issues
- 📖 Documentation: docs/