一、创建应用

1、在 QQ互联 创建应用

地址:https://connect.qq.com/manage.html#/

然后进行实名认证,创建应用,审核通过

然后点击查看,可以获得 APP ID 和 APP Key

回调地址如下

2、授权的基本原理

可以参考官方文档

1)根据QQ登录链接可以回调获得 code

2)根据APP ID 、APP Key 和 code 可获得 token

3)根据 token 获得 OpenId

4)  根据 OpenId 可以获得用户的基本信息

其中 OpenId 是一个唯一的值,比如 8A674574E1B12345D790A1B3EFE81234

3、几个必要的URL

1)登录页面授权 URL:

https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=%s&redirect_uri=%s&scope=%s

2)获得 Token 的 URL:

https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&client_id=%s&client_secret=%s&code=%s&redirect_uri=%s

3)获得用户OpenId 的 URL:

https://graph.qq.com/oauth2.0/me?access_token=%s

4)获得用户信息的 URL:

https://graph.qq.com/user/get_user_info?access_token=%s&oauth_consumer_key=%s&openid=%s

二、基本准备

1、数据库设计

主要看 bind 和 bind_type 表的数据

identifier 表示识别码,保证唯一性

credential 表示凭证,通常用不上

bind_type_id 和 user_id 是外键,很好理解

name 唯一性

style 样式

2、放置 QQ 登录按钮

这里有两种常用的方式

① 弹小窗

  1. <script>
  2. function openWin(url,name,iWidth,iHeight) {
  3. //获得窗口的垂直位置
  4. var iTop = (window.screen.availHeight - 30 - iHeight) / 2;
  5. //获得窗口的水平位置
  6. var iLeft = (window.screen.availWidth - 10 - iWidth) / 2;
  7. window.open(url, name, 'height=' + iHeight + ',innerHeight=' + iHeight + ',width=' + iWidth + ',innerWidth=' + iWidth + ',top=' + iTop + ',left=' + iLeft + ',status=no,toolbar=no,menubar=no,location=no,resizable=no,scrollbars=0,titlebar=no');
  8. }
  9. function qqLogin() {
  10. var url = "https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=101472393&redirect_uri=http://codergroup.cn/oauth/qq/callback&scope=get_user_info";
  11. openWin(url,"qqLogin",650,500);
  12. }
  13. </script>
  14. <a  href="javascript:void(0);" onclick="qqLogin()"></a>

② 在新窗口打开

  1. <a href="https://graph.qq.com/oauth2.0/authorizeresponse_type=code&client_id=101472393&redirect_uri=http://codergroup.cn/oauth/qq/callback&scope=get_user_info" target="_blank"></a>

三、具体代码

参考这里

1、由于做了多个登录,所以代码做了一定程度的封装,大致如下:

  1. //多个登录差不多都要共用这些方法,所以统一放到这个接口中
  2. public interface AuthService {
  3. public abstract String getAccessToken(String code);
  4. public abstract String getOpenId(String accessToken);
  5. public abstract String refreshToken(String code);
  6. public abstract String getAuthorizationUrl() throws UnsupportedEncodingException;
  7. public abstract JSONObject getUserInfo(String accessToken,String openId);
  8. }

2、由于全部是自己封装的,所以http请求的代码也是所有的登录共用的,这里统一放放到了类DefaultAuthServiceImpl中,代码如下:

  1. public abstract class DefaultAuthServiceImpl implements AuthService{
  2. public static RestTemplate getRestTemplate() {// 手动添加
  3. SimpleClientHttpRequestFactory requestFactory=new SimpleClientHttpRequestFactory();
  4. requestFactory.setReadTimeout(120000);
  5. List<HttpMessageConverter<?>> messageConverters = new LinkedList<>();
  6. messageConverters.add(new ByteArrayHttpMessageConverter());
  7. messageConverters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8));
  8. messageConverters.add(new ResourceHttpMessageConverter());
  9. messageConverters.add(new SourceHttpMessageConverter<Source>());
  10. messageConverters.add(new AllEncompassingFormHttpMessageConverter());
  11. messageConverters.add(new MappingJackson2HttpMessageConverter());
  12. RestTemplate restTemplate=new RestTemplate(messageConverters);
  13. restTemplate.setRequestFactory(requestFactory);
  14. return restTemplate;
  15. }
  16. }

