网站接入

 
QQ登录网站接入功能实现--非官方文档搬运
时间:2015-11-24 14:54:46      阅读:500      评论:0      收藏:0      [点我收藏+]

标签:
背景

最近第一次使用QQ登录功能,期间遇到这种问题,在网上找了很多资料,大多都是官方的搬运,并没有真正的干料,可能是个人能力问题,遇到了各种麻烦,记录一下和大家分享,希望对大家有所帮助。

由于官方文档已经做出了很明确的说明,这里我只是记录我在开发中遇到的问题和注意的事项,官方文档:http://wiki.connect.qq.com/

开发环境:SpringMVC、QQ登录Java SDK
账户注册并创建应用

地址如下:http://connect.qq.com/

一、账户登录
注意:登录的账户尽量用公司专用的,以后用于测试的时候,只能这个账户进行测试,这样的话,可以减少不必要的麻烦或者泄露自己的QQ信息

二、注册开发者账户
如果已经注册,则不会有该步骤,没有的话根据相应的需求进行注册

三、创建应用

首先可以根据官方案例进行编写自己的项目,http://qzonestyle.gtimg.cn/qzone/vas/opensns/res/doc/qqConnect_Server_SDK_java_v2.0.zip
(或者可访问:这里写链接内容)

项目代码完成之后,可以继续下边的内容:

技术分享

在一块我相信是很多人遇到的问题,第一个是网站地址该如何填写,另一个是回调地址的填写,尽管填写完成还会有相应的报错,下边做一下我的分析:

1、网站地址的选取:首先是官网的首页或登陆界面,在域名解析的时候必须为80端口(我尝试过其他端口是不可以的)

技术分享

上图是一个域名的解析,例如:www.abc.com是我的域名,111.23.23.244是我的主机,图中有三条记录

第一条是将域名和主机IP地址进行绑定;
第二条是将二级域名dubboadmin进行解析,即www.dubboadmin.abc.com;
第三条是将二级域名security进行解析;

此时可以看出,dubboadmin和security都是二级域名,一个是通过A记录一个是通过隐形URL的类型,这是因为,在默认的域名解析中,如果通过A记录来绑定域名的话,默认的是绑定到IP的80端口,即111.23.23.244:8080,但是一个IP上的端口还有很多,一个IP机器上可以运行多个项目,这样的话我们就通过隐形URL的方式来讲不同的二级域名绑定到不同的端口上,即是将dubboadmin绑定到http://www.abc.com:8012端口上.

我在做QQ登录的时候,亲测过使用其他端口的不可行,可能是测试的不完整性,如果你在开发的过程中也是出现使用IP非80端口绑定的域名遇到了这个问题,建议你使用80端口进行测试。

最后,根据80端口,我绑定的域名是www.security.abc.com,但是还要注意的是,对于任何一个用户在访问www.security.abc.com地址的时候,有可能会让用户登录,那么会跳转到一个登录界面,例如我的就是当访问www.security.abc.com的时候,他会自动跳到security.abc.com/login.do让用户登录,那我我最终的网站地址就是:http://security.abc.com/login.do,因为,这个网址也是QQ在验证网站的时候进行访问的链接(可以打log进行查看),因此使用http://security.abc.com/ 是不可以的。

技术分享

同样的在这个login界面,也就是http://security.abc.com/login.do所指向的界面中添加QQ登录按钮,和网站验证时需要填写在head标签中的meta信息,例如:

<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta property="qc:admins" content="1133201050a16asdfhjsdf7sd5f6567647"/>
    <title>QQ登录测试</title>
</head>

<div class="form-group input-group" style="margin-top: 45px;">
    <a href="/qqlogin.do">请使用你的QQ账号登陆</a>
</div>

这里的/qqlogin.do是进行登录处理的controller地址,在后边会说

2、回调地址的选择

回调地址的选择是在用户通过QQ授权之后,我们需要对用户信息进行保存的地址,由于使用的是SpringMVC,例如我的回调操作如下:(代码为官方Demo案例,可以直接使用)

@Controller
@RequestMapping
public class LoginController {

    @Inject
    private Oauth qqOauth;

    /**
     * 进行QQ登录,这里就是前台界面中访问的那个超链接的处理Controller
     */
    @RequestMapping(value = "/qqlogin")
    public void QQLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html;charset=utf-8");
        try {
            response.sendRedirect(qqOauth.getAuthorizeURL(request));
        } catch (QQConnectException e) {
            e.printStackTrace();
        }
    }

    /**
     * 用于QQ登录的回调
     */
    @RequestMapping(value = "/afterQQLogin")
    protected void afterQQLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html; charset=utf-8");

        PrintWriter out = response.getWriter();
        try {
            AccessToken accessTokenObj = (new Oauth()).getAccessTokenByRequest(request);

            String accessToken = null, openID = null;
            long tokenExpireIn = 0L;

            //这还有很多代码,是在上边的那个官方案例中给出的,请参考使用
        } catch (QQConnectException e) {
        }
    }
}

