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.

Code Wrench
Code Wrench
Code Wrench
How to Build a Unified Authentication & Authorization System for Microservices with easyms

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

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

MicroservicesAuthenticationJWTAuthorizationeasyms
Code Wrench
Written by

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. 🔧💻

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.