Middleware System
Table of Contents
- Introduction
- Project Structure
- Core Components
- Architecture Overview
- Detailed Component Analysis
- Dependency Analysis
- Performance Considerations
- Troubleshooting Guide
- Conclusion
- Appendix
Introduction
This document systematically organizes and explains the HTTP middleware system in this repository, focusing on the following aspects:
- Middleware execution order and chain invocation mechanism
- JWT authentication middleware's identity verification flow, token parsing and user information extraction
- Casbin authorization middleware's RBAC permission control, policy matching and access decision
- RSA permission verification middleware's public key verification, signature verification and security protection
- Middleware configuration, error handling, performance optimization best practices
- Custom middleware development, testing strategies and debugging techniques
Project Structure
Middleware is located in the middlewares directory of the adapter layer HTTP layer, combined with user claims, principal information, RSA authorization configuration and implementation in the auth package, as well as bootstrap's authorization assembly tool, forming a complete authentication and authorization chain.
Core Components
- JWT Authentication Middleware: Responsible for parsing Bearer Token from request header, validating signature and expiration, extracting user identity and injecting into context.
- Casbin Authorization Middleware: Based on RBAC model, uses Casbin mandatory access control, performs policy matching by path and method.
- RSA Permission Verification Middleware: Based on RSA-PSS signature, combines timestamp, nonce and request body for anti-replay and integrity verification.
- User Claims and Principal: UserClaims extends registered claims and carries user ID and roles; Principal serves as current user carrier in context.
- RSA Authorization Configuration and Implementation: RSAAuthConfig provides pluggable public key provider, nonce storage and signature cache interfaces and memory implementation.
- Bootstrap and Assembly: Authorization component is used to centrally manage middleware registration and named access.
Architecture Overview
Middleware chain follows Gin's Next/Abort pattern, executes sequentially in registration order. Typical authentication chain is as follows:
- RSA client signature verification (optional, for external clients)
- JWT identity authentication (extracts user principal information)
- Casbin RBAC permission control (based on path and method)
Detailed Component Analysis
JWT Authentication Middleware
Key Features
- Parses Bearer Token from Authorization header
- Uses HMAC signature method and specified secret key to parse and validate
- Based on v5 error type judgment, distinguishes malformed, expired, signature invalid, etc.
- Injects Principal into request context after success, convenient for subsequent handler use
Key Flow Diagram
Casbin Authorization Middleware
Key Features
- Gets username from context (usually injected by JWT middleware)
- Uses request path as resource (obj), HTTP method as action (act)
- Uses Casbin Enforcer to execute policy matching
- Allows on success, otherwise returns 403
Key Flow Diagram
RSA Permission Verification Middleware
Key Features
- Reads client ID, signature, nonce, timestamp from request headers
- Validates timestamp window and nonce deduplication, prevents replay
- Gets public key based on client ID, decodes Base64 signature
- Uses SHA256+RSA-PSS to verify request body integrity
- Optional signature cache improves performance
Key Flow Diagram
User Claims and Principal
Dependency Analysis
Coupling Between Middleware
- JWT middleware is strongly associated with user claims/principal, responsible for identity injection
- Casbin middleware depends on username in context, usually provided by JWT middleware
- RSA middleware depends on pluggable public key provider, nonce storage and signature cache
External Dependencies
- JWT uses golang-jwt/jwt/v5, error type judgment based on v5's Is... helper functions
- Casbin uses casbin/casbin/v2
- RSA verification uses crypto/* and golang.org/x/crypto/ssh
Possible Circular Dependencies
- Currently middleware passes information through context, no direct circular import seen
Performance Considerations
Signature Cache
- RSA middleware supports SignatureCache, can directly allow on hit, significantly reduces verification overhead for duplicate requests
Nonce Deduplication
- Uses NonceStore to record used nonces, avoids replay attacks while reducing repeated computation
Memory Cleanup
- Memory implementations of NonceStore and SignatureCache both have built-in periodic cleanup goroutine, avoids infinite growth
Time Window
- Default time window is 5 minutes, can be adjusted according to business, balances security and availability
Recommendations
- Enable signature cache and nonce storage in high concurrency scenarios
- For cross-node deployment, recommend replacing with distributed cache and storage implementation
- Control middleware order, try to place expensive verifications early in the chain, fail early
Troubleshooting Guide
JWT Common Issues
- Missing Authorization header or format error: Returns 401
- Token malformed, expired or signature invalid: Returns 401 and includes specific error type
- Unable to extract user information: Returns 401
- Test reference: jwt_test.go covers multiple boundary scenarios
Casbin Common Issues
- No username in context: Returns 401
- Policy matching failed: Returns 403
- Policy engine exception: Returns 500
RSA Common Issues
- Missing request headers: Returns 401
- Timestamp expired or invalid: Returns 401
- Duplicate request (same nonce): Returns 401
- Signature invalid: Returns 401
- Public key does not exist: Returns 401
- Request body read failed: Returns 400
- Test reference: rsa_perm_test.go covers normal, missing headers, invalid client, invalid signature, expired timestamp, replay attack and other scenarios
Conclusion
This middleware system achieves complete security chain from client signature verification, user identity authentication to RBAC permission control through clear chain invocation and responsibility separation. JWT middleware is responsible for identity injection, Casbin middleware provides fine-grained access control, RSA middleware ensures external client security and anti-replay capability. Through pluggable interfaces and memory implementation, the system has good extensibility and performance. Recommend combining with distributed cache and storage in production environment to further improve scalability and consistency.
Appendix
Middleware Configuration and Best Practices
JWT
- Secret Key Management: Use secure key rotation strategy, avoid hardcoding
- Token Lifecycle: Reasonably set issue, valid and expiration time
Casbin
- Policy Model and Policy File: Ensure model_path and policy_path are correct
- Username Source: Ensure JWT middleware has injected username in context
RSA
- Request Header Convention: Unified X-Client-ID, X-Client-Signature, X-Nonce, X-Timestamp
- Time Window: Adjust according to business delay, default 5 minutes
- Public Key Management: Use PublicKeyProvider implementation for dynamic update
- Cache and Deduplication: Enable SignatureCache and NonceStore
Custom Middleware Development Guide
Design Principles
- Single Responsibility: Each middleware does only one thing
- Clear Error Semantics: Return 4xx/5xx and include clear error information
- Fail Early: Complete expensive or failure-prone checks early in the chain
Development Steps
- Define Input/Output: Request headers, context keys, error types
- Implement Verification Logic: Parse, validate, inject context
- Register and Combine: Register through Authorization or route middleware
Testing Strategy
- Unit Testing: Cover normal, abnormal, boundary scenarios
- Integration Testing: Simulate chain combination, verify order and interaction
- Performance Testing: Stress test signature cache and nonce storage throughput
Debugging Techniques
- Use Gin's Debug mode and logging
- Print context information at key nodes
- Use testing tools (httptest) to construct minimal use cases