feat(auth): Add authentication middleware
This commit is contained in:
@@ -36,6 +36,14 @@ routes:
|
||||
strip_prefix:
|
||||
enabled: true
|
||||
prefix: "/api/v1"
|
||||
security:
|
||||
auth:
|
||||
enabled: true
|
||||
type: "api_key"
|
||||
header: "X-Api-Key"
|
||||
path:
|
||||
include: []
|
||||
exclude: []
|
||||
```
|
||||
|
||||
## Sections
|
||||
@@ -93,7 +101,7 @@ Links hosts to backend targets.
|
||||
|
||||
### Routes
|
||||
|
||||
Route definitions with path patterns and prefix stripping.
|
||||
Route definitions with path patterns, prefix stripping, and authentication.
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
@@ -101,6 +109,7 @@ Route definitions with path patterns and prefix stripping.
|
||||
| `api` | string | API ID to use for this route |
|
||||
| `path` | string | Chi route pattern (e.g., `/api/v1/*`) |
|
||||
| `strip_prefix` | object | Prefix stripping configuration |
|
||||
| `security` | object | Security policies (auth) |
|
||||
|
||||
#### Strip Prefix
|
||||
|
||||
@@ -109,60 +118,123 @@ Route definitions with path patterns and prefix stripping.
|
||||
| `enabled` | boolean | Enable prefix stripping |
|
||||
| `prefix` | string | Prefix to remove from path |
|
||||
|
||||
#### Security
|
||||
|
||||
##### Authentication
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `enabled` | boolean | Enable authentication |
|
||||
| `type` | string | Auth type identifier (for documentation) |
|
||||
| `header` | string | Header name to validate (e.g., `X-Api-Key`, `Authorization`) |
|
||||
| `path` | object | Path-based filtering configuration |
|
||||
|
||||
##### Auth Path Filtering
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `include` | array | Paths that require auth (empty = all, if set only these) |
|
||||
| `exclude` | array | Paths that skip auth (only used if include is empty) |
|
||||
|
||||
**Path Filtering Logic:**
|
||||
|
||||
| Include | Exclude | Behavior |
|
||||
|---------|---------|----------|
|
||||
| Empty | Empty | Auth required for ALL paths |
|
||||
| Set | Empty | Auth required ONLY for paths matching include |
|
||||
| Empty | Set | Auth required for ALL EXCEPT paths matching exclude |
|
||||
| Set | Set | Include takes precedence (same as "Set, Empty") |
|
||||
|
||||
**Wildcards in Path Patterns:**
|
||||
- `*` matches any path
|
||||
- `/api/*` matches `/api/` and any subpath
|
||||
- `/api/v1/public/test/*` matches the prefix and any subpath
|
||||
|
||||
## Example Configurations
|
||||
|
||||
### Simple Proxy (No Prefix Stripping)
|
||||
### Public API (No Auth)
|
||||
|
||||
```yaml
|
||||
gateway:
|
||||
host: "0.0.0.0"
|
||||
port: 8080
|
||||
features:
|
||||
- logger
|
||||
|
||||
hosts:
|
||||
- id: "host-001"
|
||||
name: "localhost"
|
||||
domain: "localhost:8080"
|
||||
|
||||
targets:
|
||||
- id: "target-001"
|
||||
name: "backend"
|
||||
url: "https://api.example.com"
|
||||
|
||||
apis:
|
||||
- id: "api-001"
|
||||
host: "host-001"
|
||||
target: "target-001"
|
||||
|
||||
routes:
|
||||
- id: "route-001"
|
||||
- id: "public-api"
|
||||
api: "api-001"
|
||||
path: "/api/*"
|
||||
path: "/public/*"
|
||||
strip_prefix:
|
||||
enabled: true
|
||||
prefix: "/public"
|
||||
security:
|
||||
auth:
|
||||
enabled: false
|
||||
```
|
||||
|
||||
**Request flow:**
|
||||
- Client requests: `/api/users/123`
|
||||
- Backend receives: `/api/users/123`
|
||||
|
||||
### Prefix Stripping
|
||||
### Protected API (All Paths Require Auth)
|
||||
|
||||
```yaml
|
||||
routes:
|
||||
- id: "route-001"
|
||||
- id: "protected-api"
|
||||
api: "api-001"
|
||||
path: "/api/v1/*"
|
||||
strip_prefix:
|
||||
enabled: true
|
||||
prefix: "/api/v1"
|
||||
security:
|
||||
auth:
|
||||
enabled: true
|
||||
header: "X-Api-Key"
|
||||
path:
|
||||
include: []
|
||||
exclude: []
|
||||
```
|
||||
|
||||
**Request flow:**
|
||||
- Client requests: `/api/v1/users/123`
|
||||
- Gateway strips: `/api/v1`
|
||||
- Backend receives: `/users/123`
|
||||
### Public with Protected Sub-paths (Include)
|
||||
|
||||
### Multiple Routes
|
||||
```yaml
|
||||
routes:
|
||||
- id: "mixed-api"
|
||||
api: "api-001"
|
||||
path: "/api/*"
|
||||
strip_prefix:
|
||||
enabled: true
|
||||
prefix: "/api"
|
||||
security:
|
||||
auth:
|
||||
enabled: true
|
||||
header: "X-Api-Key"
|
||||
path:
|
||||
include: ["/api/admin/*", "/api/users/*/profile"]
|
||||
exclude: []
|
||||
```
|
||||
|
||||
In this example:
|
||||
- `/api/admin/users` → Requires auth (matches include)
|
||||
- `/api/users/123/profile` → Requires auth (matches include)
|
||||
- `/api/public/data` → No auth (doesn't match include)
|
||||
- `/api/health` → No auth (doesn't match include)
|
||||
|
||||
### Protected with Public Sub-paths (Exclude)
|
||||
|
||||
```yaml
|
||||
routes:
|
||||
- id: "protected-with-public"
|
||||
api: "api-001"
|
||||
path: "/api/*"
|
||||
security:
|
||||
auth:
|
||||
enabled: true
|
||||
header: "Authorization"
|
||||
path:
|
||||
include: []
|
||||
exclude: ["/api/health", "/api/public/*", "/api/v1/public/test/*"]
|
||||
```
|
||||
|
||||
In this example:
|
||||
- `/api/health` → No auth (matches exclude)
|
||||
- `/api/public/data` → No auth (matches exclude)
|
||||
- `/api/v1/public/test/123` → No auth (matches exclude)
|
||||
- `/api/users` → Requires auth (doesn't match exclude)
|
||||
- `/api/admin/settings` → Requires auth (doesn't match exclude)
|
||||
|
||||
### Multiple Routes with Different Auth
|
||||
|
||||
```yaml
|
||||
routes:
|
||||
@@ -172,49 +244,37 @@ routes:
|
||||
strip_prefix:
|
||||
enabled: true
|
||||
prefix: "/public"
|
||||
security:
|
||||
auth:
|
||||
enabled: false
|
||||
|
||||
- id: "api-route"
|
||||
- id: "user-route"
|
||||
api: "api-001"
|
||||
path: "/api/v1/*"
|
||||
path: "/users/*"
|
||||
strip_prefix:
|
||||
enabled: true
|
||||
prefix: "/api/v1"
|
||||
```
|
||||
prefix: "/users"
|
||||
security:
|
||||
auth:
|
||||
enabled: true
|
||||
header: "X-Api-Key"
|
||||
path:
|
||||
include: []
|
||||
exclude: ["/users/login", "/users/register"]
|
||||
|
||||
### Multiple Backends
|
||||
|
||||
```yaml
|
||||
hosts:
|
||||
- id: "host-001"
|
||||
name: "api-host"
|
||||
domain: "api.example.com"
|
||||
- id: "host-002"
|
||||
name: "admin-host"
|
||||
domain: "admin.example.com"
|
||||
|
||||
targets:
|
||||
- id: "target-001"
|
||||
name: "api-backend"
|
||||
url: "https://api-backend.internal"
|
||||
- id: "target-002"
|
||||
name: "admin-backend"
|
||||
url: "https://admin-backend.internal"
|
||||
|
||||
apis:
|
||||
- id: "api-001"
|
||||
host: "host-001"
|
||||
target: "target-001"
|
||||
- id: "api-002"
|
||||
host: "host-002"
|
||||
target: "target-002"
|
||||
|
||||
routes:
|
||||
- id: "route-001"
|
||||
- id: "admin-route"
|
||||
api: "api-001"
|
||||
path: "/api/*"
|
||||
- id: "route-002"
|
||||
api: "api-002"
|
||||
path: "/admin/*"
|
||||
strip_prefix:
|
||||
enabled: true
|
||||
prefix: "/admin"
|
||||
security:
|
||||
auth:
|
||||
enabled: true
|
||||
header: "Authorization"
|
||||
path:
|
||||
include: []
|
||||
exclude: []
|
||||
```
|
||||
|
||||
## Configuration Loading
|
||||
@@ -244,3 +304,23 @@ The gateway uses chi/v5 routing patterns. Common patterns:
|
||||
| `/files/*` | `/files/` and any subpath | `/files/doc.pdf` |
|
||||
|
||||
Note: `/*` matches zero or more path segments.
|
||||
|
||||
## Debug Logging
|
||||
|
||||
To see detailed authentication decisions, enable DEBUG logging in `main.go`:
|
||||
|
||||
```go
|
||||
masterlog.SetLevel(masterlog.LevelDebug)
|
||||
```
|
||||
|
||||
This will output logs like:
|
||||
```json
|
||||
{
|
||||
"level": "debug",
|
||||
"msg": "AuthMiddleware: Checking if path requires auth",
|
||||
"path": "/api/v1/users",
|
||||
"requires_auth": true,
|
||||
"include": [],
|
||||
"exclude": ["/api/v1/public/*"]
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user