API令牌(STS)概述 v1.2

为了将众多的API数据源快速安全整合起来,客户可以通过我们的STS(SecurityToken Service,安全令牌服务)服务, API令牌STS是使用OIDC协议实现的API认证与授权解决方案,它将API认证授权集成到我们的IDaaS平台,生成密钥对后,即可快速导出公钥,更可以设定不同的认证方式,让移动及API应用的认证与授权更安全。

立刻获得基于token的身份校验方式,让自己的应用拥有和我们一样的身份安全等级。拥抱安全,告别长期不变的密码,或是固定设备ID等容易被捕获重放的认证方式。
说明 本文档默认你已经拥有了开发者权限,并已经阅读了 准备开发文档和 应用管理 文档。如果需要分配新的开发者权限的话,请联系 IT 管理员进行授权操作。

实现原理

STS服务要求开发的应用端和服务器端做出相应的修改。应用端(Web)不再直接向服务器端发送认证请求或索取资源,而是先往IDaaS的认证服务器(AS, Authentication Server)发送账号验证请求,IDaaS在向你的服务器验证成功后,会返回一个id_token作为身份令牌。向服务器发出请求的时候,就需要携带这个令牌以验证身份。

获取id_token

IDaaS的认证平台负责id_token的分发,需要进行认证的账号已经在IDaaS平台的情况下,也可以对用户的身份进行自己认证;如果IDaaS没有用户信息,不能自己进行认证,则需要传递到开发者的应用服务器,由应用服务器进行身份认证,并返回结果给IDaaS。具体流程如下图:

步骤分解:应用携带账号认证信息向IP
  1. IDaaS发出id_token申请,认证信息可以使用户名+密码,也可以是证书。
  2. IDaaS如果可以自行校验,直接根据情况返回校验结果以及id_token。如果不能自行校验,会将信息传递到应用服务器开发的接口,请求应用服务器对认证信息进行验证。
  3. 应用服务器验证完认证信息返回结果。
  4. IDaaS从应用服务器接收到验证成功或失败的结果,并根据情况返回id_token给应用。
说明 如果在创建STS应用的时候启用了Refresh Token,那么在最后一步从IDaaS认证服务器还会返回一个refresh_token给应用。应用可以将其存储起来,用来进行id_token过期并需要刷新的请求。

使用id_token

开发者需要对服务器需要被id_token保护起来的接口添加一个过滤器(filter)。只有通过了该过滤器验证的才可以访问。具体服务器端实现流程如下:

  1. 获取keyID:每次应用请求的时候会携带id_token,服务器的过滤器需要对其进行初步解析并获得keyID。
  2. 获取publicKey:keyID是密钥的全局唯一标识,我们需要使用这个keyID对应的公钥,来对id_token进行解密。如果这个keyID对应的公钥在应用服务器上有保存的话,无须再次申请直接使用。没有存储记录的话,那么需要用携带该keyID向IDaaS认证服务器请求得到公钥publicKey,并安全地保存到本地。
  3. 解密验证:使用公钥进行解密,如果成功的话,那么认证即成功,请求可以通过。

步骤分解:

  1. 开发的应用向应用服务器请求资源,携带从IDaaS认证服务器获取到的id_token。
  2. 应用服务器对id_token进行解析获得keyID,如果应用服务器本地没有与keyID对应的公钥,那么向IDaaS认证服务器请求。
  3. 应用服务器得到公钥。
  4. 应用服务器对id_token进行解密,在验证后通过过滤器,继续放行想要请求的资源,并返回给应用。

刷新id_token

如果添加的API令牌已经启用了Refresh Token功能,当id_token过期的时候,可以通过refresh_token去刷新换取一个新的id_token。

如果没有启用Refresh Token功能,那么过期后需要按照获取id_token的方式重新用身份认证信息去IDaaS获取。

步骤分解:

  1. 应用携带refresh_token向IDaaS进行刷新id_token请求
  2. IDaaS返回新的id_token给应用

申请STS应用

在开发之前,我们需要先申请一个STS应用,对应我们要开发的STS功能。

  1. 在开发者的后台管理系统中,选择左侧的列表中选择API令牌(STS),选择添加API令牌(STS)。如下图:
  2. 填写STS应用信息。如下图:
    表单字段名称 说明
    应用ID 默认生成的,应用的唯一标识
    OIDC KeyId 默认生成的唯一标识,在服务器端向IDaaS认证服务器请求获取公钥的时候会使用到
    应用名称 选择要添加的应用
    ID Token有效期 ID Token有效期,单位: 秒,默认7200(2小时)
    Refresh Token有效期 Refresh Token有效期, 单位: 天, 默认30
    启用Refresh Token 是否启用Refresh Token有效期
    可授权范围 接口可获取的参数
    备注信息 可选项,可以备注应用的相关信息
  3. 添加应用完成后,在操作中选择启用,确定后即可集成使用STS服务。如下图:
  4. 点击详细查看添加的STS应用的详细信息。如下图:

API

说明 文档中的“IDaaS-Base-URL”需要替换为当前访问地址的主域,文中接口地址前也都需要替换主域地址;接口地址中的版本号以当前使用系统版本为准,也可以查看开发者文档中右侧菜单顶部的接口版本。
  • 获取id_token

    应用端使用,用于从IDaaS认证服务器获取 OIDC 的 id_token。

    Request URI: /api/public/bff/" + API_VERSION + "/sts/retrieve_id_token POSTREST

    Content-Type:application/json

    请求参数:

    参数名 参数值 备注
    appKey {appKey} STS应用中的 appKey
    appSecret {appSecret} STS应用中的 appKey
    username {username} IDaaS账户名
    password {password} IDaaS账户密码
    请求Body示例:
    {"username":"zhangsan","refresh_token":"dK4ljtYf9TWTQX7Mgwi39Ol9p5H4md88kcgnL5nl2cChNdAn14mGNelA8CRLgHJK"}

    响应:

    {"statusCode":0,"errors":[],"id_token":"eyJhbGciOiJSUzI1NiIsImtpZCI6IjY2...","refresh_token":"Z0zGd07UFFcAL6AgOYGn...","successful": true}

    statusCode为0表示成功,HTTP响应码为401(Unauthorized)则表示失败,具体为:400表示请求参数错误,483表示系统未找到refresh_token数据,484表示refresh_token已过期,501表示账户名错误,479表示应用不再支持 refresh_token 操作。

  • 通过refresh_token刷新id_token

    应用端使用,用于从IDaaS通过refresh_token获取id_token

    Request URI: /api/public/bff/" + API_VERSION + "/sts/refresh_id_token POST

    Content-Type: application/json

    请求参数:

    参数名 参数值 备注
    username {username} IDaaS账户名
    refresh_token {refresh_token} 获取id_token时返回的refresh_token
    请求Body示例:
    {"username":"zhangsan","refresh_token":"dK4ljtYf9TWTQX7Mgwi39Ol9p5H4md88kcgnL5nl2cChNdAn14mGNelA8CRLgHJK"}
    响应:
    {"statusCode":0,"errors":[],"id_token":"eyJhbGciOiJSUzI1NiIsImtpZCI6IjY2...","refresh_token":"Z0zGd07UFFcAL6AgOYGn...","successful": true}

    statusCode为0表示成功,HTTP响应码为401(Unauthorized)则表示失败,具体为:400表示请求参数错误,483表示系统未找到refresh_token数据,484表示refresh_token已过期,501表示账户名错误,479表示应用不再支持 refresh_token 操作。

  • 通过keyId获取OIDC Public Key

应用服务器端使用,用于从IDaaS通过keyId获取OIDC Public Key公钥。

Request URI: /api/public/bff/" + API_VERSION + "/sts/public_key_{keyId} GET

请求参数:

参数名 参数值 备注
keyId {keyId} API应用的 keyId
请求示例:
http://sz.idp-local.com/api/public/sts/public_key_d037e0cbf59042d09ed4609127a37ff5pbb8c5dwEn8
响应:
{"statusCode":0,"errors":[],"publicKey":"eyJrdHkiOiJSNjd2NE5ZbtZDRBbzRZaUVFBUTMtRGdTaVB0ekdtRkZ...","successful":true}
说明 提示: 返回的publicKey是Base64 Encoded,使用时需要先调用Base64 Decoded。

statusCode为0表示成功,HTTP响应码为401(Unauthorized)则表示失败,具体为: 233表示未找到对应的keyId,482表示应用尚未启用。

移动端集成

Android集成指南

  1. 在项目libs文件夹中加stslib,并在Android studio的build.gradle添加:
    compile 'com.squareup.okhttp3:okhttp:3.3.1'
    compile 'com.google.code.gson:gson:2.4'
    compile files('libs/stslib1.0.jar')
  2. 在您的应用的AndroidManifest.xml中,申请访问网络权限:
    <uses-permission android:name="android.permission.INTERNET"/>
  3. 在Application中,初始化SDK:
    STS.init(getApplicationContext());
  4. 如何使用SDK:
    1. 调用jar中的方法请求idToken:
      STS.getInstance().getIdToken(headUrl, appKey, appSecret, username, password, listener)
      * @param headUrl   请求地址头部
      * @param listener  请求接口TokenCallBack回调,若有界面操作,需要在接口回调中开启子线程处理
      * @param appKey    STS应用的appkey
      * @param appSecret appSecret
      * @param username  用户名
      * @param password  用户密码

      在接口回调返回中带有idToken,refreshToken和errorCode

    2. idToken过期后,调用jar中的方法刷新idToken:
      STS.getInstance().refreshIdToken(headUrl, refreshToken, username,listener)
      * @param headUrl   请求地址头部
      * @param listener  请求接口TokenCallBack回调,若有界面操作,需要在接口回调中开启子线程处理
      * @param refreshToken refreshToken,用来获取新的id_token
      * @param username  用户名

      在接口回调返回中带有idToken,refreshToken和errorCode

  5. 代码混淆:
    -keep class com.idsmanager.stslibrary.** {*;}
    -dontwarn com.idsmanager.stslibrary.**

