web实现QQ第三方登录[通俗易懂]

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


Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

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

 

应用场景

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

操作步骤

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

登录流程

    开发平台的登录授权采取oauth2.0机制,这也是目前几乎所有互联网开放平台所采取的方式。
 
    
web实现QQ第三方登录[通俗易懂]
 
    需更多了解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的存储,此外对于用户数据(昵称、头像)也做好缓存或持久化,以减少接口的调用频度。
 
    

 
分类: 
j2ee 技术, 
java 技术
标签: 
java, 
oauth, 
开放平台

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/167606.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长

相关推荐

  • Keil 5下载安装教程以及使用教程

    Keil 5下载安装教程以及使用教程Keil5下载、安装、使用教程使用教程(以编写智能循迹避障小车为例)下载链接:https://pan.baidu.com/s/1QUnTgeWveKVK8shHEU4idA提取码:66kg(里面有安装教程)使用教程(以编写智能循迹避障小车为例)首先打开Keil5创建一个新的工程点击Project2.选择第一个new一个新的工程3.输入文件名4.下一步点击保存5.此时会出现当前界面点击小三角6.选择STC7.点击+8.选择STC12C5616AD9.

    2022年5月20日
  • 遗传算法_aforge遗传算法

    遗传算法_aforge遗传算法一、遗传算法简介:遗传算法是进化算法的一部分,是一种通过模拟自然进化过程搜索最优解的方法。二、遗传算法思想:遗传算法组成:1.编码2.适应度函数3.遗传算子:选择、交叉、变异4.运行参数借鉴生物进化论,遗传算法将要解决的问题模拟成一个生物进化的过程,通过复制、交叉、突变等操作产生下一代的解,并逐步淘汰掉适应度函数值低的解,增加适应度函数值高的解。这样进化N代后就很有可能会进化出适应度函数值很高的个体。2.1.编码将问题的解编码称字符串形式才能使用遗传算法。最简单的一种编码是二进制编码,即

    2022年9月3日
  • 编写 if 时不带 else,你的代码会更好!

    点击上方“全栈程序员社区”,星标公众号 重磅干货,第一时间送达 来源:翻译自:Nicklas Millard的文章《Better Software Without If-Else》…

    2021年6月27日
  • qt多线程编程实例_lgbt

    qt多线程编程实例_lgbt一、线程基础1、GUI线程与工作线程每个程序启动后拥有的第一个线程称为主线程,即GUI线程。QT中所有的组件类和几个相关的类只能工作在GUI线程,不能工作在次线程,次线程即工作线程,主要负责处理GUI线程卸下的工作。2、数据的同步访问每个线程都有自己的栈,因此每个线程都要自己的调用历史和本地变量。线程共享相同的地址空间。二、QT多线程简介QT通过三种形式提供了对线程…

    2022年5月3日
  • Zygote过程【3】——SystemServer诞生

    Zygote过程【3】——SystemServer诞生

    2022年1月2日
  • 学习方法——哈佛大学幸福课(积极心理学)学习笔记(下)[通俗易懂]

    学习方法——哈佛大学幸福课(积极心理学)学习笔记(下)[通俗易懂]最近刚看完哈佛大学的幸福课(又名积极心理学),真的是受益匪浅,通常心理学只研究如何消除抑郁、自卑等消极心理,但是消除了消极心理并不代表就会变得幸福,就像摆脱了痛苦并不代表获得了快乐。积极心理学的核心内容就是去分析积极心理的特点、研究如何培养他们。下面目录中加粗的章节是我认为的讲的最好的章节,从根源去分析悲观、焦虑以及完美主义等是如何产生的,然后分析它们与积极品性的关系,最后告诉我们培养积极品性…

    2022年7月25日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号