使用 Authing 快速实现一套类似 OpenAI 的认证、API Key 商业权益授权机制

如果你有经常使用 OpenAI 或者 HuggingFace 这一类面向开发者的 SaaS 服务,对于 API Key 肯定不会陌生。我们在使用这些服务时,通常都会在其平台上面创建一套 API Key,之后我们才能在代码中通过这一串 API key 访问其服务;同时,我们购买的权益也会和对应的 API Key 绑定在一起。


除了 API Key 的校验,用户认证也是重要的一环,如果能够快速集成市面上常见的社会化登录方式(如微信、GitHub、Google 等),这将会极大降低用户使用的门槛。而大模型服务往往需要快速上线,快速强占市场,从零开发一套完整的用户认证体系无疑会消耗大量的时间和人力成本。

这篇文章我们关注的问题是:假如你也有这样一个面向开发者的大模型服务,我们如何基于 Authing强大的认证以及数据资源能力,快速实现你的认证和 API Key 模块。

01.5 分钟、5 行代码完成用户认证

一个比较完备且用户体验良好的登录框,应该能够支持以下几个基本的认证方式:账密登录、手机号验证码登录、常见社会化登录;如果是有公众号推广需求的服务,可能还需要关注公众号登录。而这些能力,Authing 的 Guard 全部都内置好了,不需要进行任何的开发工作。

首先第一步,我们需要在 Authing 创建一个用户池,这里我们将用户池类型设置为 ToC:

接下来在 Authing 控制台的应用 - 自建应用页面创建一个应用:这里我们选择「标准 Web 应用」,并且填好应用名称和二级域名:

创建好之后,你将会自动拥有一个能够被立即在线访问到的登录页面。接下来要做的,就是在这上面配置你需要的登录方式了:在应用详情的「登录控制」菜单,你可以快速添加你需要的认证方式:

我们以微信扫码登录这个方式举例:我们提供了非常完整的文档,你只需要按照文档的说明,填入相关的 AppId、AppSecret 即可:

配置完成再次访问登录页面,就可以看到微信扫码登录已经出现在界面上了!That's It!

如果你对于登录页面有品牌化的需求,比如自定义背景、自定义 CSS 等,也可以在 Authing 控制台的品牌化页面进行自定义:

接下来我们测试一下登录:用一个账号登录之后,你会看到页面跳转到了一个欢迎界面,这个是一个默认的调试页面,这里面介绍了后续你需要完成的操作:
如果你遇到了「无权限登录,请联系管理员」的错误提示,可以在 Authing 控制台的安全设置 - 通用安全 - 注册安全页面,将「禁止注册」开关关闭,以及在应用详情的访问授权页面,设置应用访问控制规则为「所有人可访问」。


请重点关注「处理回调」这部分的内容:相信你也已经猜到了,实际我们业务上线的时候,是需要替换这个默认的调试页面成你自己的回调地址的,「处理回调」这部分介绍了后续你需要完成的内容:

1. 替换回调地址;
2. 在回调地址接收 Authing 传过来的授权码 code;
3. 使用 code 换取用户信息和 token 并存储 token;
4. 后续此用户请求你的 API 时,需要携带上此 token;
5. 在后端校验此 token 的合法性。

如果你希望将登录页面嵌入到你自己的页面中,我们也提供了 React、Vue、Angular 以及 iOS、Android 的组件:

02.实现大模型 API Key 的调用鉴权

如本文最开始介绍的:大模型服务一般都会通过 API Key 的方式,允许用户通过可编程的方式接入你的大模型服务,以 OpenAI 举例,我们都知道在 Python 程序中我们是这么去使用的:

import openai# 设置 API Key
openai.api_key = 'xxxxxxxxxxxxxxxxxxxxxx';# 接下来去请求 OpenAI 的相关接口


这里面背后的逻辑,是 OpenAI 的 Python SDK 在请求 OpenAI 接口的时候,会在请求头上携带此 token,然后在后端校验此 Token 的合法性以及权益。