iOS集成指南

  1. 导入STSFramework包到工程目录下
  2. 在Targets - General 中下方有一栏叫做Embedded Binaries,将我们的STSFramework添加进去:
    1. 点击下方的 + 号
    2. 在Frameworks中选取STSFramework
    3. 成功将STSFramework添加到Embedded Binaries中
      注意 如果没有配置这步会导致程序运行失败
  3. 获取id_token:

    传入用户名、密码、appKey、appSercert,获取id_token

    /**
    * @brief 获取id_token.
    * @param config 配置参数
    * requestURL:请求地址
    * username:用户名
    * password:密码
    * appKey:web端申请应用成功后,可在详细页面查看
    * appSercert:web端申请应用成功后,可在详细页面查看
    * success 返回获取的结果,详情可以查看错误码介绍.
    * failure 返回失败的原因.
    */
    调用示例:
    STSSDK.requestId_token(requestURL: "\(self.serverIp.text!)/api/public/sts/retrieve_id_token", username: self.username.text!, password: self.password.text!, appKey: "4dbfb4bfe9bb43f386d473e789db6776eIE2sxJlE7b", appSercert: "sVWx3VGXD5qmHTBvM6lWcFvOJOUHh5UTllrc7Z8FPr", success: { (result) in
        DispatchQueue.main.async(execute: {
           //刷新UI回到主线程
            print(result)
        })
    
    }) { (error) in
        Global.hideProgressHUD()
        print(error)
    }

    启用refresh_token选项成功响应响应:

    {"statusCode": 0, "id_token": eyJhbGciOiJSUzI1NiIsImtpZCI6IjJk..., "refresh_token": etlRa2LoK4tX32d..., "successful": 1, "errors": []}

    未启用refresh_token选项的成功响应:

    {"statusCode": 0, "id_token": eyJhbGciOiJSUzI1NiIsImtpZCI6IjJk..., "successful": 1, "errors": []}
  4. 刷新id_token:

    传入用户名、密码、appKey、appSercert,获取id_token

    /**
    * @brief 刷新id_token.
    * @param config 配置参数
    * requestURL:请求地址
    * username:用户名
    * refresh_token:第一次获取id_token会返回,用于刷新id_token
    * success 返回获取的结果,详情可以查看错误码介绍.
    * failure 返回失败的原因.
    * @return 返回获取的结果,详情可以查看错误码介绍.
    */
    调用示例:
    STSSDK.refreshId_token(requestURL: "\(self.serverIp)/api/public/sts/refresh_id_token", username: "86627161@qq.com", refresh_token: self.refreshToken, success: { (result) in
        DispatchQueue.main.async(execute: {
          //刷新UI回到主线程
            print(result)
        })
    }) { (error) in
        print(error)
    }

    启用refresh_token选项成功响应响应:

    {"statusCode":0,"errors":[],"id_token":"eyJhbGciOiJSUzI1NiIsImtpZCI6IjY2...","refresh_token":"Z0zGd07UFFcAL6AgOYGn..."}

错误码

  • Android错误码

    errorCode 备注
    1 网络出错
    2 服务器出错
    400 请求参数错误
    479 应用不支持refresh_token
    480 appKey或者appSecret错误
    481 生成idToken时出错
    482 应用没有启用
    483 refresh_token没有找到
    484 refresh_token过期
    501 用户名或密码错误(在刷新idToken时,表示用户名错误)
  • iOS错误码

    errorCode 备注
    1400 参数错误
    1401 用户名密码错误
    1402 appKey或appSecret错误
    1403 应用没有启用
    1404 应用不支持refresh_token
    1405 生成idToken时出错
    1406 refresh_token错误或不存在
    1407 refresh_token过期
    1408 未知错误

常见问题

Q:iOS为什么导入包之后,运行程序崩溃?

A:在Targets - General 中下方有一栏叫做Embedded Binaries,将我们的STSFramework添加进去。

Q:Android在使用jar中的方法时,为啥会出现“stslibrary's context is null , please initialize STS's context. eg:STS.init(context)!”错误信息?

A:请在您的Application继承类中初始化STS.init(context)。