如何开发带API Key与Client ID认证的npm包,实现类似Stripe的调用方式
单入口带认证校验的npm包开发实现方案
问题1:仅暴露单一访问入口、支持初始化传认证参数的实现方式
你只需要把所有功能逻辑封装到一个单一主类中,作为npm包的唯一导出项即可,具体实现流程如下:
- 配置npm包的入口文件:在package.json中指定入口(ESM规范配
"module": "index.js",CommonJS规范配"main": "index.cjs",可同时配置兼容两种规范) - 入口文件仅导出主类,所有功能子模块都挂载到主类的实例属性上,参考示例代码:
// 包入口文件index.js import Customers from './resources/customers.js' import Orders from './resources/orders.js' class MySdk { // 构造函数接收认证参数 constructor(apiKey, clientId) { // 用私有属性存储认证信息,避免外部直接读取修改 this.#apiKey = apiKey this.#clientId = clientId // 初始化参数格式校验 if (!apiKey?.trim() || !clientId?.trim()) { throw new Error('apiKey 和 clientId 为必填初始化参数') } // 挂载功能子模块,把当前主类实例传入子模块,方便子模块获取认证信息和公共方法 this.customers = new Customers(this) this.orders = new Orders(this) } // 私有属性存储敏感认证信息 #apiKey #clientId // 对内暴露认证信息的方法,不直接暴露私有属性 getAuthInfo() { return { apiKey: this.#apiKey, clientId: this.#clientId } } } // 唯一导出项就是主类 export default MySdk
用户安装你的包之后就可以直接用和Stripe完全一致的方式初始化:
import MySdk from '你的npm包名' const sdk = new MySdk('你的apiKey', '你的clientId') sdk.customers.create()
相关开发规范可以参考npm官方的包开发指南、ES6类封装的相关教程。
问题2:全局认证失败安全拦截的实现方式
可以通过两层拦截实现全功能的安全校验,避免认证不通过的情况下调用功能:
第一层:初始化前置校验
可以在主类构造函数中先调用服务端的认证校验接口,提前校验密钥有效性,校验不通过直接抛出错误阻止实例初始化:
class MySdk { constructor(apiKey, clientId) { // 参数校验逻辑省略 this.#authValid = false // 调用服务端接口校验认证信息有效性 this.#initAuthCheck() } async #initAuthCheck() { try { const res = await fetch('https://你的服务端认证校验接口', { headers: { 'X-Api-Key': this.#apiKey, 'X-Client-Id': this.#clientId } }) if (!res.ok) throw new Error('认证信息无效') this.#authValid = true } catch (e) { throw new Error(`SDK初始化失败:${e.message}`) } } }
第二层:全局请求拦截
在主类中封装统一的公共请求方法,所有子模块的接口调用都必须走这个公共方法,在请求方法中统一做认证状态校验和返回结果的认证错误拦截:
class MySdk { // 私有公共请求方法,所有子模块只能通过该方法发请求 async #request(path, options = {}) { // 先校验认证状态,不通过直接抛出错误 if (!this.#authValid) { throw new Error('认证信息无效,请检查apiKey和clientId是否正确') } const auth = this.getAuthInfo() // 统一注入认证头 const headers = { 'X-Api-Key': auth.apiKey, 'X-Client-Id': auth.clientId, 'Content-Type': 'application/json', ...options.headers } const res = await fetch(`https://你的服务端接口根路径/${path}`, { ...options, headers }) // 统一拦截401认证失效的响应 if (res.status === 401) { this.#authValid = false throw new Error('认证已失效,请重新初始化SDK实例') } if (!res.ok) throw new Error(`请求失败:${res.statusText}`) return res.json() } // 对外暴露绑定了当前实例的请求方法给子模块调用 getRequest() { return this.#request.bind(this) } }
子模块的代码示例:
// customers.js class Customers { constructor(sdkInstance) { this.request = sdkInstance.getRequest() } async create(params = {}) { return this.request('customers', { method: 'POST', body: JSON.stringify(params) }) } }
开发注意事项
- 所有的认证有效性校验必须走服务端接口,不要在SDK本地做密钥规则校验,避免被绕过
- 敏感的认证信息一定要用JS私有属性(#开头)存储,不要挂在实例公共属性上,防止外部意外读取或篡改
- 错误信息要明确区分参数错误、认证无效、权限不足等场景,方便接入方排查问题
相关安全开发规范可以参考Node.js SDK安全开发、API密钥校验的相关公开教程。
内容的提问来源于stack exchange,提问作者markWanka
相关产品推荐
相关产品推荐

