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登录网站接入功能实现--非官方文档搬运
标签:
网站接入
最新推荐文章于 2022-04-13 09:08:05 发布