下面我们介绍如何使用 Authing 的数据资源能力来实现这两部分功能:API Key 的鉴权、API Key 的权益校验。
创建权限空间
第一步,我们在 Authing 控制台的「权限管理」-「权限空间」菜单创建一个名为 apikey 的权限空间,我们使用这个空间来存储和管理平台所有的 API Key。

创建 API Key 数据资源
假设我们想象你的开发者在你的平台上面创建了一个 API key,这个 key 可能会包含以下基本的信息:

  • key 的展示名称;
  • key 的内容:一串随机的且唯一的字符串;
  • key 的创建时间、修改时间、最近一次使用时间等等相关的元数据;
  • key 对应的权益信息,比如最多运行调用多少次 API、已经调用了多少次 API 等。


与之对应的,Authing 提供的了「数据资源」的概念,完美契合这样的场景。我们在 Authing 控制台的「权限管理」-「数据资源权限」菜单创建一个示例的字符串类型的「数据资源」:

  • 资源名称:对应 key 的展示名称;
  • 资源 Code:一串随机的且唯一的字符串,对应 key 的内容;
  • 字符串 Value:用于存储 key 相关的所有相关信息,随着你后续业务的增长,你可能会需要存储更多的信息:
{"CREATED": "2023.10.22 10:00:00","LAST_USED": "2023.10.22 20:00:00","TOTAL_USAGE": 123,"USAGE_AVALIABLE": 1000
}

除了控制台之外,我们也提供了相关的 API 和 SDK,帮助你在程序中自动创建 API Key(数据资源),下面以 nodejs sdk 为例:

import { ManagementClient } from "authing-node-sdk";// 初始化 ManagementClient
const managementClient = new ManagementClient({accessKeyId: "AUTHING_ACCESS_KEY_ID", // Authing Access Key IDaccessKeySecret: "AUTHING_ACCESS_KEY_SECRET", // Authing Access Key Secret
});const resource = await managementClient.createDataResource({"namespaceCode": "apikey","resourceName": "My API Key","resourceCode": "fizePoEnkNrvWPwOxeYPdbQjoFXJfppDtm","type": "STRING","struct": '{"CREATED": "2023.10.22 10:00:00", "LAST_USED": "2023.10.22 20:00:00", "TOTAL_USAGE": 123, "USAGE_AVALIABLE": 1000}',"actions": [revoke]
})
console.log(resource)

给用户授权 API Key 数据资源
假如你在通过 Authing 来管理用户,我们推荐在创建好 API Key 之后,将这个 API Key 授权给对应的用户,这样你可以在 Authing 平台清晰得看到所有用户的 API Key 授权情况。如果你只是使用 Authing 的数据资源来做 API Key 管理,而不使用 Authing 来管理用户,此部分可跳过。

在 Authing 控制台的「权限管理」 - 「数据资源权限」菜单,点击右上角的「授权」按钮,我们先创建一个针对之前创建的 API Key 的数据策略:

接着将这个数据策略授权给某个用户:

在这里我们之所以使用数据策略这种将数据资源打包的方式来对用户进行授权,是为了后续的扩展性和可维护性,比如你可能还会需要给某个角色统一授权某一些打包在一起的资源,当用户订阅到期之后,将其移除出角色,这样就可以自动取消授权。

之后,你就可以看到这个用户已经被授权了这个 API Key 了:

同样的,除了控制台之外,我们也提供了相关的 API 和 SDK,下面以 nodejs sdk 为例:

import { ManagementClient } from "authing-node-sdk";// 初始化 ManagementClient
const managementClient = new ManagementClient({accessKeyId: "AUTHING_ACCESS_KEY_ID", // Authing Access Key IDaccessKeySecret: "AUTHING_ACCESS_KEY_SECRET", // Authing Access Key Secret
});// 创建数据策略
const dataPolicy = await managementClient.createDataPolicy({policyName: "APIKEY_AUTHZ",statementList: [{effect: "ALLOW",permissionList: [{resourceCode: "fizePoEnkNrvWPwOxeYPdbQjoFXJfppDtm",operationType: "ALL"},],namespaceCode: "apikey",},]
});// 授权数据策略
await managementClient.authorizeDataPolicy({policyIds: [dataPolicy.id],targetList: [{type: "USER",id: "user_id"}]
})// 获取用户权限列表
const userPermissionList = await managementClient.getUserPermissionList({"userIds": ["user_id"]
}

在项目代码中使用
下面我们将以 Node.js 的 NestJS Web 框架举例。

假设你需要用户在请求你的 API 时,在 x-myllm-apikey 请求头上需要带上 API Key,我们封装一个 NestJS 的 Guard,在这里完成 API Key 的校验逻辑:

从请求头中获取 x-myllm-apikey 的内容;

判断此 API Key 对应的数据资源是否存在,如果不存在,返回 false;

import { Injectable, CanActivate, ExecutionContext, ForbiddenException } from '@nestjs/common';
import { ManagementClient } from "authing-node-sdk";// 初始化 ManagementClient
const managementClient = new ManagementClient({accessKeyId: "AUTHING_ACCESS_KEY_ID", // Authing Access Key IDaccessKeySecret: "AUTHING_ACCESS_KEY_SECRET", // Authing Access Key Secret
});@Injectable()
export class AuthGuard implements CanActivate {constructor() {}async canActivate(context: ExecutionContext): Promise<boolean> {const apiKey = request.headers['x-myllm-apikey'];const existsRes = await managementClient.checkDataResourceExists({namespaceCode: "apikey",resourceCode: apiKey});return existsRes.data.exists;
}


接着在对应的接口中,应用此 Guard 即可:

@UseGuards(AuthGuard)
@Post('/my-api')
public async handleApi() {}

03.实现大模型 API Key 不同商业版本的权益和权限控制


假如说你的大模型服务有以下几种订阅版本:

订阅版本Rate Limit可用的 Token 数其他权益明细
免费版3 / s50000...
基础版10 / s500000...
企业版UnlimitedUnlimited...

你可以借助 Authing 的数据资源能力,将 API Key 对应的所有权益全部存储起来:比如 TOTAL_USAGE(已经使用的 token 数)、USAGE_AVALIABLE(可用的 Token 数),以及其他任何你需要存储的数据。

你可以调用 Authing 数据资源的创建、查询、修改、删除 API,对这些 API Key 进行管理。


比如我们修改一下上一节的 AuthGuard 的实现,这里我们加入了可用 Token 数的权益校验逻辑:

获取数据资源的详情;

在这里例子中我们在数据资源的内容里面添加了两个自定义字段 USAGE_AVALIABLE和 TOTAL_USAGE,所以我们的判断依据就是比较以下这两个大小即可。如果说你的业务系统有其他的判断规则,你也可以写任意的自定义逻辑。

import { Injectable, CanActivate, ExecutionContext, ForbiddenException } from '@nestjs/common';
import { ManagementClient } from "authing-node-sdk";// 初始化 ManagementClient
const managementClient = new ManagementClient({accessKeyId: "AUTHING_ACCESS_KEY_ID", // Authing Access Key IDaccessKeySecret: "AUTHING_ACCESS_KEY_SECRET", // Authing Access Key Secret
});@Injectable()
export class AuthGuard implements CanActivate {constructor() {}async canActivate(context: ExecutionContext): Promise<boolean> {const apiKey = request.headers['x-myllm-apikey'];const existsRes = await managementClient.checkDataResourceExists({namespaceCode: "apikey",resourceCode: apiKey});return existsRes.data.exists;if (!existsRes.data.exists) {return false}const { data: resource } = await managementClient.getDataResource({namespaceCode: "apikey",resourceCode: apiKey})const { struct } = resource;const apiKeyData = JSON.parse(struct);const { TOTAL_USAGE, USAGE_AVALIABLE } = apiKeyData;return USAGE_AVALIABLE > TOTAL_USAGE}
}


如果你需要在每次请求之后增加一下 TOTAL_USAGE 的值,你只需要调用修改数据资源的接口即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/176018.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

处理SAP资产折旧AFAB 过账报错:“科目 8019010100 要求一个成本会计分配”

会计在进行资产折旧AFAB时 报错如下所示&#xff1a; 原因分析&#xff1a; 折旧时没有把资产设置得成本中心带到过账凭证的成本中心字段中去。而资产中已经维护了成本中心了。 所以要在资产过账的科目分配中设置一下路径如下&#xff1a; 或者TCODE&#xff1a;ACSET科目设置这…

Jmeter(二十一):jmeter导入和导出接口的处理(超详细)

JMeter测试导入接口 利用Jmeter测试上传文件&#xff0c;首先可根据接口文档或者fiddler抓包分析文件上传的接口&#xff1b;如下图&#xff1a; 以下是我通过fiddler所截取的文件上传的接口 1、填写导入接口的信息 查看文件上传栏下的填写信息&#xff1a; 文件名称&#x…

RT-Thread 7. RT-Thread Studio ENV修改MCU型号

1. 修改MCU型号 2.在ENV界面输入 scons -c scons --dist3. dist下为更新后完整源代码 4.导入RT-Thread Studio 发现GD32F330已经生效了。 5. 自己编写startup_gd32f3x0.S&#xff0c;准确性待验证 ;/* ; * Copyright (c) 2006-2021, RT-Thread Development Team ; * ; * SPD…

MySQL主从复制原理

1、MySQL主从复制的三个步骤及其原理图 slave会从master读取binlog来进行数据同步 MySQL复制过程分成三步&#xff1a; 1、master将改变记录到二进制日志&#xff08;binary log&#xff09;。这些记录过程叫做二进制日志事件&#xff0c;binary log events。 2、slave将ma…

WebService与RESTful两种接口风格示例

下面我将分别用WebService&#xff08;SOAP&#xff09;和RESTful API的例子来说明它们是如何工作的。 1. WebService (SOAP) 示例&#xff1a; 假设有一个在线计算器服务&#xff0c;它提供了一个加法操作的SOAP WebService。 SOAP请求&#xff08;客户端到服务器&#xff…

UG\NX二次开发 球坐标到直角坐标的转换

文章作者:里海 来源网站:《里海NX二次开发3000例专栏》 感谢粉丝订阅 感谢 JiaLiHuiNaoGui 订阅本专栏,非常感谢。 简介 已知角度θ和ϕ,距离d,求P点坐标。 "> 代码 #include "me.hpp" using namespace NXOpen; using namespace std;void GetP<

MBox肯定会因为回购和销毁将起飞

近期&#xff0c;币安链上的GameFi和元宇宙平台MOBOX宣布推出代币回购和销毁计划&#xff0c;在加密货币市场还处于熊市的现在&#xff0c;消息引起了不少链游打金爱好者和玩家的关注&#xff0c;MOBOX的讨论量也在快速上升。 在近一年多的熊市之中&#xff0c;很多GameFi项目从…

LeetCode:2003. 每棵子树内缺失的最小基因值(C++)

目录 2003. 每棵子树内缺失的最小基因值 题目描述&#xff1a; 实现代码与解析&#xff1a; dfs 启发式合并 原理思路&#xff1a; 2003. 每棵子树内缺失的最小基因值 题目描述&#xff1a; 有一棵根节点为 0 的 家族树 &#xff0c;总共包含 n 个节点&#xff0c;节点编…

【Linux】虚拟机部署与发布J2EE项目(Linux版本)

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《微信小程序开发实战》。&#x1f3af;&#x1f3a…

【Vue3-Flask-BS架构Web应用】实践笔记1-使用一个bat脚本自动化完整部署环境

前言 近年来&#xff0c;Web开发已经成为计算机科学领域中最热门和多产的领域之一。Python和Vue.js是两个备受欢迎的工具&#xff0c;用于构建现代Web应用程序。在本教程中&#xff0c;我们将探索如何使用这两个工具来创建一个完整的Web项目。我们将完成从安装Python和Vue.js到…

从0到1之微信小程序快速入门(02)

目录 页面导航 - 声明式导航 1. 导航到 tabBar 页面 2. 导航到非 tabBar 页面 3. 后退导航 ​编辑 页面导航 - 编程式导航 页面导航 - 导航传参 页面事件 - 下拉刷新事件 监听下拉刷新事件 停止下拉刷新的效果 页面事件 - 上拉触底事件 监听页面的上拉触底事件 配置…

项目部署之OpenResty

项目部署之OpenResty 1. OpenResty介绍 OpenResty 是一个基于Nginx的高性能Web平台&#xff0c;用于方便地搭建能够处理超高并发、扩展性极高的动态Web应用、Web服务和动态网关。具备下列特点&#xff1a; 具备Nginx的完整功能基于Lua语言进行扩展&#xff0c;集成了大量精良…

cmake多目录构建初步成功

目录和代码和 首次cmake 多目录构建失败 此文一样&#xff1b; 只有一个CMakeLists.txt&#xff1b; cmake_minimum_required(VERSION 3.10) project(mytest3 VERSION 1.0) include_directories("${PROJECT_SOURCE_DIR}/include") add_executable(mytest3 src/main…

vue2:路由前置守卫无法获取到this.$store.state.xxx

在获取到vuex的数据时候&#xff0c;想在router目录下的index.js文件去获取到vuex仓库中声明的全局变量&#xff0c;但是通过this.$store.stote.xxx去获取的时候&#xff0c;报错提示&#xff1a;$store未定义 一、store/index.js const store new Vuex.Store({state: {// 属…

WPS中图的自动编号及引用

WPS中图的自动编号及引用 图的自动编号图编号的引用图编号及引用的更新 图的自动编号 将光标放置在需要插入编号的位置点击“引用”→“题注”&#xff1a; 点击“引用”→“题注”&#xff1a; 点击“编号”&#xff0c;设置图的编号格式&#xff0c;可勾选“包含章节编号”&…

铁轨(Rails, ACM/ICPC CERC 1997, UVa 514)rust解法

有一个火车站&#xff0c;铁轨铺设如图6-1所示。有n节车厢从A方向驶入车站&#xff0c;按进站顺序编号为1&#xff5e;n。你的任务是判断是否能让它们按照某种特定的顺序进入B方向的铁轨并驶出车站。例如&#xff0c;出栈顺序(5 4 1 2 3)是不可能的&#xff0c;但(5 4 3 2 1)是…

【错误解决方案】ModuleNotFoundError: No module named ‘xgboost‘

1. 错误提示 在尝试导入名为xgboost的模块时出现了ModuleNotFoundError。 错误提示&#xff1a;ModuleNotFoundError: No module named xgboost 这个错误通常意味着Python环境中没有安装你试图导入的模块。 2. 解决方案 安装xgboost模块即可解决上述问题。 可以通过Python…

对音频文件的处理:音频信息,读取内容,获取时长,切割音频,pcm与wav互转

音频处理发现的比较简单的代码&#xff0c;原作者代码在github&#xff1a;GitHub - silencesmile/python_wav: 对音频文件的处理&#xff1a;音频信息&#xff0c;读取内容&#xff0c;获取时长&#xff0c;切割音频&#xff0c;pcm与wav互转 可以按给定的开始和结束时间调用代…

软件安利——火绒安全

近年来&#xff0c;以优化、驱动、管理为目标所打造的软件屡见不鲜&#xff0c;大同小异的电脑管家相继走入了公众的视野。然而&#xff0c;在这日益急功近利的社会氛围驱动之下&#xff0c;真正坚持初心、优先考虑用户体验的电脑管家逐渐湮没在了浪潮之中。无论是鲁大师&#…

Dockerfile文件自动化生成R4L镜像

Dockerfile文件自动化生成R4L镜像的步骤 1、安装Docker&#xff1a;2、使用Dockerfile一键生成镜像&#xff1a;3、查看生成的Docker镜像&#xff1a;4、删除Docker镜像&#xff1a;5、生成Docker容器&#xff1a;6、查看容器7、删除容器 1、安装Docker&#xff1a; curl -fsS…