由此,所有的登录Service只需要继承AuthService即可。

3、QQ登录 Service 接口

QQAuthService.java

  1. public interface QQAuthService extends AuthService {
  2. }

4、QQ登录 Service 实现

QQAuthServiceImpl.java

  1. @Service
  2. public class QQAuthServiceImpl extends DefaultAuthServiceImpl implements QQAuthService {
  3. private Logger logger = LoggerFactory.getLogger(QQAuthServiceImpl.class);
  4. //QQ 登陆页面的URL
  5. private final static String AUTHORIZATION_URL =
  6. "https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=%s&redirect_uri=%s&scope=%s";
  7. //获取token的URL
  8. private final static String ACCESS_TOKEN_URL = "https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&client_id=%s&client_secret=%s&code=%s&redirect_uri=%s";
  9. // 获取用户 openid 的 URL
  10. private static final String OPEN_ID_URL = "https://graph.qq.com/oauth2.0/me?access_token=%s";
  11. // 获取用户信息的 URL,oauth_consumer_key 为 apiKey
  12. private static final String USER_INFO_URL = "https://graph.qq.com/user/get_user_info?access_token=%s&oauth_consumer_key=%s&openid=%s";
  13. // 下面的属性可以通过配置读取
  14. private  static final String CALLBACK_URL = "http://XXX/XX/XX"; // QQ 在登陆成功后回调的 URL,这个 URL 必须在 QQ 互联里填写过
  15. private  static final String API_KEY  = "xxxxxx";                                      // QQ 互联应用管理中心的 APP ID
  16. private  static final String API_SECRET = "xxxxxx";               // QQ 互联应用管理中心的 APP Key
  17. private  static final String SCOPE       = "get_user_info";                                  // QQ 互联的 API 接口,访问用户资料
  18. /**
  19. * @return QQ 登陆页面的 URL
  20. */
  21. @Override
  22. public String getAuthorizationUrl() {
  23. String url = String.format(AUTHORIZATION_URL,API_KEY,CALLBACK_URL,SCOPE);
  24. return url;
  25. }
  26. @Override
  27. public String getAccessToken(String code) {
  28. String url = String.format(ACCESS_TOKEN_URL,API_KEY,API_SECRET,code, CALLBACK_URL);
  29. UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
  30. URI uri = builder.build().encode().toUri();
  31. String resp = getRestTemplate().getForObject(uri, String.class);
  32. logger.error("getAccessToken resp = "+resp);
  33. if(resp.contains("access_token")){
  34. Map<String,String> map = getParam(resp);
  35. String access_token = map.get("access_token");
  36. return access_token;
  37. }else{
  38. throw new ServiceException(resp);
  39. }
  40. }
  41. //由于QQ的几个接口返回类型不一样,此处是获取key-value类型的参数
  42. private Map<String,String> getParam(String string){
  43. Map<String,String> map = new HashMap();
  44. String[] kvArray = string.split("&");
  45. for(int i = 0;i<kvArray.length;i++){
  46. String[] kv = kvArray[i].split("=");
  47. map.put(kv[0],kv[1]);
  48. }
  49. return map;
  50. }
  51. //QQ接口返回类型是text/plain,此处将其转为json
  52. public JSONObject ConvertToJson(String string){
  53. string = string.substring(string.indexOf("(")+1,string.length());
  54. string = string.substring(0,string.indexOf(")"));
  55. logger.error("ConvertToJson s = "+string);
  56. JSONObject jsonObject = JSONObject.parseObject(string);
  57. return jsonObject;
  58. }
  59. @Override
  60. public String getOpenId(String accessToken) {
  61. String url = String.format(OPEN_ID_URL,accessToken);
  62. UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
  63. URI uri = builder.build().encode().toUri();
  64. String resp = getRestTemplate().getForObject(uri, String.class);
  65. logger.error("getAccessToken resp = "+resp);
  66. if(resp.contains("openid")){
  67. JSONObject jsonObject = ConvertToJson(resp);
  68. String openid = jsonObject.getString("openid");
  69. return openid;
  70. }else{
  71. throw new ServiceException(resp);
  72. }
  73. }
  74. /**
  75. * https://graph.qq.com/user/get_user_info?access_token=YOUR_ACCESS_TOKEN&oauth_consumer_key=YOUR_APP_ID&openid=YOUR_OPENID
  76. * @param accessToken
  77. * @param openId
  78. * @return
  79. */
  80. @Override
  81. public JSONObject getUserInfo(String accessToken, String openId){
  82. openId = getOpenId(accessToken);
  83. String url = String.format(USER_INFO_URL,accessToken, API_KEY, openId);
  84. UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
  85. URI uri = builder.build().encode().toUri();
  86. String resp = getRestTemplate().getForObject(uri,String.class);
  87. JSONObject data = JSONObject.parseObject(resp);
  88. logger.error("resp = "+data);
  89. JSONObject result = new JSONObject();
  90. result.put("id",openId);
  91. result.put("nickName",data.getString("nickname"));
  92. result.put("avatar",data.getString("figureurl_qq_1"));
  93. return result;
  94. }
  95. @Override
  96. public String refreshToken(String code) {
  97. return null;
  98. }
  99. }