因此我的回调地址是:http://security.abc.com/afterQQLogin.do

如果你的项目代码中完成了以上部分的话,可以将项目不熟到真实的域名下,然后进行验证。

3、项目的配置文件

如果上述过程OK,则在官方demo中还有一个名为:qqconnectconfig.properties的配置文件,这个是需要配置的:

app_ID = 34234123 #自己申请的id
app_KEY = ecfd12341234qewrqwer69db492e1ca #自己申请的key
redirect_URI = http://security.abc.com/afterQQLogin.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
#下边还有很多,因为是不需要修改的,所以不列出

这里提示:别忘了引用qq登录的jar包

官方Demo中介绍的是该文件要放在src目录下,这是在传统的通过MyEclipse中创建的静态Web项目的做法,如果使用的是Spring框架的话,把该文件放在src目录下的话会出现bean加载失败的问题,则需要将该文件放在resource目录下,这样的话,在进行项目启动的时候就可以加载到。

技术分享

另外,如果将该文件放在了正确的位置,还是出现bean未加载的问题的话,如果出现下边的错误:

Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.qq.connect.oauth.Oauth org.albert.security.controller.LoginController.qqOauth; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.qq.connect.oauth.Oauth] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@javax.inject.Inject()}

我的解决方法是手动配置该Oauth,在spring配置文件的相应位置放入

<bean id="qqOauth" class="com.qq.connect.oauth.Oauth"/>

在使用的位置添加:

 @Inject
 private Oauth qqOauth;

并将案例中response.sendRedirect(new Oauth().getAuthorizeURL(request));的代码对应的改为response.sendRedirect(qqOauth.getAuthorizeURL(request));

这样的话,在我的项目中可以跑起来。
其他问题

1、官方对应错误返回码文档说明如下:http://wiki.connect.qq.com/公共返回码说明

2、如果使用IDEA+maven项目的开发方式的话,那么怎么引用qq的依赖jar哪?过程如下:
在WEB-INF 目录下创建一个lib目录,将该jar放进去,然后再对应的POM文件中加入:

<dependency>
            <groupId>javabuilder</groupId>
            <artifactId>javabuilder</artifactId>
            <version>1.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/webapp/WEBINF/lib/Sdk4J.jar</systemPath>
</dependency>

systemPath为自己对应的位置,即可完成对jar的依赖,另外别忘了将在Sdk4J.jar上右键将改gar加入到classpath中。

—————————————————分割线——————————————————-
另附我在项目中是使用的Controller:

@Controller
@RequestMapping
public class LoginController {

    private static final Logger LOGGER = LoggerFactory.getLogger(LoginController.class);

    @Inject
    private Oauth qqOauth;

