support authentication via APIKEY configuration
This commit is contained in:
@@ -38,6 +38,9 @@ Create and configure your `~/.claude-code-router/config.json` file. For more det
|
|||||||
The `config.json` file has several key sections:
|
The `config.json` file has several key sections:
|
||||||
- **`PROXY_URL`** (optional): You can set a proxy for API requests, for example: `"PROXY_URL": "http://127.0.0.1:7890"`.
|
- **`PROXY_URL`** (optional): You can set a proxy for API requests, for example: `"PROXY_URL": "http://127.0.0.1:7890"`.
|
||||||
- **`LOG`** (optional): You can enable logging by setting it to `true`. The log file will be located at `$HOME/.claude-code-router.log`.
|
- **`LOG`** (optional): You can enable logging by setting it to `true`. The log file will be located at `$HOME/.claude-code-router.log`.
|
||||||
|
- **`APIKEY`** (optional): You can set a secret key to authenticate requests. When set, clients must provide this key in the `Authorization` header (e.g., `Bearer your-secret-key`) or the `x-api-key` header. Example: `"APIKEY": "your-secret-key"`.
|
||||||
|
- **`HOST`** (optional): You can set the host address for the server. If `APIKEY` is not set, the host will be forced to `127.0.0.1` for security reasons to prevent unauthorized access. Example: `"HOST": "0.0.0.0"`.
|
||||||
|
|
||||||
- **`Providers`**: Used to configure different model providers.
|
- **`Providers`**: Used to configure different model providers.
|
||||||
- **`Router`**: Used to set up routing rules. `default` specifies the default model, which will be used for all requests if no other route is configured.
|
- **`Router`**: Used to set up routing rules. `default` specifies the default model, which will be used for all requests if no other route is configured.
|
||||||
|
|
||||||
@@ -45,6 +48,7 @@ Here is a comprehensive example:
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
"APIKEY": "your-secret-key",
|
||||||
"PROXY_URL": "http://127.0.0.1:7890",
|
"PROXY_URL": "http://127.0.0.1:7890",
|
||||||
"LOG": true,
|
"LOG": true,
|
||||||
"Providers": [
|
"Providers": [
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ npm install -g @musistudio/claude-code-router
|
|||||||
`config.json` 文件有几个关键部分:
|
`config.json` 文件有几个关键部分:
|
||||||
- **`PROXY_URL`** (可选): 您可以为 API 请求设置代理,例如:`"PROXY_URL": "http://127.0.0.1:7890"`。
|
- **`PROXY_URL`** (可选): 您可以为 API 请求设置代理,例如:`"PROXY_URL": "http://127.0.0.1:7890"`。
|
||||||
- **`LOG`** (可选): 您可以通过将其设置为 `true` 来启用日志记录。日志文件将位于 `$HOME/.claude-code-router.log`。
|
- **`LOG`** (可选): 您可以通过将其设置为 `true` 来启用日志记录。日志文件将位于 `$HOME/.claude-code-router.log`。
|
||||||
|
- **`APIKEY`** (可选): 您可以设置一个密钥来进行身份验证。设置后,客户端请求必须在 `Authorization` 请求头 (例如, `Bearer your-secret-key`) 或 `x-api-key` 请求头中提供此密钥。例如:`"APIKEY": "your-secret-key"`。
|
||||||
|
- **`HOST`** (可选): 您可以设置服务的主机地址。如果未设置 `APIKEY`,出于安全考虑,主机地址将强制设置为 `127.0.0.1`,以防止未经授权的访问。例如:`"HOST": "0.0.0.0"`。
|
||||||
- **`Providers`**: 用于配置不同的模型提供商。
|
- **`Providers`**: 用于配置不同的模型提供商。
|
||||||
- **`Router`**: 用于设置路由规则。`default` 指定默认模型,如果未配置其他路由,则该模型将用于所有请求。
|
- **`Router`**: 用于设置路由规则。`default` 指定默认模型,如果未配置其他路由,则该模型将用于所有请求。
|
||||||
|
|
||||||
@@ -43,6 +45,7 @@ npm install -g @musistudio/claude-code-router
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
"APIKEY": "your-secret-key",
|
||||||
"PROXY_URL": "http://127.0.0.1:7890",
|
"PROXY_URL": "http://127.0.0.1:7890",
|
||||||
"LOG": true,
|
"LOG": true,
|
||||||
"Providers": [
|
"Providers": [
|
||||||
|
|||||||
@@ -72,5 +72,7 @@
|
|||||||
"background": "ollama,qwen2.5-coder:latest",
|
"background": "ollama,qwen2.5-coder:latest",
|
||||||
"think": "deepseek,deepseek-reasoner",
|
"think": "deepseek,deepseek-reasoner",
|
||||||
"longContext": "openrouter,google/gemini-2.5-pro-preview"
|
"longContext": "openrouter,google/gemini-2.5-pro-preview"
|
||||||
}
|
},
|
||||||
|
"APIKEY": "your-secret-key",
|
||||||
|
"HOST": "0.0.0.0"
|
||||||
}
|
}
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"esbuild": "^0.25.1",
|
"esbuild": "^0.25.1",
|
||||||
|
"fastify": "^5.4.0",
|
||||||
"shx": "^0.4.0",
|
"shx": "^0.4.0",
|
||||||
"typescript": "^5.8.2"
|
"typescript": "^5.8.2"
|
||||||
},
|
},
|
||||||
|
|||||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -24,6 +24,9 @@ importers:
|
|||||||
esbuild:
|
esbuild:
|
||||||
specifier: ^0.25.1
|
specifier: ^0.25.1
|
||||||
version: 0.25.5
|
version: 0.25.5
|
||||||
|
fastify:
|
||||||
|
specifier: ^5.4.0
|
||||||
|
version: 5.4.0
|
||||||
shx:
|
shx:
|
||||||
specifier: ^0.4.0
|
specifier: ^0.4.0
|
||||||
version: 0.4.0
|
version: 0.4.0
|
||||||
|
|||||||
12
src/index.ts
12
src/index.ts
@@ -5,6 +5,7 @@ import { join } from "path";
|
|||||||
import { initConfig, initDir } from "./utils";
|
import { initConfig, initDir } from "./utils";
|
||||||
import { createServer } from "./server";
|
import { createServer } from "./server";
|
||||||
import { router } from "./utils/router";
|
import { router } from "./utils/router";
|
||||||
|
import { apiKeyAuth } from "./middleware/auth";
|
||||||
import {
|
import {
|
||||||
cleanupPidFile,
|
cleanupPidFile,
|
||||||
isServiceRunning,
|
isServiceRunning,
|
||||||
@@ -46,6 +47,14 @@ async function run(options: RunOptions = {}) {
|
|||||||
await initializeClaudeConfig();
|
await initializeClaudeConfig();
|
||||||
await initDir();
|
await initDir();
|
||||||
const config = await initConfig();
|
const config = await initConfig();
|
||||||
|
let HOST = config.HOST;
|
||||||
|
|
||||||
|
if (config.HOST && !config.APIKEY) {
|
||||||
|
HOST = "127.0.0.1";
|
||||||
|
console.warn(
|
||||||
|
"⚠️ API key is not set. HOST is forced to 127.0.0.1."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const port = options.port || 3456;
|
const port = options.port || 3456;
|
||||||
|
|
||||||
@@ -64,6 +73,7 @@ async function run(options: RunOptions = {}) {
|
|||||||
cleanupPidFile();
|
cleanupPidFile();
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
console.log(HOST)
|
||||||
|
|
||||||
// Use port from environment variable if set (for background process)
|
// Use port from environment variable if set (for background process)
|
||||||
const servicePort = process.env.SERVICE_PORT
|
const servicePort = process.env.SERVICE_PORT
|
||||||
@@ -74,6 +84,7 @@ async function run(options: RunOptions = {}) {
|
|||||||
initialConfig: {
|
initialConfig: {
|
||||||
// ...config,
|
// ...config,
|
||||||
providers: config.Providers || config.providers,
|
providers: config.Providers || config.providers,
|
||||||
|
HOST: HOST,
|
||||||
PORT: servicePort,
|
PORT: servicePort,
|
||||||
LOG_FILE: join(
|
LOG_FILE: join(
|
||||||
homedir(),
|
homedir(),
|
||||||
@@ -82,6 +93,7 @@ async function run(options: RunOptions = {}) {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
server.addHook("preHandler", apiKeyAuth(config));
|
||||||
server.addHook("preHandler", async (req, reply) =>
|
server.addHook("preHandler", async (req, reply) =>
|
||||||
router(req, reply, config)
|
router(req, reply, config)
|
||||||
);
|
);
|
||||||
|
|||||||
33
src/middleware/auth.ts
Normal file
33
src/middleware/auth.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { FastifyRequest, FastifyReply } from "fastify";
|
||||||
|
|
||||||
|
export const apiKeyAuth =
|
||||||
|
(config: any) =>
|
||||||
|
(req: FastifyRequest, reply: FastifyReply, done: () => void) => {
|
||||||
|
if (["/", "/health"].includes(req.url)) {
|
||||||
|
return done();
|
||||||
|
}
|
||||||
|
const apiKey = config.APIKEY;
|
||||||
|
|
||||||
|
if (!apiKey) {
|
||||||
|
return done();
|
||||||
|
}
|
||||||
|
|
||||||
|
const authKey: string =
|
||||||
|
req.headers.authorization || req.headers["x-api-key"];
|
||||||
|
if (!authKey) {
|
||||||
|
reply.status(401).send("APIKEY is missing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let token = "";
|
||||||
|
if (authKey.startsWith("Bearer")) {
|
||||||
|
token = authKey.split(" ")[1];
|
||||||
|
} else {
|
||||||
|
token = authKey;
|
||||||
|
}
|
||||||
|
if (token !== apiKey) {
|
||||||
|
reply.status(401).send("Invalid API key");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
done();
|
||||||
|
};
|
||||||
@@ -4,9 +4,11 @@ import {
|
|||||||
decrementReferenceCount,
|
decrementReferenceCount,
|
||||||
} from "./processCheck";
|
} from "./processCheck";
|
||||||
import { closeService } from "./close";
|
import { closeService } from "./close";
|
||||||
|
import { readConfigFile } from ".";
|
||||||
|
|
||||||
export async function executeCodeCommand(args: string[] = []) {
|
export async function executeCodeCommand(args: string[] = []) {
|
||||||
// Set environment variables
|
// Set environment variables
|
||||||
|
const config = await readConfigFile();
|
||||||
const env = {
|
const env = {
|
||||||
...process.env,
|
...process.env,
|
||||||
ANTHROPIC_AUTH_TOKEN: "test",
|
ANTHROPIC_AUTH_TOKEN: "test",
|
||||||
@@ -14,6 +16,11 @@ export async function executeCodeCommand(args: string[] = []) {
|
|||||||
API_TIMEOUT_MS: "600000",
|
API_TIMEOUT_MS: "600000",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (config?.APIKEY) {
|
||||||
|
env.ANTHROPIC_API_KEY = config.APIKEY;
|
||||||
|
delete env.ANTHROPIC_AUTH_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
// Increment reference count when command starts
|
// Increment reference count when command starts
|
||||||
incrementReferenceCount();
|
incrementReferenceCount();
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export const readConfigFile = async () => {
|
|||||||
return JSON.parse(config);
|
return JSON.parse(config);
|
||||||
} catch {
|
} catch {
|
||||||
const name = await question("Enter Provider Name: ");
|
const name = await question("Enter Provider Name: ");
|
||||||
const apiKey = await question("Enter Provider API KEY: ");
|
const APIKEY = await question("Enter Provider API KEY: ");
|
||||||
const baseUrl = await question("Enter Provider URL: ");
|
const baseUrl = await question("Enter Provider URL: ");
|
||||||
const model = await question("Enter MODEL Name: ");
|
const model = await question("Enter MODEL Name: ");
|
||||||
const config = Object.assign({}, DEFAULT_CONFIG, {
|
const config = Object.assign({}, DEFAULT_CONFIG, {
|
||||||
@@ -56,7 +56,7 @@ export const readConfigFile = async () => {
|
|||||||
{
|
{
|
||||||
name,
|
name,
|
||||||
api_base_url: baseUrl,
|
api_base_url: baseUrl,
|
||||||
api_key: apiKey,
|
api_key: APIKEY,
|
||||||
models: [model],
|
models: [model],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user