自定义鉴权
概述
自定义鉴权是指用户可以通过函数工作流(FunctionGraph)服务实现自定义鉴权逻辑,以对接入平台的设备进行身份认证。
在设备接入物联网平台前,用户可以通过应用服务调用控制台配置自定义鉴权信息,然后通过调用函数工作流(FunctionGraph)配置自定义鉴权函数。在设备接入物联网平台时,物联网平台会获取设备ID和自定义鉴权函数名称等参数,并向FunctionGraph发起发起鉴权请求,由用户实现鉴权逻辑以完成设备的接入鉴权。

使用场景
- 迁移场景:当用户的设备从第三方云平台迁移到IoTDA平台时,存量设备可以依据现有的设备鉴权方式,在平台自定义配置设备的鉴权逻辑,以实现设备鉴权方式免改动迁移。
- 原生场景:用户有自定义实现鉴权逻辑的需求(比如:用户不同的设备有其自定义的认证方式),而无需依赖于平台默认的鉴权方式。
约束与限制
- 使用自定义鉴权功能,要求设备必须使用TLS同时支持SNI(Server Name Indication),SNI中需要携带平台分配的域名。
- 每个用户默认最多支持10个自定义鉴权的配置。
- 自定义鉴权的函数最大处理时间为5秒,5秒内函数没返回结果,则认为鉴权失败。
- 每个用户总鉴权请求的TPS限制参考产品规格说明,自定义鉴权为总鉴权TPS的50%(不包含设备自注册)。
- 若用户开启了缓存FunctionGraph的鉴权结果,则在相同参数下,函数服务的修改生效时间需在缓存超期后才能生效。
- 在所有的设备接入鉴权方式中,当满足自定义鉴权条件时(匹配到设备携带的自定义鉴权器名称或用户配置了默认自定义鉴权器),优先采用自定义鉴权方式进行设备接入。