    /**
     * 进行QQ登录
     * @param request
     * @param response
     * @throws IOException
     */
    @RequestMapping(value = "/qqlogin")
    public void QQLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html;charset=utf-8");
        try {
            response.sendRedirect(qqOauth.getAuthorizeURL(request));
        } catch (QQConnectException e) {
            e.printStackTrace();
        }
    }

    /**
     * 用于QQ登录的回调
     */
    @RequestMapping(value = "/afterQQLogin")
    protected void afterQQLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html; charset=utf-8");

        PrintWriter out = response.getWriter();
        try {
            AccessToken accessTokenObj = (new Oauth()).getAccessTokenByRequest(request);

            String accessToken = null, openID = null;
            long tokenExpireIn = 0L;

            if (accessTokenObj.getAccessToken().equals("")) {
//                我们的网站被CSRF攻击了或者用户取消了授权
//                做一些数据统计工作
                System.out.print("没有获取到响应参数");
            } else {
                accessToken = accessTokenObj.getAccessToken();
                tokenExpireIn = accessTokenObj.getExpireIn();

                request.getSession().setAttribute("demo_access_token", accessToken);
                request.getSession().setAttribute("demo_token_expirein", String.valueOf(tokenExpireIn));

                // 利用获取到的accessToken 去获取当前用的openid -------- start
                OpenID openIDObj = new OpenID(accessToken);
                openID = openIDObj.getUserOpenID();

                out.println("欢迎你,代号为 " + openID + " 的用户!");
                request.getSession().setAttribute("demo_openid", openID);
//                out.println("<a href=" + "/shuoshuoDemo.html" + " target=\"_blank\">去看看发表说说的demo吧</a>");
                // 利用获取到的accessToken 去获取当前用户的openid --------- end

                out.println("<p> start -----------------------------------利用获取到的accessToken,openid 去获取用户在Qzone的昵称等信息 ---------------------------- start </p>");
                UserInfo qzoneUserInfo = new UserInfo(accessToken, openID);
                UserInfoBean userInfoBean = qzoneUserInfo.getUserInfo();
                out.println("<br/>");
                if (userInfoBean.getRet() == 0) {
                    out.println(userInfoBean.getNickname() + "<br/>");
                    out.println(userInfoBean.getGender() + "<br/>");
                    out.println("黄钻等级: " + userInfoBean.getLevel() + "<br/>");
                    out.println("会员 : " + userInfoBean.isVip() + "<br/>");
                    out.println("黄钻会员: " + userInfoBean.isYellowYearVip() + "<br/>");
                    out.println("<image src=" + userInfoBean.getAvatar().getAvatarURL30() + "/><br/>");
                    out.println("<image src=" + userInfoBean.getAvatar().getAvatarURL50() + "/><br/>");
                    out.println("<image src=" + userInfoBean.getAvatar().getAvatarURL100() + "/><br/>");
                } else {
                    out.println("很抱歉,我们没能正确获取到您的信息,原因是: " + userInfoBean.getMsg());
                }
                out.println("<p> end -----------------------------------利用获取到的accessToken,openid 去获取用户在Qzone的昵称等信息 ---------------------------- end </p>");


                out.println("<p> start ----------------------------------- 验证当前用户是否为认证空间的粉丝------------------------------------------------ start <p>");
                PageFans pageFansObj = new PageFans(accessToken, openID);
                PageFansBean pageFansBean = pageFansObj.checkPageFans("97700000");
                if (pageFansBean.getRet() == 0) {
                    out.println("<p>验证您" + (pageFansBean.isFans() ? "是" : "不是") + "QQ空间97700000官方认证空间的粉丝</p>");
                } else {
                    out.println("很抱歉,我们没能正确获取到您的信息,原因是: " + pageFansBean.getMsg());
                }
                out.println("<p> end ----------------------------------- 验证当前用户是否为认证空间的粉丝------------------------------------------------ end <p>");

                out.println("<p> start -----------------------------------利用获取到的accessToken,openid 去获取用户在微博的昵称等信息 ---------------------------- start </p>");
                com.qq.connect.api.weibo.UserInfo weiboUserInfo = new com.qq.connect.api.weibo.UserInfo(accessToken, openID);
                com.qq.connect.javabeans.weibo.UserInfoBean weiboUserInfoBean = weiboUserInfo.getUserInfo();
                if (weiboUserInfoBean.getRet() == 0) {
                    //获取用户的微博头像----------------------start
                    out.println("<image src=" + weiboUserInfoBean.getAvatar().getAvatarURL30() + "/><br/>");
                    out.println("<image src=" + weiboUserInfoBean.getAvatar().getAvatarURL50() + "/><br/>");
                    out.println("<image src=" + weiboUserInfoBean.getAvatar().getAvatarURL100() + "/><br/>");
                    //获取用户的微博头像 ---------------------end

                    //获取用户的生日信息 --------------------start
                    out.println("<p>尊敬的用户,你的生日是: " + weiboUserInfoBean.getBirthday().getYear()
                            + "年" + weiboUserInfoBean.getBirthday().getMonth() + "月" +
                            weiboUserInfoBean.getBirthday().getDay() + "日");
                    //获取用户的生日信息 --------------------end

                    StringBuffer sb = new StringBuffer();
                    sb.append("<p>所在地:" + weiboUserInfoBean.getCountryCode() + "-" + weiboUserInfoBean.getProvinceCode() + "-" + weiboUserInfoBean.getCityCode()
                            + weiboUserInfoBean.getLocation());

                    //获取用户的公司信息---------------------------start
                    ArrayList<Company> companies = weiboUserInfoBean.getCompanies();
                    if (companies.size() > 0) {
                        //有公司信息
                        for (int i = 0, j = companies.size(); i < j; i++) {
                            sb.append("<p>曾服役过的公司:公司ID-" + companies.get(i).getID() + " 名称-" +
                                    companies.get(i).getCompanyName() + " 部门名称-" + companies.get(i).getDepartmentName() + " 开始工作年-" +
                                    companies.get(i).getBeginYear() + " 结束工作年-" + companies.get(i).getEndYear());
                        }
                    } else {
                        //没有公司信息
                    }
                    //获取用户的公司信息---------------------------end
                    out.println(sb.toString());
                } else {
                    out.println("很抱歉,我们没能正确获取到您的信息,原因是: " + weiboUserInfoBean.getMsg());
                }
                out.println("<p> end -----------------------------------利用获取到的accessToken,openid 去获取用户在微博的昵称等信息 ---------------------------- end </p>");
            }
        } catch (QQConnectException e) {
        }
    }
}

登录连接:

 <div class="form-group input-group" style="margin-top: 45px;">
    <a href="/qqlogin.do">请使用你的QQ账号登陆</a>
</div>

QQ登录网站接入功能实现--非官方文档搬运

标签:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值