您的位置 首页 java

Java 实现 QQ 登陆

蓝色字体 ,选择“标星 公众号

优质文章,第一时间送达

Java 实现 QQ 登陆

1. 前言

个人网站最近增加了评论功能,为了方便用户不用注册就可以评论,对接了 qq 微博 这 2 大常用软件的一键登录,总的来说其实都挺简单的,可能会有一点小坑,但不算多,完整记录下来方便后来人快速对接。

2. 后台设计 在真正开始对接之前,我们先来聊一聊后台的方案设计。既然是对接第三方登录,那就免不了如何将用户信息保存。首先需要明确一点的是,用户在第三方登录成功之后,我们能拿到的仅仅是一个代表用户唯一身份的ID以及用来识别身份的 accessToken ,当然还有昵称、头像、性别等有限资料,对接第三方登录的关键就是如何确定用户是合法登录,如果确定这次登录的和上次登录的是同一个人并且不是假冒的。其实这个并不用我们特别操心,就以 微博 登录为例,用户登录成功之后会回调一个code 给我们,然后我们再拿code去 微博 那换取 accessToken ,如果这个code是用户乱填的,那这一关肯定过不了,所以,前面的担心有点多余。另外一个问题就是如何和现有用户系统打通,有的网站在用户已经登录成功之后还要用户输入手机号和验证码,或者要用户重新注册账号和密码来绑定第三方账户,感觉这种实现用户体验非常差,碰到这种网站我一般都是直接关掉,都已经登录了还让用户注册,什么鬼!由于我做的是评论功能,我并不希望评论用户和现有用户表打通,所以就不存在这件事了,如果想打通的话,我觉得无非就是登录成功之后默认往老用户表插入一条数据,然后和 open User 表关联起来,判断用户是否登录时把 OpenUser 鉴权 也加进去就OK了。

本文的后台以Java为例。

2.1. 数据库设计

再来说说数据库设计,为了系统的扩展性,我有一个专门的 OpenUser 表用来存放第三方登录用户,主要字段如下: Java 实现 QQ 登陆

这样设计理论上就可以无限扩展了。

2.2. 鉴权流程

这里我只是说说我的方案,把 accessToken 写入cookie肯定是不安全的,因为 accessToken 相当于是第三方网站的临时密码,被别人窃取了就可以随意拿来干坏事了。可以在用户登录成功之后我们自己生成一个token,这样的token即使 泄露 了顶多就是被人拿来随意评论,损失不大,但是如果accessToken被 泄露 了,以 微博 为例,人家可以利用这个 accessToken 随意发 微博 、删 微博 、加 关注 等等,很危险。当然,如果不想token 泄露 的话也可以通过绑定IP等方式来限制。

鉴权的话就是首先判断cookie中是否有我们自己的token,然后判断是否合法,合法再判断第三方授权是否已过期等等。

QQ 登陆

3.1. 实名认证

QQ 登录我们对接的是 QQ 互联,地址: qq . com ,首先需要注册成为开发者并实名认证,需要手持身份证照片,具体就不讲了。

3.2. 创建应用

