企企提供两种openapi接入方式, 分别是openid接入和OAuth2接入,可以根据需要自行选择接入方式。
1. openid 接入
1.1. 名词解释
- openid:openid代表一个企业的一个用户身份,调用接口时需要带上openid,以用户身份请求接口, openid长期有效
callBackUrl:callbackUrl 是开发者用来接收企企提供的openid,callbackUrl支持GET请求,响应200,开发者可选择性的提供给企企,由企企管理员设置,用户授权后,我们的请求为
GET callbackUrl?openid={openid}&requestId={requestId}
1.2. 调用openApi接口流程
使用openid接入调用openapi 接口流程大致分为3部分
- 获取密钥
- 获取openid
- 接口调用
1.2.1. 获取密钥
密钥仅需要获取一次,开发者线下将应用名称提供给企企管理员,企企管理员收到应用名称后,将密钥线下发送给开发者。
应用名称:对接的外部应用名称,将显示在授权页面,下图中的‘云峰社区’为应用名称
秘钥示例:
accessKeyId=LKJSDAFJLSKDJFK // 拿到授权的秘钥id
secretAccessKey=vkDB632ibwjasdiufjVc6ebJVD+Inq //拿到授权的秘钥
1.2.2. 获取openid
获取openid 需要用户先授权,授权只需要成功一次,授权地址:https://openapi.77hub.com/auth/openid?requestId={requestId}&accessKeyId={accessKeyId}&grantType={grantType}&redirectUrl={redirectUrl}
授权地址请求参数说明
参数名 | 是否必填 | 说明 | 获取方式 |
---|---|---|---|
requestId | 是 | 授权成功后,requestId会根据对应的 grantType响应到对应的url上 | 用户自己指定;格式为:数字+英文(A-Z,a-z,0-9),64位之内 ,例如 KLJOISUVMDIE9231JV |
accessKeyId | 是 | 密钥Id | 从企企管理员那里获取到的accessKeyId |
redirectUrl | 否 | 重定向地址,用于用户授权后重定向到redirectUrl | 调用者自己指定 ,例如 http://openapi.test.com |
grantType | 否 | normal模式(默认),code模式 ,任选其中一种模式 | 见下 |
说明:多次请求同一个企业的同一个用户授权,获取到的openid不变
normal模式获取openid
- normal模式:开发者在用户授权前向企企管理员提供callbackUrl,在用户授权后,企企服务端回调开发者提供的callBackUrl, 将openid和requestId响应到callbackUrl,然后前端重定向到redirectUrl
normal模式授权流程图:
- 假设开发者构建的授权链接是:https://openapi.77hub.com/auth/openid?requestId=6ca40cade0f4b77a7873d76411229916&accessKeyId=AKIAYOSUOUKK3D7LKOVS&redirectUrl=https://yunfeng.77hub.com/authLogin&grantType=normal
- 假设开发者提供的callbackUrl是 : https://openapi.77hub/openid
- 在用户授权完成后企企服务端发起GET请求: https://openapi.77hub/openid?openid=88caf24007444cd1b90fbf2&requestId=6ca40cade0f4b77a7873d76411229916, 前端重定向到:https://yunfeng.77hub.com/authLogin
code模式获取openid
- code模式:用户授权后,前端会重定向到redirectUrl,code和requestId作为redirectUrl的参数,开发者根据code调用企企提供的 v1/code 接口获取openid, code使用后即失效,否则有效期为24小时
code 模式授权流程图:
在用户授权完成后前端重定向到:https://yunfeng.77hub.com/authLogin?code=5db33b05cebe470d8bb74a65506fb0df&requestId=6ca40cade0f4b77a7873d76411229916
根据重定向返回的code 获取openid
1.2.3. openid接入接口调用
- 说明:接口调用要获取签名Authorization,使用sdk无需关注签名,否则请主动签名
2. OAuth2 接入
2.1. 调用openApi接口流程
使用OAuth2接入调用openapi 接口流程大致分为3部分
- 获取id_token/access_token
- 刷新id_token/access_token
- 接口调用
2.1.1. 获取id_token/access_token
步骤1:租户管理员/或者开发角色登录idps系统, 新建自建应用
- 应用类型: 自建应用
- 应用名称: 起一个容易识别的名称(比如: 外部测试系统)
- 应用所属IDP标识: 在idps中的唯一标识,要求为英文字母开始,标识当前自建应用,比如: testapp1
- logoUrl: 应用的图标, 可以不设置
- 重定向的url: 必须设置登录成功后, 回调第三方系统的callback url
idps系统地址:https://idps.77hub.com
接着需要记录新建应用的API Key 和Secret Key
自建应用如下图所示:
步骤2: 获取Authorization Code
外部系统通过IDPS获取token访问企企管理云Open API时, 需要通过重定向用户浏览器到 https://idps.77hub.com/idps/auth 地址,并带上以下参数:
client_id:必要参数,注册应用时获得的API Key。
response_type:必要参数,此值固定为“code”。
redirect_uri:必要参数,授权后要回调的URI,即接收Authorization Code的URI。redirect_uri必须与步骤一中的重定向url中的某一个相匹配。
scope:必要参数,以空格分隔的权限列表,目前idps支持的scope如下:
- offline_access: 离线访问,会返回refresh_token
- openid: 返回id token
- email: 返回email和phone信息
- profile: 返回用户名称等信息
state:非必要参数,用于保持请求和回调的状态,授权服务器在回调时(重定向用户浏览器到“redirect_uri”时),会在Query Parameter中原样回传该参数。OAuth2.0标准协议建议,利用state参数来防止CSRF攻击。
例如:client_id为n1pRXWNYFa4MQLzpDfHyovFb的应用要请求某个用户的默认权限,并在授权后需跳转到http://localhost:8080/login,同时希望在弹出窗口中展现用户登录、授权界面,则应用需要重定向用户的浏览器到如下URL:
https://idps.77hub.com/idps/auth?client_id=n1pRXWNYFa4MQLzpDfHyovFb&redirect_uri=http://localhost:8080/login&response_type=code&scope=openid offline_access,
响应数据包格式:
此时授权服务会根据应用传递参数的不同,为用户展现不同的授权页面。如果用户在此页面同意授权,授权服务则将重定向用户浏览器到应用所指定的redirect_uri,并附带上表示授权服务所分配的Authorization Code的code参数,以及state参数(如果请求authorization code时带了这个参数)。
例如:继续上面的例子,假设授权服务在用户同意授权后生成的 Authorization Code 为71c279ccd145a3dff977b38e6a8e34b4,则授权服务将会返回如下响应包以重定向用户浏览器到http://localhost:8080/login地址:
HTTP/1.1 302 Found Location: http://localhost:8080/login?code=71c279ccd145a3dff977b38e6a8e34b4
注意:每一个Authorization Code的有效期为30分钟,并且只能使用一次,再次使用将无效。
步骤3: 通过Authorization Code获取id_token/access_token
通过上面第一步获得Authorization Code后,便可以用其换取id_token/access_token。获取方式是:应用在其服务端程序中发送请求(推荐使用POST)到 IDPS授权服务的https://idps.77hub.com/idps/token地址,并带上以下5个必须参数:
grant_type:必须参数,此值固定为authorization_code。
code:必须参数,通过上面第一步所获得的Authorization Code。
client_id:必须参数,应用的API Key。
client_secret:必须参数,应用的Secret Key。
redirect_uri:必须参数,该值必须与获取Authorization Code时传递的redirect_uri保持一致。
响应数据包格式:
若参数无误,服务器将返回一段JSON文本,包含以下参数:
access_token:要获取的Access Token。
expires_in:Access Token的有效期,以秒为单位(默认60分钟的有效期)。
refresh_token:用于刷新Access Token 的 Refresh Token。
refresh_token_expires_in:Refresh Token的有效期,以秒为单位(默认7天的有效期,刷一次access token会自动继期)。
id_token: JWT格式的ID Token信息
例如:
{
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImVkYTk3N2Q1NWQwYzJiYzY0ZmQxNTZhYmNkZjc1YWQzNWZjNDZlOWUifQ.eyJpc3MiOiJodHRwOi8vdGVzdC5jb206ODA4MC9pZHBzIiwic3ViIjoiQ2dkMWMyVnlhV1F5RWc5Qk4wTldOekkyTVZBMU9ERXdNREkiLCJhdWQiOiJ0ZXN0LWFwcCIsImV4cCI6MTY4MTEwMjYxMiwiaWF0IjoxNjgxMDk5MDEyLCJhdF9oYXNoIjoiTjM4SXZJMkpFRWRpbTYzOU9RUnZtUSIsImVtYWlsIjoid29sZi5qaWFuZ0A3N2h1Yi5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwicGhvbmVfbnVtYmVyIjoiKzg2MTU2OTk3MzY3MzYiLCJwaG9uZV9udW1iZXJfdmVyaWZpZWQiOnRydWUsIm5hbWUiOiJ0ZXN0IiwicHJlZmVycmVkX3VzZXJuYW1lIjoidGVzdCIsInRlbmFudF9pZCI6InRlbmFudDIiLCJyX2lkIjoiZHZnN2VzcW1uYmVuajJ1NTJrdmtlYXFpcSIsImlzX2Rldl9tYW5hZ2VyIjp0cnVlfQ.QGjUAkMzuBOHZPpK2qM1Qkz6y_2ZUMSg_Ka2YHc8Vi_L19Yr8EyeL7hrd7yZSAs47GPOCF5xUZLA7CzfSAVRDqbuL8LktZYD2-SwCwbtOsZbJVd_rVl1N6hRIiEs6FJwsYUiNA9Xgag-3MLrnfJMUSy5A6AN0AidpCfwYjAaEEaca-lyGlVXv0A1U3hx3JmBzRgNGmNZhlHuI1HHQUNEfQnqLy74JF416Irl_1TQjmdzLkJYVp7dvuuvvVfbSEHZS1C0bKaYbfASFi62UWHLrCdjHYPgIYgUcvQZdtryg4JjMfU1bTxP4kBhdoGsUR1O17izmyX_i3oyknyJhUn7aw",
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImVkYTk3N2Q1NWQwYzJiYzY0ZmQxNTZhYmNkZjc1YWQzNWZjNDZlOWUifQ.eyJpc3MiOiJodHRwOi8vdGVzdC5jb206ODA4MC9pZHBzIiwic3ViIjoiQ2dkMWMyVnlhV1F5RWc5Qk4wTldOekkyTVZBMU9ERXdNREkiLCJhdWQiOiJ0ZXN0LWFwcCIsImV4cCI6MTY4MTEwMDMxNSwiaWF0IjoxNjgxMDk2NzE1LCJhdF9oYXNoIjoicENScEtVU1pITE1tNkV5MGJQZWpiQSIsImVtYWlsIjoid29sZi5qaWFuZ0A3N2h1Yi5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwicGhvbmVfbnVtYmVyIjoiKzg2MTU2OTk3MzY3MzYiLCJwaG9uZV9udW1iZXJfdmVyaWZpZWQiOnRydWUsIm5hbWUiOiJ0ZXN0IiwicHJlZmVycmVkX3VzZXJuYW1lIjoidGVzdCIsInRlbmFudF9pZCI6InRlbmFudDIiLCJyX2lkIjoiaGF2NmtjZmdpZWhyN2dzMmJjdTN5eG9uaSIsImlzX2Rldl9tYW5hZ2VyIjp0cnVlfQ.G5Ur2dCwBlCow7F1rgwiCaBTnPzOzNxZcq7TjuU66GViS-vxMI4nwsPdPnuNYy8dmfj4h8nkInpUBFiM3xMkPqnDqqyFqxxyPNrmmQcgY3Y6mjoChD6GjULvm01PpeQBrsrCvxwGzichEHKSfmqVyQCgkBRDQopfMOe6KRWZemHFQbAt5dfIkSrpsWpk1SZQ0b5AZ9b5s186pVwGnzVgLNzKGz47HWZSxEKLO4Xa-2SKj0CykMR9pePrHq7x-U0KfY00oRdQDgKxmA0-uqN6CirIjHe5_qUic_5YckuZ252hWvjH_d0brDXfl043ObA1I1CIbvPFWgc03QAyEWZ0Eg",
"expires_in": 3599,
"refresh_token": "ChloYXY2a2NmZ2llaHI3Z3MyYmN1M3l4b25pEhllamJqdDJzYW11dG5ubHF5bWFjZjJjZzV2",
"refresh_token_expires_in": 604799
}
若请求错误,服务器将返回一段JSON文本,包含以下参数:
error:错误码。
error_description:错误描述信息,用来帮助理解和解决发生的错误。
https://idps.77hub.com/idps/token接口postman请求示例如下:
2.1.2. 刷新id_token/access_token
取得id_token/access_token和refresh_token信息,通过id_token/access_token即可访问OpenAPI接口;当id_token/access_token过期时(默认有效期为60分钟), 需要使用refresh_token(refresh_token默认有效期为7天,使用后失效)来刷新id_token/access_token,会返回id_token/access_token/refresh_token等信息,下次刷新id_token/access_token要使用新返回的refresh_token
刷新id_token/access_token方式是:应用在其服务端程序中发送请求(推荐使用POST)到 IDPS授权服务的https://idps.77hub.com/idps/token地址,并带上以下4个必须参数:
grant_type:必须参数,此值固定为refresh_token
client_id:必须参数,应用的API Key。
client_secret:必须参数,应用的Secret Key。
refresh_token:必须参数,以上获取到到refresh_token。
响应数据包格式:
若参数无误,服务器将返回一段JSON文本,包含以下参数:
access_token:要获取的Access Token。
expires_in:Access Token的有效期,以秒为单位(默认60分钟的有效期)。
refresh_token:用于刷新Access Token 的 Refresh Token。
refresh_token_expires_in:Refresh Token的有效期,以秒为单位(默认7天的有效期,刷一次access token会自动继期)。
id_token: JWT格式的ID Token信息
例如:
{
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImFiZWRmYjg5MGRkYWM4YzhjODExNjE3ZjJlOTRjNDM0YmIzNjRmZmMifQ.eyJpc3MiOiJodHRwczovL2lkcHMuNzdodWIuY29tL2lkcHMiLCJzdWIiOiJDZzg0TjB0VlZsTTFNRVZEUnpBd01sWVNEMEUzUTFZM01qWXhVRFU0TURBd01RIiwiYXVkIjoiamVtb21vb2Nmd3h0bzY1Nnp3bG5oMm10ciIsImV4cCI6MTY4MjMyOTYxNywiaWF0IjoxNjgyMzI2MDE3LCJhdF9oYXNoIjoiRlRXXzlZSmc1VXg0Y3hzdDZHaDU1QSIsInRlbmFudF9pZCI6IldCOFExUDUwNTZWMDAwMSIsInJfaWQiOiJjaDMyZ3Q1dmN1MXBxOTNrOWpoZyIsImlzX2Rldl9tYW5hZ2VyIjp0cnVlfQ.qjYvnV3Av5r8MRXr7iQqou-S9sxpLOzFmTgu72gYSdPdDV4Ol6wsyEYVbtkfPHnvURLITnKynitm-dhRNH4aPky75OUCgTlmEAcxoE80TLbhaYa5OYBoKfvwz6Hdf7KyXaTlGusrwGMbGjvJarBJwIleJ9WsFO30XOmkcLVP-_Oy40p-v362RJcaoCZUU75Sue1IVNNRxrCxiAmzp-5L3ddHikRJPwibHkXSJjXCWNXfgGo6r4SNF-f79YLJ9RU6rD8KopoZ6xbugJeq7IB6TeAvbuw68QVW6zzs6xNv0thjheZWJ-sMFNfmmD_nBLpS1hoDY131mqr53VwwCpYxfQ",
"token_type": "bearer",
"expires_in": 3599,
"refresh_token": "ChRjaDMyZ3Q1dmN1MXBxOTNrOWpoZxIZbGZsbW9sZXh3YWFzZ2ZraWJ1c2x0cWRhZg",
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImFiZWRmYjg5MGRkYWM4YzhjODExNjE3ZjJlOTRjNDM0YmIzNjRmZmMifQ.eyJpc3MiOiJodHRwczovL2lkcHMuNzdodWIuY29tL2lkcHMiLCJzdWIiOiJDZzg0TjB0VlZsTTFNRVZEUnpBd01sWVNEMEUzUTFZM01qWXhVRFU0TURBd01RIiwiYXVkIjoiamVtb21vb2Nmd3h0bzY1Nnp3bG5oMm10ciIsImV4cCI6MTY4MjMyOTYxNywiaWF0IjoxNjgyMzI2MDE3LCJhdF9oYXNoIjoiT3NSVTAtSWdORE52dTJxNENXRFczdyIsInRlbmFudF9pZCI6IldCOFExUDUwNTZWMDAwMSIsInJfaWQiOiJjaDMyZ3Q1dmN1MXBxOTNrOWpoZyIsImlzX2Rldl9tYW5hZ2VyIjp0cnVlfQ.DFF5P4cnkfwGdMVtGeS_W6-sA7tV8V_4nPwqXbNqmJtedheRLMkr2OD0ph5buurj5Ed5b8Xd0_fhNcUY9AxsSz0zY2SSOokK4NU7i49QLZxkkJDOkoHxHITVVv42ilaJsE090RM6lGGj9LP3qdLFEmLteo4_dpapz9_3DHeHQSulV8JvfQbfH3F94OOXXpFidRfXA8HruuQrI9_zjsDDG5mPyeiuyiywkdkZ3x0_6algBHzQ0nhumqzyP9juIsHc_5QQ7jscHsjGTikwldlCpdgqjAn4wAKC-PBnPGc6OQcHdKMj4ffv_Qpi4i-Xb3rPJdHlfPTF9Rh7EmBIs06FWw",
"refresh_token_expires_in": 604799
}
若请求错误,服务器将返回一段JSON文本,包含以下参数:
error:错误码。
error_description:错误描述信息,用来帮助理解和解决发生的错误。
2.1.3. OAuth2接入接口调用
postman 接口调用示例:
curl示例:
curl --location 'https://api2.77hub.com/v2/list' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImI3YTIzM2FmMTJjZGQ0MThhMWVjMGQyYmQyZmU0OTRkNzA4ZDUzZWYifQ.eyJpc3MiOiJodHRwczovL2lkcHMuNzdodWIuY29tL2lkcHMiLCJzdWIiOiJDZzg0TjB0VlZsTTFNRVZEUnpBd01sWVNEMEUzUTFZM01qWXhVRFU0TURBd01RIiwiYXVkIjoibG9jYWx3ZWIiLCJleHAiOjE2ODI1ODM2ODUsImlhdCI6MTY4MjU4MDA4NSwiYXRfaGFzaCI6Ijlkb1VPSWNfTVBYSEE0eTlwcGstS0EiLCJjX2hhc2giOiI2OGI4ZjhlellkVXJGM2MtQ3B2VEV3IiwiZW1haWwiOiJsYW4uc2hhbkA3N2h1Yi5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwicGhvbmVfbnVtYmVyIjoiKzg2MTM5MTEyOTYzMDEiLCJwaG9uZV9udW1iZXJfdmVyaWZpZWQiOnRydWUsIm5hbWUiOiLljZXlspoiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiLljZXlspoiLCJ0ZW5hbnRfaWQiOiJXQjhRMVA1MDU2VjAwMDEiLCJyX2lkIjoiY2g1MjR0ZnM5OGNyMHBnZHV1ZjAiLCJpc19kZXZfbWFuYWdlciI6dHJ1ZX0.sOI5wY_btSBhLGivPGdBemf0dLZ29zLxSL6zWAJ7aKRxmXDXzy7FGq0xJ6lLo7bncRys7ZIgQZ3ZYz3vHY59bOo70rkE1bCGS_OYeiKNebLU2UIMFj-PTAGShMDZhyfCXqa37_SCmEtwBURfIqgT5vUU4X7JxTbHEztNBYXuVhAkJTDB6LTCOD81NDRj-Kf6uRxJf_vym7EniADaOW3qij_S6tgVUoAeBTChddZrVQcZMmPO-m5DrYkwFsFVpCN-4mHlN3EQLxNkglBNSA8orZTMvrfUSd66wmYITVSUjeUnVKX1EMVUmvgO1ibleSnsF-g2_UcjBO8jkRpN7gj8tg' \
--header 'Content-Type: application/json' \
--data '{"json":"{\n\"objectType\":\"Customer\",\n\"criteriaStr\":\"id is not null\",\n\"fields\":[\n\"id\",\n\n{\n \"fieldName\":\"category\",\n \"fields\":[\n \"id\",\n \"name\"\n ]\n },\n {\n \"fieldName\":\"contacts\",\n \"fields\":[\n \"id\",\n \"name\"\n ]\n },\n \"code\"\n ]\n}"}'