自定义认证功能是为方便用户快速接入平台,免于设备侧改造。平台将使用您提供的鉴权模板进行鉴权,请合理审视认证方式的安全程度,避免使用弱校验或者免校验。由于您自定义模板安全程度过低造成的安全问题,平台将不承担任何安全责任。
使用说明
操作步骤
- 配置自定义鉴权函数:用户通过调用函数服务(FunctionGraph)创建自定义鉴权函数。单击控制台,搜索函数工作流FunctionGraph服务进入,创建函数。
图3 函数列表-创建函数图4 创建函数-参数信息
- 创建自定义鉴权:用户可以通过Console配置自定义鉴权信息,IoTDA负责自定义鉴权信息存库和进行相应的管理维护。用户最多支持配置10个自定义鉴权器。
图5 自定义鉴权-入口图6 自定义鉴权-创建鉴权
表1 自定义鉴权参数信息 参数名称
是否必选
描述
鉴权名称
是
自定义鉴权器名称。
鉴权函数
是
自定义鉴权器对应的函数名称,从1中FunctionGraph已经创建的函数列表中选取。
状态
是
激活停用参数,用于表示该鉴权是否为激活状态,默认为停用状态。若需使用该鉴权器,则应激活后才能生效。
签名认证
是
启动签名认证后,不满足签名要求的鉴权信息将被拒绝,以减少无效的函数调用,默认为开启。
token值
否
签名校验的token值,开启签名校验时使用,用于认证设备携带的签名信息是否正确。
公钥
否
签名校验的公钥,开启签名校验时使用,用于认证设备携带的签名信息是否正确。
是否默认自定义鉴权器
是
开启后,如果设备发起鉴权时的username没有携带authorizer_name参数,则默认使用此鉴权器。此处默认为不开启。
是否缓存
是
缓存开关,用于开启缓存FunctionGraph的鉴权结果,缓存时间为300分钟~1天,默认不开启。
- 设备发起鉴权请求:设备通过MQTT协议发起的CONNECT请求需携带username参数,该参数应包含自定义鉴权的相关可选参数。
- username格式如下。参数传值时需去掉大括号“{}”,username的每个参数需采用分隔符“|”分隔,各参数具体内容不要出现“|”,否则可能导致鉴权失败。
{device-identifier}|authorizer-name={authorizer-name}|authorizer-signature={token-signature}|signing-token={token-value} 示例: 659b70a0bd3f665a471e5ec9_auth|authorizer-name=Test_auth_1|authorizer-signature=***|signing-token=tokenValue
表2 username参数信息 参数名称
是否必选
描述
device-identifier
是
设备标识符,建议设定为设备id。
authorizer-name
否
自定义鉴权器名称,需要同用户配置的鉴权器一致。不携带鉴权器名称时,如用户配置了默认的自定义鉴权器,则使用自定义鉴权,否则使用原有的密钥/证书鉴权方式。
authorizer-signature
否
签名校验功能开启时,需要携带该参数。该参数由私钥和signing-token进行加密后获取。需与2中创建自定义鉴权时填写的鉴权名称保持一致。
signing-token
否
签名校验功能开启时,需要携带该参数。该参数为签名校验的token,需与2中创建自定义鉴权时填写的token值保持一致。
- authorizer-signature通过如下命令行获取:
echo -n {signing-token} | openssl dgst -sha256 -sign {private key} | openssl base64
表3 命令行参数解析 参数名称
描述
echo -n {signing-token}
使用echo命令将签名令牌(signing-token)的值输出,并使用-n参数去掉末尾的换行符。signing-token需与2中创建自定义鉴权时填写的token值保持一致。
openssl dgst -sha256 -sign
使用 SHA256 算法对输入的数据进行哈希处理。
{private key}
使用 RSA 算法加密的私钥,可传入.pem/.key格式的私钥文件。
openssl base64
将签名结果进行Base64编码,以便于传输和存储。
- username格式如下。参数传值时需去掉大括号“{}”,username的每个参数需采用分隔符“|”分隔,各参数具体内容不要出现“|”,否则可能导致鉴权失败。
- IoTDA处理鉴权请求:IoTDA收到鉴权请求时,会根据username的参数信息和自定义鉴权的配置来决策是否使用自定义鉴权方式。
- 判断username是否携带了自定义鉴权名称,如果有携带,则根据平台的自定义鉴权名称,去匹配鉴权器处理函数。如果没有携带,则使用用户配置的默认自定义鉴权器去匹配鉴权处理函数,若无匹配到则使用原有的密钥/证书鉴权方式。
- 检查用户是否开启了签名校验,如果开启了签名校验,则校验username携带的签名信息是否可以校验成功,校验失败则直接返回鉴权失败。
- 匹配到处理函数后,携带设备的鉴权信息(即5的入参event)并通过函数的URN(Uniform Resource Name,唯一标识函数。)向FunctionGraph发起鉴权请求。
- 用户实现鉴权逻辑:用户在1中通过FunctionGraph创建的处理函数中进行开发,函数的返回结果需要符合要求,函数使用示例及返回的JSON格式要求如下:
exports.handler = async (event, context) => { console.log("username=" + event.username); // 此处编写您的校验逻辑 // 返回的JSON格式(格式固定不变) const authRes = { "result_code": 200, "result_desc": "successful", "refresh_seconds": 300, "device": { "device_id": "myDeviceId", "provision_enable": true, "provisioning_resource": { "device_name": "myDeviceName", "node_id": "myNodeId", "product_id": "myProductId", "app_id": "customization0000000000000000000", "policy_ids": ["657a4e0c2ea0cb2cd831d12a", "657a4e0c2ea0cb2cd831d12b"] } } } return JSON.stringify(authRes); }
其中,函数的请求参数(即event,JSON格式)如下:
{ "username": "myUserName", "password": "myPassword", "client_id": "myClientId", "certificate_info": { "common_name": "", "fingerprint": "123" } }
表4 请求参数信息 参数名称
参数类型
是否必选
描述
username
String
是
MQTT协议中CONNECT消息的username字段,与3的username格式相同。
password
String
是
MQTT协议中CONNECT消息的password参数。
client_id
String
是
MQTT协议中CONNECT消息的clientId参数。
certificate_info
JsonObject
否
MQTT协议中CONNECT消息的设备证书信息。
表5 certificate_info证书信息 参数名称
参数类型
是否必选
描述
common_name
String
是
设备携带设备证书时,从设备证书中解析的commonName信息。
fingerprint
String
是
设备携带设备证书时,从设备证书中解析的指纹信息。
表6 返回参数信息 参数名称
参数类型
是否必选
描述
result_code
Integer
是
鉴权结果码, 返回200标识鉴权成功。
result_desc
String
否
鉴权结果描述信息。
refresh_seconds
Integer
否
鉴权结果的缓存时间,单位(s)。
device
JsonObject
否
认证成功时的设备信息。当设备信息中的设备ID不存在时,如果用户开启自注册设备自注册,则平台会根据设备信息自动创建对应的设备。
表7 device设备信息 参数名称
参数类型
是否必选
描述
device_id
String
是
参数说明:设备ID,自注册场景、非自注册场景都必选。全局唯一,用于唯一标识一个设备。如果携带该参数,平台将设备ID设置为该参数值;建议使用product_id + _ + node_id拼接而成。 取值范围:长度不超过128,只允许字母、数字、下划线(_)、连接符(-)的组合,建议不少于4个字符。
provision_enable
Boolean
否
参数说明:自注册开关,默认为false。
provisioning_resource
JsonObject
自注册场景必选
参数说明:自注册参数信息。
表8 provisioning_resource自注册参数信息 参数名称
参数类型
是否必选
描述
device_name
String
否
参数说明:设备名称,资源空间下唯一,用于资源空间下唯一标识一个设备。 取值范围:长度不超过256,只允许中文、字母、数字、以及_?'#().,&%@!-等字符的组合,建议不少于4个字符。
最小长度:1
最大长度:256
node_id
String
是
参数说明:设备标识码,通常使用IMEI、MAC地址或Serial No作为node_id。 设备标识码长度为1到64个字符,包含英文字母、数字、连接号-和下划线_。 注意:NB设备由于模组烧录信息后无法配置,所以NB设备会校验node_id全局唯一。 取值范围:长度不超过64,只允许字母、数字、下划线(_)、连接符(-)的组合,建议不少于4个字符。
product_id
String
是
参数说明:设备关联的产品ID,用于唯一标识一个产品模型,创建产品后获得。取值范围:长度不超过256,只允许中文、字母、数字、以及_?'#().,&%@!-等字符的组合,建议不少于4个字符。
最小长度:1
最大长度:256
app_id
String
是
参数说明:资源空间ID,该参数指定创建的设备归属到哪个资源空间。 取值范围:长度不超过36,只允许字母、数字、下划线(_)、连接符(-)的组合。
policy_ids
List<String>
否
参数说明:Topic策略ID。
图7 函数编写-部署 - FunctionGraph返回结果后,判断是否需要支持自注册功能,如果需要则触发设备的自动注册。自注册设备全部默认为密钥认证,密钥随机生成。IoTDA收到鉴权结果后,进行接下来的业务实现流程。