进入应用管理页面( qq .com /manage.html#/)创建应用,根据实际需要是创建网站应用还是移动应用,我这里是网站应用:

Java 实现 QQ 登陆

第一步:

Java 实现 QQ 登陆

第二步:

Java 实现 QQ 登陆

提交完之后会自动提交审核,基本上就是审核你的资料和备案的资料是否一致,所有资料必须和备案资料一模一样,否则审核不会通过:

Java 实现 QQ 登陆

当然,这些资料后面还是可以修改的。申请成功之后你会得到 app Id app Key

3.3. 引导用户登录

这里可以 下载 一些视觉素材,在页面合适位置放一个 QQ 登录按钮,点击时引导用户进入授权页面:

Java 实现 QQ 登陆

代码:

 function openWindow(url, width, height)  {   width = width || 600;   height = height || 400;   var left = (window.screen.width - width) / 2;   var top = (window.screen.height - height) / 2;   window.open(url, "_blank", "toolbar=yes, location=yes, directories=no, status=no, menubar=yes, scrollbars=yes, resizable=no, copyhistory=yes, left="+left+", top="+top+", width="+width+", height="+height);  }  
function qqLogin { var qqAppId = '424323422'; // 上面申请得到的 app id var qqAuthPath = ' http :// www .test .com /auth'; // 前面设置的回调地址 var state = 'fjdslfjsdlkfd'; // 防止CSRF攻击的随机参数,必传,登录成功之后会回传,最好后台自己生成然后校验合法性 openWindow(` qq .com /oauth2.0/authorize?response_type=token&client_id=${qqAppId}&redirect_uri=${encodeURIComponent(qqAuthPath)}&state=${state}`); }

然后会打开一个授权页面,这个页面大家应该都熟悉:

Java 实现 QQ 登陆

然后到了这里我就碰到一个问题了,官方文档( qq .com )写的是登录成功之后首先会回传一个code,然后再拿code调接口换取accessToken,然后我试了很多次也换过2个账号发现每次都是直接返回了accessToken,帮我省了一步了,不知道是什么情况,郁闷。 微信 搜索 Web项目聚集地 获取更多实战教程。

3.4. 拿到accessToken

现在假设我们都是直接拿到accessToken(因为我暂时还没搞明白 QQ 为啥会直接返回,跟文档说的不一样),但是授权回调时accessToken会被放在 # 后面,URL地址中的hash值好像不会被传到后台(貌似是这样,如有不正确欢迎评论指正),所以只能写一个下面这样的临时页面:

 @RequestM app ing("/authqq")  public void authQQ(HttpServletRequest request, HttpServletResponse response) throws Exception  {   //  QQ 登录有点特殊,参数放在#后面,后台无法获取#后面的参数,只能用JS做中间转换   String html = "<!DOCTYPE html>" +   "<html lang="zh-cn">" +   "<head>" +   " <title> QQ 登录重定向页</title>" +   " <meta charset="utf-8"/>" +   "</head>" +   "<body>" +   " <script type="text/javascript">" +   " location.href = location.href.replace('#', '&').replace('auth_qq', 'auth_qq_redirect');" +   "   </script>  " +   "</body>" +   "</html>";   response.getWriter.print(html);  }  

3.5. 获取 openid

根据accessToken调接口获取用户的openId,特别注意这个openId是相对于 QQ 号+ app Id 唯一的,换句话说同一个 QQ 号登录2个不同 app Id时获取到的openId是不同的。顺便说一句, QQ 登录的相关接口做的还真够“随便”的,全部都是最简单的get请求,所以对接起来非常顺利。 微信 搜索 Web项目聚集地 获取更多实战教程。

直接看代码:

 // 根据accessToken换取openId  // 错误示例:callback( {"error":100016,"error_description":"access token check failed"} );  // 正确示例:callback( {"client_id":"10XXXXX49","openid":"CF2XXXXXXXX9F4C"} );  String result = HttpsUtil.get(" qq  .com /oauth2.0/me?access_token=" + accessToken);   Map <String, Object> resp = parseQQAuthResponse(result); // 这个方法就是把结果转Map  // 欢迎 关注  Web项目聚集地 获取更多实战教程  Integer errorCode = (Integer)resp.get("error");  String error msg  = (String)resp.get("error_description");  String openId = (String)resp.get("openid");  if(errorCode != ) return new ErrorResult(errorCode, "获取 QQ 用户openId失败:"+errorMsg);  

3.6. 获取用户头像昵称等信息

 // 获取用户昵称、头像等信息,{ret: 0, msg: '', nickname: '', ...} ret不为0表示失败  result = HttpsUtil.get(" qq  .com /user/get_user_info?access_token="+accessToken+"&oauth_consumer_key="+ app Id+"&openid="+openId);  resp = JsonUtil.parseJsonToMap(result);  // 欢迎 关注  Web项目聚集地 获取更多实战教程  Integer ret = (Integer)resp.get("ret");  String msg = (String)resp.get("msg");  if(ret != 0) return new ErrorResult("获取用户 QQ 信息失败:"+msg);  
// 用户昵称可能存在4个字节的utf-8字符,MySQL默认不支持,直接插入会报错,所以过滤掉 String nickname = StringUtil.filterUtf8Mb4((String)resp.get("nickname")).trim; // 这个方法可以自行百度 // figureurl_qq_2=QQ的100*100头像,figureurl_2=QQ 100&100空间头像,QQ头像不一定有,空间头像一定有 String avatar = (String)resp.get("figureurl_qq_2"); if(StringUtil.isBlank(avatar)) avatar = (String)resp.get("figureurl_2"); String gender = (String)resp.get("gender");

3.7. 注意事项

到了这一步基本上涉及第三方的就结束了,是不是很简单?后面无非就是如何插入数据库、如何保存token、写入session等。

有几点注意事项:

  • 需要注意数据库中是否已经有改用户,没有的添加,有的修改,不要重复添加了;

  • QQ 昵称昵称有各种奇奇怪怪的字符,包括emoji,MySQL默认没有开启 utf8mb4 ,直接插入会报错,所以需要过滤掉;
  • 需要做好对各种错误的兼容;

  • 接口会同时返回 QQ 头像和空间头像, QQ 头像不一定有,空间头像一定有;

  • 回调地址必须和申请的域名一致,否则会报错。

  • QQ 互联有个特大的bug,有时候显示已登录但是点击授权管理一直报错,此时只需要退出重新登录即可;

  • 授权之后用户可能会在过期之前提前取消授权;

  • 微信 搜索 Web项目聚集地 获取更多实战教程。

相关文档官网已经写得比较细了,但是比较乱: http ://wiki.connect. qq .com /

对接 微博 登陆

4.1. 实名认证

这个我就不具体讲了,登录 http ://open.weibo .com / 很容易找到相关入口,注册成为开发者,实名认证,一模一样的。

4.2. 创建应用

点击链接 http ://open.weibo .com / app s/new?sort=web 创建web应用:

Java 实现 QQ 登陆

创建成果后完善相关信息,主要是下面这些:

Java 实现 QQ 登陆

我就不一一介绍了,都看得懂。

微博 登录不需要网站一定要备案,但对网站本身有一定要求,不能弄一个空壳网站让人家去审核,肯定审核不通过的。

有关 微博 的对接可以参考我好几年前写的一篇文章:

http :// www .cnblogs .com /liuxianan/archive/2012/11/11/2765123.html

4.3. 引导用户登录

微博 视觉素材( .com /wiki/ 微博 标识 下载 下载 在这里,页面合适位置放一个登录按钮:

 
 function weiboLogin  {   let weiboAppId = '432432';   let weiboAuthPath = ' http :// www .test .com /authweibo';   openWindow(` .com /oauth2/authorize?client_id=${weiboAppId}&response_type=code&redirect_uri=${encodeURIComponent(weiboAuthPath)}`);  }  

微博 登录有一个好处,第一次登录需要授权,后面第二次登录时只会一闪而过自动就登录成功了,都不需要点一下,用户体验非常好,看下图:

Java 实现 QQ 登陆

4.4. 获取accessToken

登录成功会返回一个code,根据code换取accessToken:

 String params = "client_id=" +  app Id   + "&client_secret=" +  app Secret   + "&grant_type=authorization_code"   + "&redirect_uri=" + URLUtil.encode(authPath)   + "&code=" + code;  // 用code换取accessToken  String result = HttpsUtil.post(" .com /oauth2/access_token", params);  Map<String, Object> resp = JsonUtil.toObject(result, new TypeReference<Map<String, Object>>{});  
Integer errorCode = (Integer)resp.get("error_code"); String error = (String)resp.get("error"); String errorMsg = (String)resp.get("error_description"); if(errorCode != && errorCode != 0) return new ErrorResult(errorCode, error + (errorMsg==?"":errorMsg)); String accessToken = (String)resp.get("access_token"); String uid = (String)resp.get("uid"); // 这个uid就是 微博 用户的唯一用户ID,可以通过这个id直接访问到用户 微博 主页 int expires = (Integer)resp.get("expires_in"); // 有效期,单位秒

4.5. 获取用户头像等信息

 // 用uid和accessToken换取用户信息  String result = HttpsUtil.get(" .com /2/users/show.json?access_token="+accessToken+"&uid="+uid);  Map<String, Object> resp = JsonUtil.toObject(result, new TypeReference<Map<String, Object>>{});  
errorCode = (Integer)resp.get("error_code"); error = (String)resp.get("error"); errorMsg = (String)resp.get("error_description"); if(errorCode != && errorCode != 0) return new ErrorResult(errorCode, error + (errorMsg==?"":errorMsg));
String nickname = (String)resp.get("screen_name"); // 微博 180*180高清头像 String avatar = (String)resp.get("avatar_large"); String gender = (String)resp.get("gender"); gender = "m".equals(gender) ? "男" : ("f".equals(gender) ? "女" : "");
 

至此涉及第三方的东西都完了,剩下的就是用户自己保存到数据库、写入token

保存 session 以及鉴权接口开发了。

4.6. 注意事项

  • 微博 接口都有频率限制,不过一般不会超过;

  • 需做好错误兼容;

  • 微博 直接返回的uid,可以根据这个uid直达用户 微博 主页 .com /u/xxxxx ,所以可以把用户头像链接到这里;

  • 其实也有现成的js-sdk,可以根据自己实际需要选择是否使用;

  • 微博 的接口是https,并且是post,需要注意;

  • 微博 开放平台:open.weibo .com /

  • 微博 登录授权机制:open.weibo .com /wiki/授权机制

  • QQ 互联:connect. qq .com /

  • QQ 授权管理页面:connect. qq .com /manage.html#/ app auth/user

作者:我是小茗同学

排版:Web项目聚集地(web_resource)

链接: www .cn blogs .com /liuxianan.html

如果喜欢本篇文章,欢迎。 关注 订阅 号「Web项目聚集地」,回复「进群」即可进入无广告技术交流。

文章来源:智云一二三科技

文章标题:Java 实现 QQ 登陆

文章地址:https://www.zhihuclub.com/180386.shtml

关于作者: 智云科技

热门文章

网站地图