6 第三方应用集成技术规范
第三方应用通过实现OAuth方式接入云平台后,云平台用户在应用商店中通过点击应用图标(链接)访问业务系统,业务系统通过云平台提供的appid以及密钥,按照OAuth标准流程请求授权以及相关资源。
6.1 依赖包
commons-codec-1.3.jar commons-httpclient-3.1.jar commons-logging-1.1.1.jar httpclient-4.1.3.jar jstl-1.2.jar log4j-1.2.17.jar openapi-sdk.jar |
其中openapi-sdk.jar请参考源码实例。
6.2 相关说明
API调用的必备参数,需在应用集成前通过平台运营方提前获取,除调用入口地址外,还包括AppKey、AppSecret、Access Token(或SessionKey)。AppKey、Appsecret在从管理平台创建该应用时获得;Access Token则通过登录账号授权方式(详细请参考下一节用户授权介绍)取得;取得这些数据后可进行API 调用,获取相应的用户数据。
使用平台用户登录第三方应用系统,通过OAuth服务完成授权之后,需要获取用户隐私信息(如:用户账户信息、用户身份信息等),为保证用户数据的安全性与隐私性,第三方应用系统应取得用户的授权{即Access Token(授权令牌)}。在这种情况下,第三方应用系统应引导用户完成使用平台帐号“登录授权”的流程。
该流程采用国际通用的OAuth2.0标准协议作为用户身份验证与授权协议,支持网站、手机客户端、桌面客户端。
6.2.1 授权码模式
此授权方式要求第三方应用系统的独立软件开发商(ISV)有Web Server应用,能够保存应用本身的密钥以及状态,可以通过https直接访问平台的授权服务器。
6.2.2 授权操作步骤
以获取acccess_token为例说明,如果是环境测试,应将请求入口地址等相关数据换成对应入口地址,授权操作流程则同正式环境一致。
实际进行授权操作时,授权参数client_id(应用ID)、client_secret(应用密钥)均需根据ISV在平台中创建应用时所分配的实际数据为准进行替换使用,不应使用示例中给出的值直接进行测试,以免影响实际测试效果。
1) 拼接授权URL
用户通过青岛教育e平台访问目标应用链接(集成应用的requestLogin的地址示例:http://www.example.com/OAuth_client/requestLogin),应用在相应的后台filter类生成“授权地址”发起访问,来引导用户授权,并获得authorization_code。
参数列表:
参数名称 |
参数说明 |
client_id |
必选参数,应用的唯一标识,对应于应用ID |
redirect_uri |
必选参数,用户授权完成后的回调地址,应用需要通过此回调地址获得用户的授权结果。此地址必须与在应用注册时填写的回调地址一致。 |
response_type |
必选参数,此值可以为 code 或者 token 。在本流程中,此值为 code |
scope |
可选参数,申请权限的范围,如果不填,则使用缺省的应用默认申请的服务列表。 |
state |
可选参数,用来维护请求和回调状态的附加字符串,在授权完成回调时会附加此参数,应用可以根据此字符串来判断上下文关系。 |
(2) 授权服务会判断当前会话信息,如果已登录,则会跳转到授权页面引导用户授权;未登录系统会跳转到云平台用户登录页面,输入管理公共服务平台账号密码,点击登录进行账号验证。
(3) 验证通过之后,获取autorization_code,再跳转到用户授权页面,当用户拒绝授权时,浏览器会重定向到redirect_uri,并附加错误信息,示例如下:
http://www.example.com/back?error=access_denied |
在引导登录用户授权页面,当用户同意授权时,浏览器会重定向到redirect_uri,并附加autorization_code,示例如下:
http://www.example.com/back?code=45aEq |
(4) 换取AccessToken
换取AccessToken地址示例如下:
http://www.example.com/auth/OAuth/token |
上述地址传入参数列表:
参数名称 |
参数说明 |
client_id |
必选参数,应用的唯一标识,对应于应用ID |
client_secret |
必选参数,应用的唯一标识,对应于应用密钥 |
redirect_uri |
必选参数,用户授权完成后的回调地址,应用需要通过此回调地址获得用户的授权结果。此地址必须与在应用注册时填写的回调地址一致 |
grant_type |
必选参数,此值可以为 authorization_code 或者 refresh_token 。在本流程中,此值为 authorization_code |
code |
必选参数,上一步中获得的authorization_code |
注意:此请求必须是HTTP POST方式,例如:
http://www.example.com/auth/token? client_id=2356&client_secret=edfc4e395ef93375& redirect_uri=https://www.example.com/back&grant_type=authorization_code&code=45aEq |
返回结果:
{ "access_token":"a14afef0f66fcffce3e0fcd2e34f6ff4", "expires_in":3920, "refresh_token":"5d633d136b6d56a41829b73a424803ec", "scope":["/a/b/2.0","/weather/bj/1.1"] } |
返回结果参数说明:
参数名称 |
参数说明 |
access_token |
应用授权码 |
expires_in |
表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。 |
refresh_token |
表示更新令牌,用来获取下一次的访问令牌,可选项 |
scope |
表示权限范围,如果与客户端申请的范围一致,此项可省略 |
6.3 开发示例
以第三方应用中采用青岛教育e平台账号登陆为例,通过验证青岛教育e平台中实名制账户信息,获取青岛教育e平台中用户的相关资料。
首先,需要向开发者中心进行注册,登陆到 http:// 27.221.57.93:8081/oam。
配置参数说明(此配置环境为测试环境):
##应用id client_ID = 5427 ##应用密钥 client_SERCRET = 67ad2626894b237fdcc2dc89ccbe1fa5 ##回调地址,sdk读取 redirect_URI =http://www.example.com:8080/OAuth_client/callback ##应用首页,应用自己读取 app_URL = index.jsp ##widget首页(地址可为空) widget_URL = ######以下内容不需要修改############## #获取用户信息 baseURL = http://www.example.com/auth/api #获取令牌 accessTokenURL = http://www.example.com/auth/OAuth/token #请求授权 authorizeURL =http://www.example.com/auth/OAuth/authorize |
(1) 直接请求授权url(requestLogin),自动跳转到云平台登录页面,并且url请求中会附带回调服务url路径
OAuth OAuth = new OAuth();
java.util.Random r = new java.util.Random();
String state = Integer.toString(r.nextInt());
hrequest.getSession().setAttribute(Config.getValue("client_ID") "_state", state);
boolean forcelogin = false;
String auth_url;
try {
auth_url = OAuth.authorize("code", state, forcelogin);//拼接授权url由sdk完成
hresponse.sendRedirect(auth_url);
} catch (OpenAPIException e) {
throw new ServletException(e);
}
(2) 授权验证,第三方获取返回值code
输入用户名密码之后点击登陆,管理平台会进行验证;验证通过之后,获取Code,获取用户信息进行处理,然后自动跳转到回调url
String code = hrequest.getParameter("code"); if (code == null || code.isEmpty()) { throw new ServletException("获取code出错"); } HttpSession session = hrequest.getSession(); // 增加state参数防止跨站攻击,不支持session的需去掉 Object sstate = session.getAttribute(client_ID "_state"); String state = request.getParameter("state"); if (state == null || !state.equals(sstate)) { throw new ServletException("跨站攻击!"); } OAuth OAuth = new OAuth(); // 获取accesstoken AccessToken tokenObj; try { tokenObj = OAuth.getAccessTokenByCode(code, state); String token = tokenObj.getAccessTokenString(); session.setAttribute(this.client_ID "_access_token", token); // client_ID为应用ID, client_SERCRET为应用密钥 //openapi为浪潮封装jar包 // 下面开始获取用户信息 OpenApi api = new OpenApi(this.client_ID, this.client_SERCRET); api.client.setToken(token); JSONObject userJsonObj = api.sendCommand("/user/get_user_Info_phone", "1.0", "get", null); String status = userJsonObj.getString("status"); JSONObject result = userJsonObj.getJSONObject("result"); String error = result.getString("error"); if (error != null && !error.isEmpty()) { throw new ServletException("获取信息出错"); } Iterator it = result.keys(); Map u = new HashMap(); while (it.hasNext()) { String key = (String) it.next(); u.put(key, result.get(key)); } // 模拟登陆往session里放登陆信息 session.setAttribute("user", u); // 调到第三方应用系统界面,视应用情况而定 hresponse.sendRedirect(hrequest.getContextPath() "/jsp/callindex.jsp"); } catch (OpenAPIException e) { throw new ServletException(e); } catch (JSONException e) { throw new ServletException(e); } |
(3) 第三方应用获取青岛教育e平台的用户信息之后,进行相应的第三方资源访问;或者按照需求记录用户,以便下次访问能够直接访问第三方系统。