How to Build a Unified Authentication & Authorization System for Microservices with easyms
Learn how to design and implement a unified authentication and authorization system for complex microservice architectures using the open‑source easyms project, covering core components, JWT handling, token revocation, API‑gateway integration, security best practices, and extensible features.
Why Microservices Need Unified Authentication and Authorization
In a large community analogy, each service having its own key creates complexity and security gaps. A unified authentication and authorization (UAA) system acts like a single access card, allowing users to log in once and access all services securely.
Overall System Architecture
Core Components
Auth Service : issues and validates tokens.
User Service : provides user data.
API Gateway : single entry point that intercepts and validates authentication.
Service Discovery (Consul) : registers and discovers services.
Architecture Flow Diagram
┌──────────────┐ 1.获取Token ┌──────────────┐
│ 客户端 │ ───────────→ │ 认证服务 │
└──────────────┘ └──────────────┘
│ │
│ 2. 携带Token访问 │
↓ │
┌──────────────┐ 3.验证Token ┌──────────────┐
│ API网关 │ ───────────→ │ Token验证器 │
└──────────────┘ └──────────────┘
│ │
│ 4. 转发请求 │
↓ │
┌──────────────┐ │
│ 用户服务 │ ◀─────────────────┘
└──────────────┘Auth Service Implementation
1. Secure Password Storage
Passwords are hashed with bcrypt to avoid storing plaintext.
// HashPassword 使用 bcrypt 哈希密码
func (u *UserDetails) HashPassword() error {
hashed, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)
if err != nil { return err }
u.PasswordHash = string(hashed)
return nil
}
// CheckPassword 校验密码
func (u *UserDetails) CheckPassword(password string) bool {
return bcrypt.CompareHashAndPassword([]byte(u.PasswordHash), []byte(password)) == nil
}2. JWT Token Generation
Tokens are signed with RS256 to ensure integrity.
type OAuth2TokenCustomClaims struct {
UserDetails UserDetails
ClientDetails ClientDetails
RefreshToken OAuth2Token
JTI string // 防重放攻击
IssuedAt int64
jwt.StandardClaims
}3. Token Revocation Mechanism
Since JWTs are self‑contained, a blacklist stored in the database is used for revocation.
type RevokedToken struct {
ID int64 `gorm:"primaryKey"`
TokenValue string `gorm:"uniqueIndex"`
Expiry time.Time `gorm:"index"`
}
func (store *JwtTokenStore) RemoveAccessToken(token string) {
revoked := &RevokedToken{TokenValue: token, Expiry: time.Now().Add(24*time.Hour)}
store.db.Insert(revoked)
}API Gateway Authentication
The gateway validates JWTs before forwarding requests.
func (v *Validator) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authz := r.Header.Get("Authorization")
if !strings.HasPrefix(strings.ToLower(authz), "bearer ") {
http.Error(w, "missing bearer token", http.StatusUnauthorized)
return
}
raw := strings.TrimPrefix(authz, "Bearer ")
parser := jwt.NewParser(jwt.WithValidMethods([]string{"RS256"}))
var claims jwt.MapClaims
_, err := parser.ParseWithClaims(raw, &claims, func(t *jwt.Token) (interface{}, error) {
keyID := t.Header["kid"].(string)
key, found := v.set.LookupKeyID(keyID)
if !found { return nil, errors.New("unknown key") }
var rawKey interface{}
_ = key.Raw(&rawKey)
return rawKey, nil
})
if err != nil {
http.Error(w, "invalid token", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r.WithContext(context.WithValue(r.Context(), "claims", claims)))
})
}Technical Highlights
Security : bcrypt password storage, RS256‑signed JWT, blacklist revocation.
Extensibility : Consul for service discovery, multi‑environment configuration.
Usability : unified auth middleware lets business services ignore authentication logic.
Pitfalls to Avoid
Consul Key Path : must follow easyms/<service>/<env>.
Database Configuration : Auth service requires PostgreSQL support.
Key Management : store private keys securely (Vault/KMS) and never hard‑code them.
Extended Play Ideas
Support additional OAuth2 flows (authorization code, password grant).
Implement role‑based access control (RBAC).
Record audit logs of user actions.
Integrate multi‑factor authentication (MFA).
Conclusion
Using easyms's unified authentication and authorization, a microservice ecosystem can achieve:
Single sign‑on for users across all services.
Business services focus on core logic without duplicating auth code.
Improved security and scalability, acting like an intelligent “butler” that precisely identifies users and allocates permissions.
Source code repositories:
GitHub: https://github.com/louis-xie-programmer/easyms.golang
Gitee: https://gitee.com/louis_xie/easyms.golang
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Code Wrench
Focuses on code debugging, performance optimization, and real-world engineering, sharing efficient development tips and pitfall guides. We break down technical challenges in a down-to-earth style, helping you craft handy tools so every line of code becomes a problem‑solving weapon. 🔧💻
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
