我不太喜欢讲原理,喜欢按照应用流程一步步完成一个测试项目,然后掉过头来看原理。
如此。
首先,我们得建一个应用,这无可厚非。
来个网站应用吧!
填写基本信息时,有个网站地址,我们填写一个自己所维护的外部网站页面地址。
在HEAD标签里按照提示,嵌入验证代码,并加以验证。
回调地址填写相应的域名。
示例:
在新建的web项目里新加一个配置文件如下:
app_ID = ******** app_KEY = ************************* redirect_URI = http://www.******************.tk/Qqtest4SDK/afterlogin.do scope = get_user_info,add_topic,add_one_blog,add_album,upload_pic,list_album,add_share,check_page_fans,add_t,add_pic_t,del_t,get_repost_list,get_info,get_other_info,get_fanslist,get_idollist,add_idol,del_ido,get_tenpay_addr baseURL = https://graph.qq.com/ getUserInfoURL = https://graph.qq.com/user/get_user_info accessTokenURL = https://graph.qq.com/oauth2.0/token authorizeURL = https://graph.qq.com/oauth2.0/authorize getOpenIDURL = https://graph.qq.com/oauth2.0/me
这里的redirect_URI是在oauth2.0认证时调用的地址,必须为有效地址,且为同项目下的,我建一个Servlet对应该请求。
我们访问网站地址(并没有做特殊的处理),默认将跳转到本地的index.jsp,jsp的头部之前已经说过,需要添加先关验证<meta>标签
body部分:
<center> <!-- 测试登陆授权 --> <a href="/Qqtest4SDK/login.do"><img src="/Qqtest4SDK/img/qq_login.png" /></a> </center>
后端Servlet处理请求:
public class IndexServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { response.setContentType("text/html;charset=utf-8"); try { String reUrl =new Oauth().getAuthorizeURL(request); response.sendRedirect(reUrl); } catch (QQConnectException e) { e.printStackTrace(); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { doGet(request, response); } }
这里我们需要了解下Oauth2.0的相关认证,Eclipse market下载安装JadClipse反编译工具.
Oauth2.0:
构造请求(PC):
Step1:获取 Authorization Code
Get方式:
https://graph.qq.com/oauth2.0/token
参数:
response_type 固定为code、client_id为appid、redirect_uri 授权成功后callbackURL、state:client端的状态值
public String getAuthorizeURL(ServletRequest request) throws QQConnectException { String state = RandomStatusGenerator.getUniqueState(); ((HttpServletRequest) request).getSession().setAttribute( "qq_connect_state", state); String scope = QQConnectConfig.getValue("scope"); if ((scope != null) && (!(scope.equals("")))) { return getAuthorizeURL("code", state, scope); } return QQConnectConfig.getValue("authorizeURL").trim() + "?client_id=" + QQConnectConfig.getValue("app_ID").trim() + "&redirect_uri=" + QQConnectConfig.getValue("redirect_URI").trim() + "&response_type=" + "code" + "&state=" + state; }
Step2:通过 Authorization Code获取令牌Access Token:
授权成功后,解析响应信息,获取authorization code及原始的state:
private String[] extractionAuthCodeFromUrl(String url) throws QQConnectException { if (url == null) { throw new QQConnectException("you pass a null String object"); } Matcher m = Pattern.compile("code=(\\w+)&state=(\\w+)&?").matcher(url); String authCode = ""; String state = ""; if (m.find()) { authCode = m.group(1); state = m.group(2); } return new String[] { authCode, state }; }
封装信息,并POST请求获取Access Token:
public AccessToken getAccessTokenByRequest(ServletRequest request) throws QQConnectException { String queryString = ((HttpServletRequest) request).getQueryString(); if (queryString == null) { return new AccessToken(); } String state = (String) ((HttpServletRequest) request).getSession() .getAttribute("qq_connect_state"); if ((state == null) || (state.equals(""))) { return new AccessToken(); } String[] authCodeAndState = extractionAuthCodeFromUrl(queryString); String returnState = authCodeAndState[1]; String returnAuthCode = authCodeAndState[0]; AccessToken accessTokenObj = null; if ((returnState.equals("")) || (returnAuthCode.equals(""))) { accessTokenObj = new AccessToken(); } else if (!(state.equals(returnState))) { accessTokenObj = new AccessToken(); } else accessTokenObj = new AccessToken(this.client.post( QQConnectConfig.getValue("accessTokenURL"), new PostParameter[] { new PostParameter("client_id", QQConnectConfig .getValue("app_ID")), new PostParameter("client_secret", QQConnectConfig .getValue("app_KEY")), new PostParameter("grant_type", "authorization_code"), new PostParameter("code", returnAuthCode), new PostParameter("redirect_uri", QQConnectConfig .getValue("redirect_URI")) }, Boolean .valueOf(false))); return accessTokenObj; }
有了令牌,我们就可以根据令牌获取openid,有了openid我们才可以调用接口。
那么,如何获取openid呢?
Step3:获取Openid
请求地址:https://graph.qq.com/oauth2.0/me
参数 :access_token
Get方式:
private String getUserOpenID(String accessToken) throws QQConnectException { String openid = ""; String jsonp = this.client.get( QQConnectConfig.getValue("getOpenIDURL"), new PostParameter[] { new PostParameter("access_token", accessToken) }).asString(); Matcher m = Pattern.compile("\"openid\"\\s*:\\s*\"(\\w+)\"").matcher( jsonp); if (m.find()) openid = m.group(1); else { throw new QQConnectException("server error!"); } return openid; }
Step4:调用OpenAPI
以get_user_info接口为例:
https://graph.qq.com/user/get_user_info?access_token=YOUR_ACCESS_TOKEN&oauth_consumer_key=YOUR_APP_ID&openid=YOUR_OPENID
很简单,构造UserInfo 继承自维护access token和openid的父类,新增返回用户信息UserInfoBean的方法:
在方法里请求以上url并封装响应结果json信息即可:
public class UserInfo extends QQConnect { private static final long serialVersionUID = -6124397423510235640L; public UserInfo(String token, String openID) { super(token, openID); } private UserInfoBean getUserInfo(String openid) throws QQConnectException { return new UserInfoBean(this.client.get( QQConnectConfig.getValue("getUserInfoURL"), new PostParameter[] { new PostParameter("openid", openid), new PostParameter("oauth_consumer_key", QQConnectConfig .getValue("app_ID")), new PostParameter("access_token", this.client .getToken()), new PostParameter("format", "json") }).asJSONObject()); } public UserInfoBean getUserInfo() throws QQConnectException { return getUserInfo(this.client.getOpenID()); } }