5、在Controller中调用,代码如下:

  1. @RestController
  2. @RequestMapping(value = "/oauth")
  3. public class AuthController {
  4. private Logger logger = LoggerFactory.getLogger(AuthController.class);
  5. @Autowired
  6. private QQAuthService qqAuthService;
  7. @Autowired
  8. private UserService userService;
  9. //访问登陆页面,然后会跳转到 QQ 的登陆页面
  10. @RequestMapping(value = "/qqLoginPage",method = RequestMethod.GET)
  11. public JSONObject qqLogin() throws Exception {
  12. String uri = qqAuthService.getAuthorizationUrl();
  13. return loginPage(uri);
  14. }
  15. }
  16. //qq授权后会回调此方法,并将code传过来
  17. @RequestMapping("/qq/callback")
  18. public void getQQCode(String code, HttpServletRequest request,HttpServletResponse response) throws Exception {
  19. //根据code获取token
  20. String accessToken = qqAuthService.getAccessToken(code);
  21. // 保存 accessToken 到 cookie,过期时间为 30 天,便于以后使用
  22. Cookie cookie = new Cookie("accessToken", accessToken);
  23. cookie.setMaxAge(60 * 24 * 30);
  24. response.addCookie(cookie);
  25. //本网站是将用户的唯一标识存在用户表中,大家也可以加一张表,存储用户和QQ的对应信息。
  26. //根据openId判断用户是否已经绑定过
  27. String openId = qqAuthService.getOpenId(accessToken);
  28. KmsUser user = userService.getUserByCondition(openId);
  29. if (user == null) {
  30. //如果用户不存在,则跳转到绑定页面
  31. response.sendRedirect(request.getContextPath() + "/bind?type="+Constants.LOGIN_TYPE_QQ);
  32. } else {
  33. //如果用户已存在,则直接登录
  34. response.sendRedirect(request.getContextPath());
  35. }
  36. }

查看更多

SpringBoot网站添加第三方登录之GitHub登录

本文转载自

原文作者:言曌博客

原文链接:https://liuyanzhao.com/8210.html

