应用场景

    web应用通过QQ登录授权实现第三方登录。
 

操作步骤

    1  注册成为QQ互联平台开发者,http://connect.qq.com/
    2  准备一个可访问的域名,如dev.foo.com
    3  创建网页应用,配置必要信息,其中包括域名以及回调地址;
        其中域名需要验证,需确保对域名主机有足够的控制权限
    4  获取应用appID、appKey进行开发
 

登录流程

    开发平台的登录授权采取oauth2.0机制,这也是目前几乎所有互联网开放平台所采取的方式。
 
    
 
    需更多了解oauth2.0可参考阮老师的文章: http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
 

实现方式

    client-side
        流程:
        前端页面通过Implict方式 登录授权 -> 回调获得accessToken -> 获取openid -> 同步用户信息并登录
 
        为了保证数据安全,在获取用户信息并登录这一步必须由服务端实现。
        这种方式的开发相对便捷,也是后面的实战案例将要采取的方式。
 
    server-side
        流程:
        由server端页面跳转到登录授权页面(Authorization code方式) -> 回调获得code -> 置换accessToken -> 获取openid -> 同步用户信息并登录
 

SDK使用

    JSSDK  可快捷实现前端登录授权的功能,可自定制登录按钮
        缺点:存在浏览器兼容风险,此外登录按钮UI的定制也存在受限
 
    JavaSDK  屏蔽了oauth授权的复杂度,方便后端实现授权及api操作
        缺点:增加依赖jar包,项目容易变得臃肿,尤其是当前项目已经存在oauth功能实现时可不必采用。
 
 

案例实战

 
    功能描述
    clientside + server-side 通过QQ网页授权登录,并获取用户信息
 

1  本地开发环境准备

        修改hosts文件将dev.foo.com映射到127.0.0.1;
        本地服务器以80端口启动, windows下可能会出现80端口被系统进程占用的情况,解决方法可参考 http://www.cnblogs.com/littleatp/p/4414578.html
        本地服务器启动后,以dev.foo.com的域名进行访问,在QQ登录授权时可通过域名验证这一步
 

2  登录跳转页面

<html>
<head>
<title>QQ登录跳转</title>
<script src="http://lib.sinaapp.com/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.com/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.com/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.com/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.com/%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.com"; 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.com/get_user_info
*
*
* 调用地址:
* https://graph.qq.com/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.cn/qzapp/101207268/982C9FEADAF7B242C5069B8F390784BF/30",
* "figureurl_1": "http://qzapp.qlogo.cn/qzapp/101207268/982C9FEADAF7B242C5069B8F390784BF/50",
* "figureurl_2": "http://qzapp.qlogo.cn/qzapp/101207268/982C9FEADAF7B242C5069B8F390784BF/100",
* "figureurl_qq_1": "http://q.qlogo.cn/qqapp/101207268/982C9FEADAF7B242C5069B8F390784BF/40",
* "figureurl_qq_2": "http://q.qlogo.cn/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则表示异常结果,可通过以下地址查询错误原因:
 
接口调用过于频繁或超过限制
        应用系统可做好access_token的存储,此外对于用户数据(昵称、头像)也做好缓存或持久化,以减少接口的调用频度。
 
    

