admin管理员组文章数量:1558092
来源http://wwwblogs/Leo_wl/p/4418790.html
应用场景
web应用通过QQ登录授权实现第三方登录。操作步骤
1 注册成为QQ互联平台开发者, http://connect.qq/ 2 准备一个可访问的域名,如dev.foo 3 创建网页应用,配置必要信息,其中包括域名以及回调地址; 其中域名需要验证,需确保对域名主机有足够的控制权限 4 获取应用appID、appKey进行开发登录流程
开发平台的登录授权采取oauth2.0机制,这也是目前几乎所有互联网开放平台所采取的方式。 需更多了解oauth2.0可参考阮老师的文章: http://www.ruanyifeng/blog/2014/05/oauth_2_0.html实现方式
client-side 流程: 前端页面通过Implict方式 登录授权 -> 回调获得accessToken -> 获取openid -> 同步用户信息并登录 为了保证数据安全,在获取用户信息并登录这一步必须由服务端实现。 这种方式的开发相对便捷,也是后面的实战案例将要采取的方式。 server-side 流程: 由server端页面跳转到登录授权页面(Authorization code方式) -> 回调获得code -> 置换accessToken -> 获取openid -> 同步用户信息并登录 可参考: http://wiki.connect.qq/%E5%BC%80%E5%8F%91%E6%94%BB%E7%95%A5_server-sideSDK使用
JSSDK 可快捷实现前端登录授权的功能,可自定制登录按钮 使用文档: http://wiki.connect.qq/js_sdk%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E 缺点:存在浏览器兼容风险,此外登录按钮UI的定制也存在受限 JavaSDK 屏蔽了oauth授权的复杂度,方便后端实现授权及api操作 缺点:增加依赖jar包,项目容易变得臃肿,尤其是当前项目已经存在oauth功能实现时可不必采用。案例实战
功能描述 clientside + server-side 通过QQ网页授权登录,并获取用户信息1 本地开发环境准备
修改hosts文件将dev.foo映射到127.0.0.1; 本地服务器以80端口启动, windows下可能会出现80端口被系统进程占用的情况,解决方法可参考 http://wwwblogs/littleatp/p/4414578.html 本地服务器启动后,以dev.foo的域名进行访问,在QQ登录授权时可通过域名验证这一步2 登录跳转页面
<html> <head> <title>QQ登录跳转</title> <script src="http://lib.sinaapp/js/jquery/1.7.2/jquery.min.js" type="text/javascript"></script> <script type="text/javascript"> //切割字符串转换参数表 function toParamMap(str){ var map = {}; var segs = str.split("&"); for(var i in segs){ var seg = segs[i]; var idx = seg.indexOf('='); if(idx < 0){ continue; } var name = seg.substring(0, idx); var value = seg.substring(idx+1); map[name] = value; } return map; } //隐式获取url响应内容(JSONP) function openImplict(url){ var script = document.createElement('script'); script.src = url; document.body.appendChild(script); } //获得openid的回调 function callback(obj) { var openid = obj.openid; $("#openid").text(openid); //跳转服务端登录url var resulturl = "@{openapi.QQs.login_result()}"; var accessToken = $("#accessToken").text(); //向服务端传输access_token及openid参数 document.location.href=resulturl + "?access_token=" + accessToken + "&openid=" + openid; } </script> </head> <body> <p>AccessToken:<span id="accessToken"></span>--ExpireIn<span id="expire"></span></p> <p>OpenID:<span id="openid"></span></p> <!-- 执行脚本 --> <script type="text/javascript"> //应用的APPID var appID = "101207268"; //登录授权后的回调地址,设置为当前url var redirectURI = "@@{openapi.QQs.login()}"; //初始构造请求 if (window.location.hash.length == 0) { var path = 'https://graph.qq/oauth2.0/authorize?'; var queryParams = ['client_id=' + appID, 'redirect_uri=' + redirectURI, 'scope=' + 'get_user_info,list_album,upload_pic,add_feeds,do_like','response_type=token']; var query = queryParams.join('&'); var url = path + query; window.location.href= url; } //在成功授权后回调时location.hash将带有access_token信息,开始获取openid else { //获取access token var accessToken = window.location.hash.substring(1); var map = toParamMap(accessToken); //记录accessToken $("#accessToken").text(map.access_token); $("#expire").text(map.expires_in); //使用Access Token来获取用户的OpenID var path = "https://graph.qq/oauth2.0/me?"; var queryParams = ['access_token='+map.access_token, 'callback=callback']; var query = queryParams.join('&'); var url = path + query; openImplict(url); } </script> </body> </html>功能描述 页面在第一次打开时跳转到QQ登录授权页面; 授权成功之后回到当前页面通过url参数(hash串)获得accessToken; 此后可通过jsonp方式获取用户的openid,url如:
https://graph.qq/oauth2.0/me?access_token=YOUR_ACCESS_TOKEN获取到用户OpenID,返回包如下(JSONP方式获取):
callback( {"client_id":"YOUR_APPID","openid":"YOUR_OPENID"} )将access_token及openid传到服务端进行处理
3 server端获取用户信息
接收openid的页面方法/** * 登录结果 * * @param access_token * @param openid */ public static void login_result(String access_token, String openid) { //调用api获取qq用户信息 QQUserInfo user = QQApi.getUserInfo(access_token, openid); //此时若取得user信息,则可以进行保存,并执行用户登录操作 .... //登录成功后跳转 redirect(xxx); }
QQApi的实现
/** * QQ互联API * * <pre> * 登录流程: * * 1 前端跳转qq授权页面 * 2 js获得access_token * 3 通过jsonp方式获得openid * 4 server端根据上传的access_token及openid获取用户信息,如昵称、头像 * * 参考文档: * http://wiki.connect.qq/%E5%BC%80%E5%8F%91%E6%94%BB%E7%95%A5_client-side#Step2.EF.BC.9A.E8.8E.B7.E5.8F.96AccessToken * </pre> * * @author xxx * @createDate 2015年3月10日 * */ public class QQApi { public static String appId = "xxx"; public static String appSecret = "xxx"; public static String baseUrl = "https://graph.qq"; protected static final String URL_GET_USERINFO = baseUrl + "/user/get_user_info?access_token=%s&oauth_consumer_key=%s&openid=%s"; protected static final long ACCESS_TIMEOUT = 15; protected static final String DEF_APP_TOKEN_EXPIRE = "3h"; /** * 获取用户信息 * * <pre> * http://wiki.connect.qq/get_user_info * * * 调用地址: * https://graph.qq/user/get_user_info * 参数 * access_token=*************& * oauth_consumer_key=12345& * openid * * 返回结果如下: * { * "ret": 0, * "msg": "", * "is_lost": 0, * "nickname": "小吞", * "gender": "女", * "province": "广东", * "city": "广州", * "year": "1993", * "figureurl": "http://qzapp.qlogo/qzapp/101207268/982C9FEADAF7B242C5069B8F390784BF/30", * "figureurl_1": "http://qzapp.qlogo/qzapp/101207268/982C9FEADAF7B242C5069B8F390784BF/50", * "figureurl_2": "http://qzapp.qlogo/qzapp/101207268/982C9FEADAF7B242C5069B8F390784BF/100", * "figureurl_qq_1": "http://q.qlogo/qqapp/101207268/982C9FEADAF7B242C5069B8F390784BF/40", * "figureurl_qq_2": "http://q.qlogo/qqapp/101207268/982C9FEADAF7B242C5069B8F390784BF/100", * "is_yellow_vip": "0", * "vip": "0", * "yellow_vip_level": "0", * "level": "0", * "is_yellow_year_vip": "0" * } * </pre> * * @param accessToken * @return */ public static QQUserInfo getUserInfo(String accessToken, String openid) { if (StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(openid)) { return null; } String url = String.format(URL_GET_USERINFO, accessToken, appId, openid); String resultString = DefaultHttp.get(url, ACCESS_TIMEOUT, GlobalConstants.UTF_8); Logger.debug("[sso-qq]get userinfo. use url '%s'", url); QQUserInfo userinfo = JsonUtil.fromJson(resultString, QQUserInfo.class); if (userinfo == null || !userinfo.hasGot()) { Logger.debug("[sso-qq]get userinfo failed, with result of '%s'", resultString); return null; } Logger.debug("[sso-qq]get userinfo success, with result of '%s'", resultString); return userinfo; }
常见问题
网页跳转提示 "redirect_uri_mismatch" 通常是应用配置中的域名与当前开发服务器访问地址不一致导致,参照案例中的本地开发环境准备小节 api调用返回错误 查看返回的ret字段,对于非0值的ret则表示异常结果,可通过以下地址查询错误原因: http://wiki.connect.qq/%E5%85%AC%E5%85%B1%E8%BF%94%E5%9B%9E%E7%A0%81%E8%AF%B4%E6%98%8E 接口调用过于频繁或超过限制 应用系统可做好access_token的存储,此外对于用户数据(昵称、头像)也做好缓存或持久化,以减少接口的调用频度。版权声明:本文标题:开放平台-web实现QQ第三方登录 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/xitong/1727385825a1112339.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论