第三方登录:QQ登录实现(OAuth2.0)的更多相关文章

  1. 第三方登录 QQ登录 人人网登录 新浪微博登录

    http://www.pp6.cn/Index.aspx http://www.pp6.cn/Login.aspx 网站有自己的账号系统,这里使用的第三方登录仅仅是获取第三方账号的唯一id,昵称,性别 ...

  2. 第三方登录 ----QQ登录

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

  3. 安卓Android第三方登录-QQ登录

    要实现QQ第三方登录,其实只需要一个封装类:QQLoginManager 几乎 三行代码 就实现QQ登录功能 这里先给出Github开源项目地址,项目下有详细的使用说明   下面就开始详细说一说怎么实 ...

  4. PHP第三方登录——QQ登录

    主要内容 简单回顾OAuth协议基本原理 接入QQ登录的前置条件以及开放平台账号申请 引入官方SDK SDK参数配置 SDK核心方法解读 整合QQ登录SDK到Web应用中 SDK优化 调用API的开发 ...

  5. 第三方账号登录--QQ登录,以及QQ微博账号登录

    在QQ登陆测试的时候,刚申请正常登陆,但是由于app未上线,或许是腾讯升级造成的个别时候QQ登陆无法成功会提示下图代码,功能上没啥问题,已经达到 测试效果了.附上腾讯错误代码图(大家测试QQ登陆的时候 ...

  6. 第三方登录:微信扫码登录(OAuth2.0)

    1.OAuth2.0 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. 允许用户提供 ...

  7. php微信开放平台--第三方网页微信扫码登录(OAuth2.0)

    第一.OAuth2.0 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. 允许用户提 ...

  8. 微信开放平台开发——网页微信扫码登录(OAuth2.0)

    1.OAuth2.0 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. 允许用户提供 ...

  9. 第三方登录(QQ登录)开发流程详解

    原文:http://www.cnblogs.com/it-cen/p/4338202.html 近排由于工作的繁忙,已经一个星期没写博文做分享了,接下来我对网站接入第三方登录----QQ登录的实现逻辑 ...

  10. (转)第三方登录(QQ登录)开发流程详解

    近排由于工作的繁忙,已经一个星期没写博文做分享了,接下来我对网站接入第三方登录----QQ登录的实现逻辑做一个详细的讲解. 对于整个流程的详细文档可以到QQ互联官网(http://wiki.conne ...

随机推荐

  1. LoadRunner改脚本

    加action,不支持嵌套大括号 Action(){int iCt = 0; iCt = lr_output_message("abcdefg"); iCt = funA(3,5) ...

  2. Codeforces Round #536 (Div. 2) B. Lunar New Year and Food Ordering

    #include <bits/stdc++.h> #define N 300010 #define PII pair<int, int> using namespace std ...

  3. VS IDE 中Visual C++ 中的项目属性配置

    VS IDE 中Visual C++ 中的项目属性配置 一. Visual C++ 项目系统基于 MSBuild. 虽然可以直接在命令行上编辑 XML 项目文件和属性表,我们仍建议你使用 VS IDE ...

  4. 异步多线程 Task理解

    一.简介 Task是.NET Framework4.0 TPL(任务并行库)提供的新的操作线程池线程的封装类.它提供等待.终止(取消).返回值.完成通知.失败通知.控制执行的先后次序等优化线程操作功能 ...

  5. Java-动态代理技术

    1.程序中的代理 为具有相同接口的目标类的各个方法,添加一些系统功能,如日志,异常处理,计算方法运行的 时间,事务管理等等,都可以交给另一个类去实现这些功能,该类称为代理类. 注意:为了让代理类共享目 ...

  6. Android-HttpClient-Get与Post请求登录功能

    HttpClient 是org.apache.http.* 包中的: 第一种方式使用httpclient-*.jar (需要在网上去下载httpclient-*.jar包) 把httpclient-4 ...

  7. hdu 1.2.7

    #include<cstdio> #include<iostream> using namespace std; int main() { //freopen("in ...

  8. sqlserver,杀掉死锁的进程

    USE [erpdb1]GO/****** Object:  StoredProcedure [dbo].[p_lockinfo_MyKill]    Script Date: 12/26/2014 ...

  9. 实验8 LCD8*8点阵

    1.控制点阵红绿交替显示,分别从上到下,从左到右循环闪烁三次 接线: P0接J12.P1接J20.P2接J19 /** 1.控制点阵红绿交替显示,分别从上到下,从左到右循环闪烁三次 **/ #incl ...

  10. .NET Entity Framework (with Oracle ODP.NET) -Code First

    上一篇文章介绍了.NET Entity Framework ,并演示了Model First模式,本文将继续讨论 Code First 模式的实现. 一.摘要 1.目标 本文验证了通过Oracle D ...