mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-02 04:20:50 +08:00
- Added extensive SDK usage guides for `cliproxy`, `sdk/access`, and watcher integration. - Introduced `--password` flag for specifying local management access passwords. - Enhanced management API with local password checks to secure localhost requests. - Updated documentation to reflect the new password functionality.
177 lines
6.7 KiB
Markdown
177 lines
6.7 KiB
Markdown
# @sdk/access SDK Reference
|
|
|
|
The `github.com/router-for-me/CLIProxyAPI/v6/sdk/access` package centralizes inbound request authentication for the proxy. It offers a lightweight manager that chains credential providers, so servers can reuse the same access control logic inside or outside the CLI runtime.
|
|
|
|
## Importing
|
|
|
|
```go
|
|
import (
|
|
sdkaccess "github.com/router-for-me/CLIProxyAPI/v6/sdk/access"
|
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
|
)
|
|
```
|
|
|
|
Add the module with `go get github.com/router-for-me/CLIProxyAPI/v6/sdk/access`.
|
|
|
|
## Manager Lifecycle
|
|
|
|
```go
|
|
manager := sdkaccess.NewManager()
|
|
providers, err := sdkaccess.BuildProviders(cfg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
manager.SetProviders(providers)
|
|
```
|
|
|
|
* `NewManager` constructs an empty manager.
|
|
* `SetProviders` replaces the provider slice using a defensive copy.
|
|
* `Providers` retrieves a snapshot that can be iterated safely from other goroutines.
|
|
* `BuildProviders` translates `config.Config` access declarations into runnable providers. When the config omits explicit providers but defines inline API keys, the helper auto-installs the built-in `config-api-key` provider.
|
|
|
|
## Authenticating Requests
|
|
|
|
```go
|
|
result, err := manager.Authenticate(ctx, req)
|
|
switch {
|
|
case err == nil:
|
|
// Authentication succeeded; result describes the provider and principal.
|
|
case errors.Is(err, sdkaccess.ErrNoCredentials):
|
|
// No recognizable credentials were supplied.
|
|
case errors.Is(err, sdkaccess.ErrInvalidCredential):
|
|
// Supplied credentials were present but rejected.
|
|
default:
|
|
// Transport-level failure was returned by a provider.
|
|
}
|
|
```
|
|
|
|
`Manager.Authenticate` walks the configured providers in order. It returns on the first success, skips providers that surface `ErrNotHandled`, and tracks whether any provider reported `ErrNoCredentials` or `ErrInvalidCredential` for downstream error reporting.
|
|
|
|
If the manager itself is `nil` or no providers are registered, the call returns `nil, nil`, allowing callers to treat access control as disabled without branching on errors.
|
|
|
|
Each `Result` includes the provider identifier, the resolved principal, and optional metadata (for example, which header carried the credential).
|
|
|
|
## Configuration Layout
|
|
|
|
The manager expects access providers under the `auth.providers` key inside `config.yaml`:
|
|
|
|
```yaml
|
|
auth:
|
|
providers:
|
|
- name: inline-api
|
|
type: config-api-key
|
|
api-keys:
|
|
- sk-test-123
|
|
- sk-prod-456
|
|
```
|
|
|
|
Fields map directly to `config.AccessProvider`: `name` labels the provider, `type` selects the registered factory, `sdk` can name an external module, `api-keys` seeds inline credentials, and `config` passes provider-specific options.
|
|
|
|
### Loading providers from external SDK modules
|
|
|
|
To consume a provider shipped in another Go module, point the `sdk` field at the module path and import it for its registration side effect:
|
|
|
|
```yaml
|
|
auth:
|
|
providers:
|
|
- name: partner-auth
|
|
type: partner-token
|
|
sdk: github.com/acme/xplatform/sdk/access/providers/partner
|
|
config:
|
|
region: us-west-2
|
|
audience: cli-proxy
|
|
```
|
|
|
|
```go
|
|
import (
|
|
_ "github.com/acme/xplatform/sdk/access/providers/partner" // registers partner-token
|
|
sdkaccess "github.com/router-for-me/CLIProxyAPI/v6/sdk/access"
|
|
)
|
|
```
|
|
|
|
The blank identifier import ensures `init` runs so `sdkaccess.RegisterProvider` executes before `BuildProviders` is called.
|
|
|
|
## Built-in Providers
|
|
|
|
The SDK ships with one provider out of the box:
|
|
|
|
- `config-api-key`: Validates API keys declared inline or under top-level `api-keys`. It accepts the key from `Authorization: Bearer`, `X-Goog-Api-Key`, `X-Api-Key`, or the `?key=` query string and reports `ErrInvalidCredential` when no match is found.
|
|
|
|
Additional providers can be delivered by third-party packages. When a provider package is imported, it registers itself with `sdkaccess.RegisterProvider`.
|
|
|
|
### Metadata and auditing
|
|
|
|
`Result.Metadata` carries provider-specific context. The built-in `config-api-key` provider, for example, stores the credential source (`authorization`, `x-goog-api-key`, `x-api-key`, or `query-key`). Populate this map in custom providers to enrich logs and downstream auditing.
|
|
|
|
## Writing Custom Providers
|
|
|
|
```go
|
|
type customProvider struct{}
|
|
|
|
func (p *customProvider) Identifier() string { return "my-provider" }
|
|
|
|
func (p *customProvider) Authenticate(ctx context.Context, r *http.Request) (*sdkaccess.Result, error) {
|
|
token := r.Header.Get("X-Custom")
|
|
if token == "" {
|
|
return nil, sdkaccess.ErrNoCredentials
|
|
}
|
|
if token != "expected" {
|
|
return nil, sdkaccess.ErrInvalidCredential
|
|
}
|
|
return &sdkaccess.Result{
|
|
Provider: p.Identifier(),
|
|
Principal: "service-user",
|
|
Metadata: map[string]string{"source": "x-custom"},
|
|
}, nil
|
|
}
|
|
|
|
func init() {
|
|
sdkaccess.RegisterProvider("custom", func(cfg *config.AccessProvider, root *config.Config) (sdkaccess.Provider, error) {
|
|
return &customProvider{}, nil
|
|
})
|
|
}
|
|
```
|
|
|
|
A provider must implement `Identifier()` and `Authenticate()`. To expose it to configuration, call `RegisterProvider` inside `init`. Provider factories receive the specific `AccessProvider` block plus the full root configuration for contextual needs.
|
|
|
|
## Error Semantics
|
|
|
|
- `ErrNoCredentials`: no credentials were present or recognized by any provider.
|
|
- `ErrInvalidCredential`: at least one provider processed the credentials but rejected them.
|
|
- `ErrNotHandled`: instructs the manager to fall through to the next provider without affecting aggregate error reporting.
|
|
|
|
Return custom errors to surface transport failures; they propagate immediately to the caller instead of being masked.
|
|
|
|
## Integration with cliproxy Service
|
|
|
|
`sdk/cliproxy` wires `@sdk/access` automatically when you build a CLI service via `cliproxy.NewBuilder`. Supplying a preconfigured manager allows you to extend or override the default providers:
|
|
|
|
```go
|
|
coreCfg, _ := config.LoadConfig("config.yaml")
|
|
providers, _ := sdkaccess.BuildProviders(coreCfg)
|
|
manager := sdkaccess.NewManager()
|
|
manager.SetProviders(providers)
|
|
|
|
svc, _ := cliproxy.NewBuilder().
|
|
WithConfig(coreCfg).
|
|
WithAccessManager(manager).
|
|
Build()
|
|
```
|
|
|
|
The service reuses the manager for every inbound request, ensuring consistent authentication across embedded deployments and the canonical CLI binary.
|
|
|
|
### Hot reloading providers
|
|
|
|
When configuration changes, rebuild providers and swap them into the manager:
|
|
|
|
```go
|
|
providers, err := sdkaccess.BuildProviders(newCfg)
|
|
if err != nil {
|
|
log.Errorf("reload auth providers failed: %v", err)
|
|
return
|
|
}
|
|
accessManager.SetProviders(providers)
|
|
```
|
|
|
|
This mirrors the behaviour in `cliproxy.Service.refreshAccessProviders` and `api.Server.applyAccessConfig`, enabling runtime updates without restarting the process.
|