feat(auth): Add authentication middleware
This commit is contained in:
@@ -25,10 +25,10 @@ The SecNex API Gateway follows a modular architecture with clear separation of c
|
|||||||
│ Route Handler │
|
│ Route Handler │
|
||||||
│ ┌──────────────────────────────────────────────────────┐ │
|
│ ┌──────────────────────────────────────────────────────┐ │
|
||||||
│ │ Per-Route Middleware Chain │ │
|
│ │ Per-Route Middleware Chain │ │
|
||||||
│ │ ┌────────────┐ ┌──────────────┐ │ │
|
│ │ ┌────────────┐ ┌────────────┐ ┌──────────────┐ │ │
|
||||||
│ │ │ Strip │→ │ Reverse │ │ │
|
│ │ │ Auth │→ │ Strip │→ │ Reverse │ │ │
|
||||||
│ │ │ Prefix │ │ Proxy │ │ │
|
│ │ │ Middleware │ │ Prefix │ │ Proxy │ │ │
|
||||||
│ │ └────────────┘ └──────────────┘ │ │
|
│ │ └────────────┘ └────────────┘ └──────────────┘ │ │
|
||||||
│ └──────────────────────────────────────────────────────┘ │
|
│ └──────────────────────────────────────────────────────┘ │
|
||||||
└─────────────────────────┬──────────────────────────────────┘
|
└─────────────────────────┬──────────────────────────────────┘
|
||||||
│
|
│
|
||||||
@@ -54,11 +54,12 @@ app/
|
|||||||
│ └── database.go # Database configuration
|
│ └── database.go # Database configuration
|
||||||
├── server/ # Core server components
|
├── server/ # Core server components
|
||||||
│ ├── gateway.go # Main gateway server
|
│ ├── gateway.go # Main gateway server
|
||||||
│ ├── routes.go # Route registration
|
│ ├── routes.go # Route registration & middleware chain
|
||||||
│ ├── api.go # API definitions
|
│ ├── api.go # API definitions
|
||||||
│ ├── host.go # Host definitions
|
│ ├── host.go # Host definitions
|
||||||
│ └── target.go # Target (backend) definitions
|
│ └── target.go # Target (backend) definitions
|
||||||
├── middlewares/ # HTTP middleware
|
├── middlewares/ # HTTP middleware
|
||||||
|
│ ├── auth.go # Authentication middleware
|
||||||
│ ├── host.go # Host logging middleware
|
│ ├── host.go # Host logging middleware
|
||||||
│ └── logger.go # Structured logging middleware
|
│ └── logger.go # Structured logging middleware
|
||||||
└── utils/ # Utility functions
|
└── utils/ # Utility functions
|
||||||
@@ -79,7 +80,7 @@ The Gateway is the main server component that:
|
|||||||
|
|
||||||
The Routes component handles:
|
The Routes component handles:
|
||||||
- Creating route handlers from configuration
|
- Creating route handlers from configuration
|
||||||
- Applying strip prefix middleware
|
- Applying per-route middleware chain (Auth → StripPrefix)
|
||||||
- Registering routes with chi router (method-agnostic)
|
- Registering routes with chi router (method-agnostic)
|
||||||
- Connecting routes to API backends
|
- Connecting routes to API backends
|
||||||
|
|
||||||
@@ -101,9 +102,17 @@ Host definitions for:
|
|||||||
|
|
||||||
Target (backend) definitions that:
|
Target (backend) definitions that:
|
||||||
- Store backend service URLs
|
- Store backend service URLs
|
||||||
- Create `httputil.ReverseProxy` instances
|
- Create `httputil.NewSingleHostReverseProxy` instances
|
||||||
- Handle proxy configuration
|
- Handle proxy configuration
|
||||||
|
|
||||||
|
#### Auth Middleware (`middlewares/auth.go`)
|
||||||
|
|
||||||
|
Authentication middleware that:
|
||||||
|
- Validates presence of configured auth header (e.g., `X-Api-Key`, `Authorization`)
|
||||||
|
- Supports path-based filtering via include/exclude patterns
|
||||||
|
- Removes auth header before forwarding to backend
|
||||||
|
- Provides extensive DEBUG logging for troubleshooting
|
||||||
|
|
||||||
## Middleware Chain
|
## Middleware Chain
|
||||||
|
|
||||||
### Global Middleware
|
### Global Middleware
|
||||||
@@ -119,19 +128,71 @@ Applied to all requests via chi middleware:
|
|||||||
|
|
||||||
### Per-Route Middleware
|
### Per-Route Middleware
|
||||||
|
|
||||||
Applied to each route handler:
|
Applied in order to each route handler:
|
||||||
|
|
||||||
1. **StripPrefix** - Removes specified prefix from request path before proxying
|
1. **Auth** (if enabled) - Validates authentication header with path filtering
|
||||||
|
2. **StripPrefix** (if enabled) - Removes specified prefix from request path before proxying
|
||||||
|
|
||||||
## Request Flow
|
## Request Flow
|
||||||
|
|
||||||
1. **Client Request** → Gateway receives HTTP request
|
1. **Client Request** → Gateway receives HTTP request
|
||||||
2. **Global Middleware** → Request ID, Real IP, Host logging, Logger applied
|
2. **Global Middleware** → Request ID, Real IP, Host logging, Logger applied
|
||||||
3. **Route Matching** → Chi matches route pattern (e.g., `/api/v1/*`)
|
3. **Route Matching** → Chi matches route pattern (e.g., `/api/v1/*`)
|
||||||
4. **Per-Route Middleware** → StripPrefix (if enabled)
|
4. **Per-Route Middleware** → Auth → StripPrefix (if enabled)
|
||||||
5. **Reverse Proxy** → Request forwarded to backend API
|
5. **Reverse Proxy** → Request forwarded to backend API
|
||||||
6. **Response** → Backend response returned to client
|
6. **Response** → Backend response returned to client
|
||||||
|
|
||||||
|
## Authentication Flow
|
||||||
|
|
||||||
|
The authentication middleware supports flexible path-based filtering:
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────┐
|
||||||
|
│ Include and Exclude both empty? │
|
||||||
|
└──────────────────┬──────────────────┘
|
||||||
|
│ Yes
|
||||||
|
┌─────────┴─────────┐
|
||||||
|
│ Auth required │
|
||||||
|
│ for ALL paths │
|
||||||
|
└───────────────────┘
|
||||||
|
|
||||||
|
│ No
|
||||||
|
┌─────────┴─────────┐
|
||||||
|
▼ │
|
||||||
|
┌───────────────────┐ │
|
||||||
|
│ Only Include set? │ │
|
||||||
|
└─────────┬─────────┘ │
|
||||||
|
│ Yes │ No │
|
||||||
|
▼ ▼ │
|
||||||
|
┌────────┐ ┌────────────────┐│
|
||||||
|
│ Auth │ │ Exclude set? ││
|
||||||
|
│ ONLY │ └───────┬────────┘│
|
||||||
|
│ for │ │ No │
|
||||||
|
│ Include│ ┌────┴────┐ │
|
||||||
|
│ paths │ │ Auth │ │
|
||||||
|
└────────┘ │ for ALL │ │
|
||||||
|
└────┬────┘ │
|
||||||
|
│ Yes │
|
||||||
|
┌─────────┴─────────┐│
|
||||||
|
│ Auth EXCEPT ││
|
||||||
|
│ matching Exclude ││
|
||||||
|
└───────────────────┘│
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Check Auth Header
|
||||||
|
```
|
||||||
|
|
||||||
|
**Path Filtering Logic:**
|
||||||
|
1. **Both include and exclude empty** → Auth required for ALL paths
|
||||||
|
2. **Only include set** → Auth required ONLY for paths matching include patterns
|
||||||
|
3. **Only exclude set** → Auth required for ALL paths EXCEPT those matching exclude patterns
|
||||||
|
4. **Both set** → Include takes precedence (same as #2)
|
||||||
|
|
||||||
|
**Wildcard Pattern Matching:**
|
||||||
|
- `*` matches any path
|
||||||
|
- `/api/*` matches `/api/` and any subpath
|
||||||
|
- `/api/v1/public/test/*` matches the prefix and any subpath
|
||||||
|
|
||||||
## Configuration Flow
|
## Configuration Flow
|
||||||
|
|
||||||
1. Load `gateway.yaml` via `config.NewFile()`
|
1. Load `gateway.yaml` via `config.NewFile()`
|
||||||
@@ -139,10 +200,10 @@ Applied to each route handler:
|
|||||||
3. Create Hosts from configuration
|
3. Create Hosts from configuration
|
||||||
4. Create Targets from configuration
|
4. Create Targets from configuration
|
||||||
5. Create APIs (linking Hosts to Targets)
|
5. Create APIs (linking Hosts to Targets)
|
||||||
6. Create Routes (linking Routes to APIs)
|
6. Create Routes (linking Routes to APIs with Auth config)
|
||||||
7. Initialize Gateway with all components
|
7. Initialize Gateway with all components
|
||||||
8. Configure proxy directors
|
8. Configure proxy directors
|
||||||
9. Register routes with chi router
|
9. Register routes with chi router (including Auth middleware)
|
||||||
10. Start HTTP server
|
10. Start HTTP server
|
||||||
|
|
||||||
## Logging
|
## Logging
|
||||||
@@ -151,6 +212,7 @@ The gateway uses structured JSON logging via `masterlog`:
|
|||||||
|
|
||||||
- **HTTP Request Logging** - method, path, status, duration, host, IP
|
- **HTTP Request Logging** - method, path, status, duration, host, IP
|
||||||
- **Gateway Events** - startup, route registration, proxy configuration
|
- **Gateway Events** - startup, route registration, proxy configuration
|
||||||
|
- **Auth Debug Logs** - detailed auth decision logging when DEBUG level enabled
|
||||||
- **Sensitive Field Pseudonymization** - user_id, email, ip fields are pseudonymized
|
- **Sensitive Field Pseudonymization** - user_id, email, ip fields are pseudonymized
|
||||||
|
|
||||||
Example log output:
|
Example log output:
|
||||||
@@ -166,3 +228,15 @@ Example log output:
|
|||||||
"ip": "127.0.0.1:52342"
|
"ip": "127.0.0.1:52342"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Auth debug logs (when DEBUG level enabled):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"level": "debug",
|
||||||
|
"msg": "AuthMiddleware: Checking if path requires auth",
|
||||||
|
"path": "/api/v1/users",
|
||||||
|
"requires_auth": true,
|
||||||
|
"include": [],
|
||||||
|
"exclude": ["/api/v1/public/*"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -36,6 +36,14 @@ routes:
|
|||||||
strip_prefix:
|
strip_prefix:
|
||||||
enabled: true
|
enabled: true
|
||||||
prefix: "/api/v1"
|
prefix: "/api/v1"
|
||||||
|
security:
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
type: "api_key"
|
||||||
|
header: "X-Api-Key"
|
||||||
|
path:
|
||||||
|
include: []
|
||||||
|
exclude: []
|
||||||
```
|
```
|
||||||
|
|
||||||
## Sections
|
## Sections
|
||||||
@@ -93,7 +101,7 @@ Links hosts to backend targets.
|
|||||||
|
|
||||||
### Routes
|
### Routes
|
||||||
|
|
||||||
Route definitions with path patterns and prefix stripping.
|
Route definitions with path patterns, prefix stripping, and authentication.
|
||||||
|
|
||||||
| Field | Type | Description |
|
| Field | Type | Description |
|
||||||
|-------|------|-------------|
|
|-------|------|-------------|
|
||||||
@@ -101,6 +109,7 @@ Route definitions with path patterns and prefix stripping.
|
|||||||
| `api` | string | API ID to use for this route |
|
| `api` | string | API ID to use for this route |
|
||||||
| `path` | string | Chi route pattern (e.g., `/api/v1/*`) |
|
| `path` | string | Chi route pattern (e.g., `/api/v1/*`) |
|
||||||
| `strip_prefix` | object | Prefix stripping configuration |
|
| `strip_prefix` | object | Prefix stripping configuration |
|
||||||
|
| `security` | object | Security policies (auth) |
|
||||||
|
|
||||||
#### Strip Prefix
|
#### Strip Prefix
|
||||||
|
|
||||||
@@ -109,60 +118,123 @@ Route definitions with path patterns and prefix stripping.
|
|||||||
| `enabled` | boolean | Enable prefix stripping |
|
| `enabled` | boolean | Enable prefix stripping |
|
||||||
| `prefix` | string | Prefix to remove from path |
|
| `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
|
## Example Configurations
|
||||||
|
|
||||||
### Simple Proxy (No Prefix Stripping)
|
### Public API (No Auth)
|
||||||
|
|
||||||
```yaml
|
```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:
|
routes:
|
||||||
- id: "route-001"
|
- id: "public-api"
|
||||||
api: "api-001"
|
api: "api-001"
|
||||||
path: "/api/*"
|
path: "/public/*"
|
||||||
|
strip_prefix:
|
||||||
|
enabled: true
|
||||||
|
prefix: "/public"
|
||||||
|
security:
|
||||||
|
auth:
|
||||||
|
enabled: false
|
||||||
```
|
```
|
||||||
|
|
||||||
**Request flow:**
|
### Protected API (All Paths Require Auth)
|
||||||
- Client requests: `/api/users/123`
|
|
||||||
- Backend receives: `/api/users/123`
|
|
||||||
|
|
||||||
### Prefix Stripping
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
routes:
|
routes:
|
||||||
- id: "route-001"
|
- id: "protected-api"
|
||||||
api: "api-001"
|
api: "api-001"
|
||||||
path: "/api/v1/*"
|
path: "/api/v1/*"
|
||||||
strip_prefix:
|
strip_prefix:
|
||||||
enabled: true
|
enabled: true
|
||||||
prefix: "/api/v1"
|
prefix: "/api/v1"
|
||||||
|
security:
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
header: "X-Api-Key"
|
||||||
|
path:
|
||||||
|
include: []
|
||||||
|
exclude: []
|
||||||
```
|
```
|
||||||
|
|
||||||
**Request flow:**
|
### Public with Protected Sub-paths (Include)
|
||||||
- Client requests: `/api/v1/users/123`
|
|
||||||
- Gateway strips: `/api/v1`
|
|
||||||
- Backend receives: `/users/123`
|
|
||||||
|
|
||||||
### 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
|
```yaml
|
||||||
routes:
|
routes:
|
||||||
@@ -172,49 +244,37 @@ routes:
|
|||||||
strip_prefix:
|
strip_prefix:
|
||||||
enabled: true
|
enabled: true
|
||||||
prefix: "/public"
|
prefix: "/public"
|
||||||
|
security:
|
||||||
|
auth:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
- id: "api-route"
|
- id: "user-route"
|
||||||
api: "api-001"
|
api: "api-001"
|
||||||
path: "/api/v1/*"
|
path: "/users/*"
|
||||||
strip_prefix:
|
strip_prefix:
|
||||||
enabled: true
|
enabled: true
|
||||||
prefix: "/api/v1"
|
prefix: "/users"
|
||||||
```
|
security:
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
header: "X-Api-Key"
|
||||||
|
path:
|
||||||
|
include: []
|
||||||
|
exclude: ["/users/login", "/users/register"]
|
||||||
|
|
||||||
### Multiple Backends
|
- id: "admin-route"
|
||||||
|
|
||||||
```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"
|
|
||||||
api: "api-001"
|
api: "api-001"
|
||||||
path: "/api/*"
|
|
||||||
- id: "route-002"
|
|
||||||
api: "api-002"
|
|
||||||
path: "/admin/*"
|
path: "/admin/*"
|
||||||
|
strip_prefix:
|
||||||
|
enabled: true
|
||||||
|
prefix: "/admin"
|
||||||
|
security:
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
header: "Authorization"
|
||||||
|
path:
|
||||||
|
include: []
|
||||||
|
exclude: []
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration Loading
|
## Configuration Loading
|
||||||
@@ -244,3 +304,23 @@ The gateway uses chi/v5 routing patterns. Common patterns:
|
|||||||
| `/files/*` | `/files/` and any subpath | `/files/doc.pdf` |
|
| `/files/*` | `/files/` and any subpath | `/files/doc.pdf` |
|
||||||
|
|
||||||
Note: `/*` matches zero or more path segments.
|
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/*"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
240
.docs/usage.md
240
.docs/usage.md
@@ -56,6 +56,109 @@ curl -X PUT http://localhost:8080/api/v1/data/123
|
|||||||
curl -X DELETE http://localhost:8080/api/v1/data/123
|
curl -X DELETE http://localhost:8080/api/v1/data/123
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
### Using API Key Authentication
|
||||||
|
|
||||||
|
**Configuration:**
|
||||||
|
```yaml
|
||||||
|
security:
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
header: "X-Api-Key"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Valid request:**
|
||||||
|
```bash
|
||||||
|
curl -H "X-Api-Key: your-secret-key" http://localhost:8080/api/v1/data
|
||||||
|
```
|
||||||
|
|
||||||
|
**Invalid request (missing header):**
|
||||||
|
```bash
|
||||||
|
curl http://localhost:8080/api/v1/data
|
||||||
|
# Returns: 401 Unauthorized
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using Bearer Token Authentication
|
||||||
|
|
||||||
|
**Configuration:**
|
||||||
|
```yaml
|
||||||
|
security:
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
header: "Authorization"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Valid request:**
|
||||||
|
```bash
|
||||||
|
curl -H "Authorization: Bearer your-token-here" http://localhost:8080/api/v1/data
|
||||||
|
```
|
||||||
|
|
||||||
|
### Path-Based Authentication Examples
|
||||||
|
|
||||||
|
#### All Paths Require Auth
|
||||||
|
|
||||||
|
**Configuration:**
|
||||||
|
```yaml
|
||||||
|
security:
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
header: "X-Api-Key"
|
||||||
|
path:
|
||||||
|
include: []
|
||||||
|
exclude: []
|
||||||
|
```
|
||||||
|
|
||||||
|
All requests to this route require authentication.
|
||||||
|
|
||||||
|
#### Only Specific Paths Require Auth (Include)
|
||||||
|
|
||||||
|
**Configuration:**
|
||||||
|
```yaml
|
||||||
|
security:
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
header: "X-Api-Key"
|
||||||
|
path:
|
||||||
|
include: ["/api/admin/*", "/api/users/*/profile"]
|
||||||
|
exclude: []
|
||||||
|
```
|
||||||
|
|
||||||
|
**Request examples:**
|
||||||
|
```bash
|
||||||
|
# Requires auth (matches include)
|
||||||
|
curl -H "X-Api-Key: key" http://localhost:8080/api/admin/users
|
||||||
|
curl -H "X-Api-Key: key" http://localhost:8080/api/users/123/profile
|
||||||
|
|
||||||
|
# No auth required (doesn't match include)
|
||||||
|
curl http://localhost:8080/api/public/data
|
||||||
|
curl http://localhost:8080/api/health
|
||||||
|
```
|
||||||
|
|
||||||
|
#### All Paths Except Specific Ones Require Auth (Exclude)
|
||||||
|
|
||||||
|
**Configuration:**
|
||||||
|
```yaml
|
||||||
|
security:
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
header: "X-Api-Key"
|
||||||
|
path:
|
||||||
|
include: []
|
||||||
|
exclude: ["/api/health", "/api/public/*"]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Request examples:**
|
||||||
|
```bash
|
||||||
|
# No auth required (matches exclude)
|
||||||
|
curl http://localhost:8080/api/health
|
||||||
|
curl http://localhost:8080/api/public/data
|
||||||
|
|
||||||
|
# Requires auth (doesn't match exclude)
|
||||||
|
curl -H "X-Api-Key: key" http://localhost:8080/api/users
|
||||||
|
curl -H "X-Api-Key: key" http://localhost:8080/api/admin/settings
|
||||||
|
```
|
||||||
|
|
||||||
## Route Examples
|
## Route Examples
|
||||||
|
|
||||||
### Strip Prefix Example
|
### Strip Prefix Example
|
||||||
@@ -87,6 +190,9 @@ routes:
|
|||||||
strip_prefix:
|
strip_prefix:
|
||||||
enabled: true
|
enabled: true
|
||||||
prefix: "/public"
|
prefix: "/public"
|
||||||
|
security:
|
||||||
|
auth:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
- id: "api-route"
|
- id: "api-route"
|
||||||
api: "api-001"
|
api: "api-001"
|
||||||
@@ -94,15 +200,19 @@ routes:
|
|||||||
strip_prefix:
|
strip_prefix:
|
||||||
enabled: true
|
enabled: true
|
||||||
prefix: "/api/v1"
|
prefix: "/api/v1"
|
||||||
|
security:
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
header: "X-Api-Key"
|
||||||
```
|
```
|
||||||
|
|
||||||
**Requests:**
|
**Requests:**
|
||||||
```bash
|
```bash
|
||||||
# Public route - backend receives /status
|
# Public route - no auth, backend receives /status
|
||||||
curl http://localhost:8080/public/status
|
curl http://localhost:8080/public/status
|
||||||
|
|
||||||
# API route - backend receives /users
|
# API route - requires auth, backend receives /users
|
||||||
curl http://localhost:8080/api/v1/users
|
curl -H "X-Api-Key: key" http://localhost:8080/api/v1/users
|
||||||
```
|
```
|
||||||
|
|
||||||
## Logging
|
## Logging
|
||||||
@@ -130,6 +240,27 @@ The gateway uses structured JSON logging via `masterlog`. All HTTP requests are
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Debug Logging
|
||||||
|
|
||||||
|
To enable detailed authentication logging, set DEBUG level in `main.go`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
masterlog.SetLevel(masterlog.LevelDebug)
|
||||||
|
```
|
||||||
|
|
||||||
|
This will output detailed auth decision logs:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"level": "debug",
|
||||||
|
"msg": "AuthMiddleware: Checking if path requires auth",
|
||||||
|
"path": "/api/v1/users",
|
||||||
|
"requires_auth": true,
|
||||||
|
"include": [],
|
||||||
|
"exclude": ["/api/v1/public/*"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
### Gateway fails to start
|
### Gateway fails to start
|
||||||
@@ -146,6 +277,13 @@ cat ../gateway.yaml
|
|||||||
|
|
||||||
3. Check logs for detailed error messages
|
3. Check logs for detailed error messages
|
||||||
|
|
||||||
|
### 401 Unauthorized
|
||||||
|
|
||||||
|
- Verify auth header is included
|
||||||
|
- Check header name matches configuration (case-sensitive)
|
||||||
|
- Verify path is not excluded from auth (check exclude patterns)
|
||||||
|
- Enable DEBUG logging to see auth decision process
|
||||||
|
|
||||||
### 404 Not Found
|
### 404 Not Found
|
||||||
|
|
||||||
- Verify the route path matches your request
|
- Verify the route path matches your request
|
||||||
@@ -165,6 +303,22 @@ cat ../gateway.yaml
|
|||||||
- Remember that `/*` matches zero or more path segments
|
- Remember that `/*` matches zero or more path segments
|
||||||
- Check that multiple routes don't have conflicting patterns
|
- Check that multiple routes don't have conflicting patterns
|
||||||
|
|
||||||
|
### Auth not working as expected
|
||||||
|
|
||||||
|
1. Enable DEBUG logging to see auth decisions:
|
||||||
|
```go
|
||||||
|
masterlog.SetLevel(masterlog.LevelDebug)
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Check the logs for:
|
||||||
|
- Whether the path requires auth
|
||||||
|
- Whether the auth header is present
|
||||||
|
- Which patterns are being matched
|
||||||
|
|
||||||
|
3. Verify your include/exclude patterns:
|
||||||
|
- Wildcards end with `*`
|
||||||
|
- Patterns are prefix-based (e.g., `/api/v1/public/test/*`)
|
||||||
|
|
||||||
## Performance Considerations
|
## Performance Considerations
|
||||||
|
|
||||||
- The gateway uses Go's `httputil.ReverseProxy` for efficient proxying
|
- The gateway uses Go's `httputil.ReverseProxy` for efficient proxying
|
||||||
@@ -175,23 +329,57 @@ cat ../gateway.yaml
|
|||||||
|
|
||||||
## Common Patterns
|
## Common Patterns
|
||||||
|
|
||||||
### API Versioning
|
### API Versioning with Auth
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
routes:
|
routes:
|
||||||
- id: "v1-api"
|
- id: "v1-public-api"
|
||||||
|
api: "api-001"
|
||||||
|
path: "/api/v1/public/*"
|
||||||
|
strip_prefix:
|
||||||
|
enabled: true
|
||||||
|
prefix: "/api/v1/public"
|
||||||
|
security:
|
||||||
|
auth:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
- id: "v1-protected-api"
|
||||||
api: "api-001"
|
api: "api-001"
|
||||||
path: "/api/v1/*"
|
path: "/api/v1/*"
|
||||||
strip_prefix:
|
strip_prefix:
|
||||||
enabled: true
|
enabled: true
|
||||||
prefix: "/api/v1"
|
prefix: "/api/v1"
|
||||||
|
security:
|
||||||
- id: "v2-api"
|
auth:
|
||||||
api: "api-001"
|
|
||||||
path: "/api/v2/*"
|
|
||||||
strip_prefix:
|
|
||||||
enabled: true
|
enabled: true
|
||||||
prefix: "/api/v2"
|
header: "X-Api-Key"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mixed Authentication
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
routes:
|
||||||
|
- id: "user-api"
|
||||||
|
api: "api-001"
|
||||||
|
path: "/users/*"
|
||||||
|
security:
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
header: "X-Api-Key"
|
||||||
|
path:
|
||||||
|
include: []
|
||||||
|
exclude: ["/users/login", "/users/register"]
|
||||||
|
|
||||||
|
- id: "admin-api"
|
||||||
|
api: "api-001"
|
||||||
|
path: "/admin/*"
|
||||||
|
security:
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
header: "Authorization"
|
||||||
|
path:
|
||||||
|
include: []
|
||||||
|
exclude: []
|
||||||
```
|
```
|
||||||
|
|
||||||
### Microservices Routing
|
### Microservices Routing
|
||||||
@@ -220,6 +408,10 @@ routes:
|
|||||||
strip_prefix:
|
strip_prefix:
|
||||||
enabled: true
|
enabled: true
|
||||||
prefix: "/users"
|
prefix: "/users"
|
||||||
|
security:
|
||||||
|
auth:
|
||||||
|
enabled: true
|
||||||
|
header: "X-Api-Key"
|
||||||
|
|
||||||
- id: "orders-route"
|
- id: "orders-route"
|
||||||
api: "order-api"
|
api: "order-api"
|
||||||
@@ -227,28 +419,8 @@ routes:
|
|||||||
strip_prefix:
|
strip_prefix:
|
||||||
enabled: true
|
enabled: true
|
||||||
prefix: "/orders"
|
prefix: "/orders"
|
||||||
```
|
security:
|
||||||
|
auth:
|
||||||
### External API Proxy
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
targets:
|
|
||||||
- id: "external-api"
|
|
||||||
name: "External API"
|
|
||||||
url: "https://api.external.com"
|
|
||||||
|
|
||||||
apis:
|
|
||||||
- id: "external"
|
|
||||||
host: "host-001"
|
|
||||||
target: "external-api"
|
|
||||||
|
|
||||||
routes:
|
|
||||||
- id: "external-proxy"
|
|
||||||
api: "external"
|
|
||||||
path: "/proxy/external/*"
|
|
||||||
strip_prefix:
|
|
||||||
enabled: true
|
enabled: true
|
||||||
prefix: "/proxy/external"
|
header: "Authorization"
|
||||||
```
|
```
|
||||||
|
|
||||||
Request to `/proxy/external/users` becomes `/users` on the external API.
|
|
||||||
|
|||||||
198
app/middlewares/auth.go
Normal file
198
app/middlewares/auth.go
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
package middlewares
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.secnex.io/secnex/api-gateway/config"
|
||||||
|
"git.secnex.io/secnex/masterlog"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AuthMiddleware handles authentication based on header validation and path filtering
|
||||||
|
type AuthMiddleware struct {
|
||||||
|
header string
|
||||||
|
pathConfig config.AuthPath
|
||||||
|
handler http.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAuthMiddleware creates a new authentication middleware
|
||||||
|
func NewAuthMiddleware(header string, pathConfig config.AuthPath, handler http.Handler) http.Handler {
|
||||||
|
masterlog.Debug("Creating AuthMiddleware", map[string]interface{}{
|
||||||
|
"header": header,
|
||||||
|
"include_paths": pathConfig.Include,
|
||||||
|
"exclude_paths": pathConfig.Exclude,
|
||||||
|
})
|
||||||
|
|
||||||
|
return &AuthMiddleware{
|
||||||
|
header: header,
|
||||||
|
pathConfig: pathConfig,
|
||||||
|
handler: handler,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServeHTTP handles the authentication logic
|
||||||
|
func (m *AuthMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
requestPath := r.URL.Path
|
||||||
|
|
||||||
|
// Step 1: Determine if this path requires authentication
|
||||||
|
requiresAuth := m.requiresAuth(requestPath)
|
||||||
|
|
||||||
|
masterlog.Debug("AuthMiddleware: Checking if path requires auth", map[string]interface{}{
|
||||||
|
"path": requestPath,
|
||||||
|
"requires_auth": requiresAuth,
|
||||||
|
"include": m.pathConfig.Include,
|
||||||
|
"exclude": m.pathConfig.Exclude,
|
||||||
|
})
|
||||||
|
|
||||||
|
if !requiresAuth {
|
||||||
|
// No auth required, skip to next handler
|
||||||
|
masterlog.Debug("AuthMiddleware: Skipping auth for path", map[string]interface{}{
|
||||||
|
"path": requestPath,
|
||||||
|
"reason": "path_matches_exclude_or_not_include",
|
||||||
|
})
|
||||||
|
m.handler.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Check if auth header is present
|
||||||
|
authHeader := r.Header.Get(m.header)
|
||||||
|
|
||||||
|
masterlog.Debug("AuthMiddleware: Checking auth header", map[string]interface{}{
|
||||||
|
"path": requestPath,
|
||||||
|
"header_name": m.header,
|
||||||
|
"header_present": authHeader != "",
|
||||||
|
})
|
||||||
|
|
||||||
|
if authHeader == "" {
|
||||||
|
masterlog.Warn("AuthMiddleware: Missing auth header", map[string]interface{}{
|
||||||
|
"path": requestPath,
|
||||||
|
"header": m.header,
|
||||||
|
})
|
||||||
|
http.Error(w, "Unauthorized: Missing authentication header", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: Auth header present, remove it before forwarding
|
||||||
|
// (don't send the auth header to the backend)
|
||||||
|
r.Header.Del(m.header)
|
||||||
|
|
||||||
|
masterlog.Debug("AuthMiddleware: Authentication successful", map[string]interface{}{
|
||||||
|
"path": requestPath,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Step 4: Forward to next handler
|
||||||
|
m.handler.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// requiresAuth determines if a given path requires authentication
|
||||||
|
//
|
||||||
|
// Logic:
|
||||||
|
// 1. If BOTH include and exclude are empty → auth required for ALL paths
|
||||||
|
// 2. If ONLY include is set (non-empty) → auth required ONLY for paths matching include patterns
|
||||||
|
// 3. If ONLY exclude is set (non-empty) → auth required for ALL paths EXCEPT those matching exclude patterns
|
||||||
|
// 4. If BOTH are set → include takes precedence (auth required ONLY for paths matching include patterns)
|
||||||
|
//
|
||||||
|
// Wildcard patterns are supported:
|
||||||
|
// - "*" matches any path
|
||||||
|
// - "/api/*" matches "/api/" and any subpath like "/api/users", "/api/users/123"
|
||||||
|
// - "/api/v1/public/test/*" matches "/test", "/test/123", etc.
|
||||||
|
func (m *AuthMiddleware) requiresAuth(path string) bool {
|
||||||
|
include := m.pathConfig.Include
|
||||||
|
exclude := m.pathConfig.Exclude
|
||||||
|
|
||||||
|
includeEmpty := len(include) == 0
|
||||||
|
excludeEmpty := len(exclude) == 0
|
||||||
|
|
||||||
|
masterlog.Debug("AuthMiddleware: Evaluating auth requirement", map[string]interface{}{
|
||||||
|
"path": path,
|
||||||
|
"include_empty": includeEmpty,
|
||||||
|
"exclude_empty": excludeEmpty,
|
||||||
|
"include": include,
|
||||||
|
"exclude": exclude,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Case 1: Both include and exclude are empty → auth required for ALL
|
||||||
|
if includeEmpty && excludeEmpty {
|
||||||
|
masterlog.Debug("AuthMiddleware: Both include/exclude empty, auth required for all", map[string]interface{}{
|
||||||
|
"path": path,
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 2: Only include is set → auth required ONLY for matching paths
|
||||||
|
if !includeEmpty {
|
||||||
|
for _, pattern := range include {
|
||||||
|
if m.matchPattern(path, pattern) {
|
||||||
|
masterlog.Debug("AuthMiddleware: Path matches include pattern", map[string]interface{}{
|
||||||
|
"path": path,
|
||||||
|
"pattern": pattern,
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
masterlog.Debug("AuthMiddleware: Path does not match any include pattern", map[string]interface{}{
|
||||||
|
"path": path,
|
||||||
|
"patterns": include,
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 3: Only exclude is set (include is empty) → auth required EXCEPT for matching paths
|
||||||
|
// This is also reached when both are set (include takes precedence above)
|
||||||
|
for _, pattern := range exclude {
|
||||||
|
if m.matchPattern(path, pattern) {
|
||||||
|
masterlog.Debug("AuthMiddleware: Path matches exclude pattern", map[string]interface{}{
|
||||||
|
"path": path,
|
||||||
|
"pattern": pattern,
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
masterlog.Debug("AuthMiddleware: Path does not match any exclude pattern, auth required", map[string]interface{}{
|
||||||
|
"path": path,
|
||||||
|
"patterns": exclude,
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// matchPattern checks if a path matches a wildcard pattern
|
||||||
|
//
|
||||||
|
// Supported patterns:
|
||||||
|
// - "*" matches any path
|
||||||
|
// - "/api/*" matches "/api/" and any subpath
|
||||||
|
// - "/api/v1/public/test/*" matches the exact prefix and any subpath
|
||||||
|
//
|
||||||
|
// The pattern matching is prefix-based. If the pattern ends with "*",
|
||||||
|
// it matches any path that starts with the pattern (excluding the "*").
|
||||||
|
func (m *AuthMiddleware) matchPattern(path, pattern string) bool {
|
||||||
|
// Wildcard: matches everything
|
||||||
|
if pattern == "*" {
|
||||||
|
masterlog.Debug("AuthMiddleware: Wildcard pattern matches", map[string]interface{}{
|
||||||
|
"path": path,
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pattern ends with wildcard: prefix matching
|
||||||
|
if strings.HasSuffix(pattern, "*") {
|
||||||
|
prefix := strings.TrimSuffix(pattern, "*")
|
||||||
|
matches := strings.HasPrefix(path, prefix)
|
||||||
|
masterlog.Debug("AuthMiddleware: Prefix pattern matching", map[string]interface{}{
|
||||||
|
"path": path,
|
||||||
|
"pattern": pattern,
|
||||||
|
"prefix": prefix,
|
||||||
|
"matches": matches,
|
||||||
|
})
|
||||||
|
return matches
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exact match
|
||||||
|
matches := path == pattern
|
||||||
|
masterlog.Debug("AuthMiddleware: Exact pattern matching", map[string]interface{}{
|
||||||
|
"path": path,
|
||||||
|
"pattern": pattern,
|
||||||
|
"matches": matches,
|
||||||
|
})
|
||||||
|
return matches
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.secnex.io/secnex/api-gateway/config"
|
"git.secnex.io/secnex/api-gateway/config"
|
||||||
|
"git.secnex.io/secnex/api-gateway/middlewares"
|
||||||
"git.secnex.io/secnex/masterlog"
|
"git.secnex.io/secnex/masterlog"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
)
|
)
|
||||||
@@ -17,6 +18,7 @@ type Route struct {
|
|||||||
ID string
|
ID string
|
||||||
Path string
|
Path string
|
||||||
StripPrefix config.StripPrefix
|
StripPrefix config.StripPrefix
|
||||||
|
Security config.Security
|
||||||
Api *Api
|
Api *Api
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,6 +29,7 @@ func NewRoutes(cfg *config.Configuration, apis Apis) *Routes {
|
|||||||
ID: route.ID,
|
ID: route.ID,
|
||||||
Path: route.Path,
|
Path: route.Path,
|
||||||
StripPrefix: route.StripPrefix,
|
StripPrefix: route.StripPrefix,
|
||||||
|
Security: route.Security,
|
||||||
Api: apis[route.Api],
|
Api: apis[route.Api],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -39,6 +42,10 @@ func (rs *Routes) Register(r *chi.Mux) {
|
|||||||
"id": route.ID,
|
"id": route.ID,
|
||||||
"path": route.Path,
|
"path": route.Path,
|
||||||
"api": route.Api.ID,
|
"api": route.Api.ID,
|
||||||
|
"auth_enabled": route.Security.Auth.Enabled,
|
||||||
|
"auth_header": route.Security.Auth.Header,
|
||||||
|
"auth_include": route.Security.Auth.Path.Include,
|
||||||
|
"auth_exclude": route.Security.Auth.Path.Exclude,
|
||||||
})
|
})
|
||||||
|
|
||||||
handler := route.createHandler()
|
handler := route.createHandler()
|
||||||
@@ -47,9 +54,29 @@ func (rs *Routes) Register(r *chi.Mux) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Route) createHandler() http.Handler {
|
func (r *Route) createHandler() http.Handler {
|
||||||
|
// Start with the API (proxy) handler
|
||||||
handler := http.Handler(r.Api)
|
handler := http.Handler(r.Api)
|
||||||
|
|
||||||
|
// Apply middlewares in reverse order (last one wraps first)
|
||||||
|
// 1. Auth middleware (if enabled)
|
||||||
|
if r.Security.Auth.Enabled {
|
||||||
|
masterlog.Debug("Route: Applying Auth middleware", map[string]interface{}{
|
||||||
|
"path": r.Path,
|
||||||
|
"header": r.Security.Auth.Header,
|
||||||
|
})
|
||||||
|
handler = middlewares.NewAuthMiddleware(
|
||||||
|
r.Security.Auth.Header,
|
||||||
|
r.Security.Auth.Path,
|
||||||
|
handler,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Strip prefix middleware (if enabled)
|
||||||
if r.StripPrefix.Enabled {
|
if r.StripPrefix.Enabled {
|
||||||
|
masterlog.Debug("Route: Applying StripPrefix middleware", map[string]interface{}{
|
||||||
|
"path": r.Path,
|
||||||
|
"prefix": r.StripPrefix.Prefix,
|
||||||
|
})
|
||||||
handler = newStripPrefixMiddleware(r.StripPrefix.Prefix, handler)
|
handler = newStripPrefixMiddleware(r.StripPrefix.Prefix, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user