开放平台-web实现QQ第三方登录的更多相关文章

  1. web实现QQ第三方登录 开放平台-web实现QQ第三方登录

    应用场景     web应用通过QQ登录授权实现第三方登录.   操作步骤     1  注册成为QQ互联平台开发者,http://connect.qq.com/     2  准备一个可访问的域名, ...

  2. 开放平台-web实现人人网第三方登录

    应用场景     web应用通过人人网登录授权实现第三方登录.   操作步骤     1  注册成为人人网开放平台开发者         http://app.renren.com/developer ...

  3. web实现QQ第三方登录

    开放平台-web实现QQ第三方登录   应用场景     web应用通过QQ登录授权实现第三方登录.   操作步骤     1  注册成为QQ互联平台开发者,http://connect.qq.com ...

  4. Android应用之——最新版本号SDK V2.4实现QQ第三方登录

    为什么要写这篇博客呢?由于.我在做这个第三方登录的时候,找了非常多资料,发现要么就是过时了.要么就是说的非常不清楚.非常罗嗦.并且非常多都是一些小demo,不是什么实例.甚至连腾讯官方的文档都有这个问 ...

  5. 微信开放平台PC端扫码登录功能个人总结

    最近公司给我安排一个微信登录的功能,需求是这样的: 1.登录授权 点击二维码图标后,登录界面切换为如下样式(二维码),微信扫描二维码并授权,即可成功登录:    若当前账号未绑定微信账号,扫描后提示“ ...

  6. 使用QQ第三方登录时,手机应用和网站应用对同一个QQ号,获取到的openid不一样

    使用QQ第三方登录时,手机应用和网站应用对同一个QQ号,获取到的openid不一样openid生成是根据应用的appid和QQ号的一些信息加密生成,对于一个appid和QQ号来说,openid是唯一的 ...

  7. 【第三方登录】之QQ第三方登录

    最近公司做了个网站,需要用到第三方登录的东西.有QQ第三方登录,微信第三方登录.先把QQ第三方登录的代码列一下吧. public partial class QQBack : System.Web.U ...

  8. QQ第三方登录

    QQ第三方登录 在Android应用程序的开发过程中,很多时候需要加入用户登录/注册模块.除了自己动手设计登录界面并实现相应功能外,现在还可以借助百度.腾讯等开发者平台提供的第三方账号登录模块.最近研 ...

  9. PHP实现QQ第三方登录

    PHP实现QQ第三方登录 学习之前,请大家先看一下oAuth协议. 首先呢,我们进入QQ互联的官方网站 http://connect.qq.com登入我们自己的QQ号,没有QQ号的小伙伴可以忽略本篇博 ...

随机推荐

  1. 为什么SQL语句加 1=1

    是为了链接下面的查询条件条件,也或者是替换没有查询条件的语句.比如:要把检索条件作为一个参数传递给SQL,那么,当这个检索语句不存在的话就可以给它赋值为1=1.这样就避免了SQL出错,也就可以把加条件 ...

  2. Cookies和Session的区别

    原文:http://www.cnblogs.com/lijihong/p/4743818.html 今天主要学习了Cookies和Session,网络上关于这方面的知识可谓很多,让人眼花缭乱,在此作一 ...

  3. UIkit框架之UIScrollView

    1.继承链:UIview:UIresponder:NSObject 引言 UIScrollView的是几个UIKit类包括的UITableView和UITextView中的超类. 一个UIScroll ...

  4. 如何将内存图像数据封装成QImage

    http://blog.csdn.net/lyc_daniel/article/details/9055787 当采用Qt开发相机数据采集软件时,势必会遇到采集内存图像并进行处理(如缩放.旋转)操作. ...

  5. Python的"数组"储存

    import time member=["小甲鱼","小布丁","黑夜","迷途","伊静"] pr ...

  6. python数据分析入门——matplotlib的中文显示问题&最小二乘法

    正在学习<用python做科学计算>,在练习最小二乘法时遇到matplotlib无法显示中文的问题.查资料,感觉动态的加上几条语句是最好,这里贴上全部的代码. # -*- coding: ...

  7. 学习php前需要了解的知识

    1.静态网站与动态网站 A)静态网站: 不支持数据交互的网站(后缀:   .html  .htm) B)动态网站: 支持数据交互的网站,动态网站可以放静态网页的 i.实现动态网站的技术 1.Asp   ...

  8. C# 封装一个钩子类

    利用C#设置钩子函数,并封装成类.如果想要实现全局钩子的话,必须将实现的代码封装到类库里. using System; using System.Collections.Generic; using ...

  9. C#使用指针复制字节数组

    下面的示例使用指针将字节从一个数组复制到另一个数组. 此示例使用 unsafe 关键字,它使您能够在 Copy 方法中使用指针. fixed 语句用于声明指向源数组和目标数组的指针. 这将锁定源数组和 ...

  10. magento添加多个产品到购物车(Add multiple products to cart )

    Step  1app\design\frontend\base\default\template\catalog\product\list.phtml<?php    $_productColl ...