qq互联申请开发者账号

搞第三方登录,必须先进行接口的申请 得到授权;

QQ第三方接口的申请地址:QQ互联 https://connect.qq.com/index.html

申请之前,你必须有一个进行过国内备案过的网站,个人也可以;

登录QQ互联后,首先填写个人或者公司信息,然后申请网站应用,但是APP的话,需要申请移动应用.

个人信息

填写后,一般一周内审核

个人信息审核

应用信息

这里有个回调地址注意下,是用户进行第三方登录的时候会带上这个参数一起请求服务器,然后腾讯服务器再调用这个地址,顺便把用户信息带也过来,这样开发者的服务器就能得到用户信息了;

get_user_info接口窥探

申请通过过,腾讯开放平台给我们提供了get_user_info接口

我们得熟悉下这个接口,通过这个接口我们能获取到一些比如昵称,性别,头像等信息;

接口概要

接口概要

请求参数:

请求参数

请求Demo:

https://graph.qq.com/user/get_user_info?access_token=YOUR_ACCESS_TOKEN&oauth_consumer_key=YOUR_APP_ID&openid=YOUR_OPENID

返回Demo:

{
“ret”:0,
“msg”:””,
“nickname”:”YOUR_NICK_NAME”,

}

返回参数说明:

ret 返回码
msg 如果ret<0,会有相应的错误信息提示,返回数据全部用UTF-8编码。

  1. nickname 用户在QQ空间的昵称。
  2. figureurl 大小为30×30像素的QQ空间头像URL。
  3. figureurl_1 大小为50×50像素的QQ空间头像URL。
  4. figureurl_2 大小为100×100像素的QQ空间头像URL。
  5. figureurl_qq_1 大小为40×40像素的QQ头像URL。
  6. figureurl_qq_2 大小为100×100像素的QQ头像URL。需要注意,不是所有的用户都拥有QQ的100x100的头像,但40x40像素则是一定会有。
  7. gender 性别。 如果获取不到则默认返回”男”

鑫哥要说:大体原理了解,大体流程了解,看下面我的一顿猛操,直接撸代码,就几步搞定,坑我都已经填平了;

1.pom.xml 相关依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<!-- 热部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>

<!-- thymeleaf 模版 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- 以下是 qq wx 联合登陆需要的相关依赖工具 commons-io, commons-lang3,httpclient,fastjson-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.38</version>
</dependency>
</dependencies>

2. 配置文件信息

填写QQ互联的Appid,key,登录后回调地址(必须和QQ互联填写的一致,QQLogin 对应代码里的接口)

1
2
3
4
### QQ
constants.qqAppId= 101847701
constants.qqAppSecret= ******** #换自己密钥
constants.qqRedirectUrl= http://www.lovekhh.xyz/connect/qq

3. 读取配置文件信息常量类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

/**
* qq 登陆常量配置类
*/
@Configuration
@Data
public class Constants {

@Value("${constants.qqAppId}")
private String qqAppId;

@Value("${constants.qqAppSecret}")
private String qqAppSecret;

@Value("${constants.qqRedirectUrl}")
private String qqRedirectUrl;

@Value("${constants.weCatAppId}")
private String weCatAppId;

@Value("${constants.weCatAppSecret}")
private String weCatAppSecret;

@Value("${constants.weCatRedirectUrl}")
private String weCatRedirectUrl;

}

4. qq数据实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class QQUserInfo {

private Integer ret;
private String msg;
private Integer is_lost;
private String nickname;
private String gender;
private String province;
private String city;
private String year;
private String constellation;
private String figureurl;
private String figureurl_1;
private String figureurl_2;
private String figureurl_qq;
private String figureurl_qq_1;
private String figureurl_qq_2;
private String is_yellow_vip;
private String vip;
private String yellow_vip_level;
private String level;
private String is_yellow_year_vip;

//自行生成 set get
}

5.Http工具类 HttpClientUtils.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;

/**
* Created by Administrator on 2018/10/30/030.
*/

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;

@SuppressWarnings("all")
public class HttpClientUtils {

public static final int connTimeout = 10000;
public static final int readTimeout = 10000;
public static final String charset = "UTF-8";
private static HttpClient client = null;

static {
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(128);
cm.setDefaultMaxPerRoute(128);
client = HttpClients.custom().setConnectionManager(cm).build();
}

public static String postParameters(String url, String parameterStr)
throws ConnectTimeoutException, SocketTimeoutException, Exception {
return post(url, parameterStr, "application/x-www-form-urlencoded", charset, connTimeout, readTimeout);
}

public static String postParameters(String url, String parameterStr, String charset, Integer connTimeout,
Integer readTimeout) throws ConnectTimeoutException, SocketTimeoutException, Exception {
return post(url, parameterStr, "application/x-www-form-urlencoded", charset, connTimeout, readTimeout);
}

public static String postParameters(String url, Map<String, String> params)
throws ConnectTimeoutException, SocketTimeoutException, Exception {
return postForm(url, params, null, connTimeout, readTimeout);
}

public static String postParameters(String url, Map<String, String> params, Integer connTimeout,
Integer readTimeout) throws ConnectTimeoutException, SocketTimeoutException, Exception {
return postForm(url, params, null, connTimeout, readTimeout);
}

public static String get(String url) throws Exception {
return get(url, charset, null, null);
}

public static String get(String url, String charset) throws Exception {
return get(url, charset, connTimeout, readTimeout);
}

/**
* 发送一个 Post 请求, 使用指定的字符集编码.
*
* @param url
* @param body RequestBody
* @param mimeType 例如 application/xml "application/x-www-form-urlencoded"
* a=1&b=2&c=3
* @param charset 编码
* @param connTimeout 建立链接超时时间,毫秒.
* @param readTimeout 响应超时时间,毫秒.
* @return ResponseBody, 使用指定的字符集编码.
* @throws ConnectTimeoutException 建立链接超时异常
* @throws SocketTimeoutException 响应超时
* @throws Exception
*/
public static String post(String url, String body, String mimeType, String charset, Integer connTimeout,
Integer readTimeout) throws ConnectTimeoutException, SocketTimeoutException, Exception {
HttpClient client = null;
HttpPost post = new HttpPost(url);
String result = "";
try {
if (StringUtils.isNotBlank(body)) {
HttpEntity entity = new StringEntity(body, ContentType.create(mimeType, charset));
post.setEntity(entity);
}
// 设置参数
Builder customReqConf = RequestConfig.custom();
if (connTimeout != null) {
customReqConf.setConnectTimeout(connTimeout);
}
if (readTimeout != null) {
customReqConf.setSocketTimeout(readTimeout);
}
post.setConfig(customReqConf.build());

HttpResponse res;
if (url.startsWith("https")) {
// 执行 Https 请求.
client = createSSLInsecureClient();
res = client.execute(post);
} else {
// 执行 Http 请求.
client = HttpClientUtils.client;
res = client.execute(post);
}
result = IOUtils.toString(res.getEntity().getContent(), charset);
} finally {
post.releaseConnection();
if (url.startsWith("https") && client != null && client instanceof CloseableHttpClient) {
((CloseableHttpClient) client).close();
}
}
return result;
}

/**
* 提交form表单
*
* @param url
* @param params
* @param connTimeout
* @param readTimeout
* @return
* @throws ConnectTimeoutException
* @throws SocketTimeoutException
* @throws Exception
*/
public static String postForm(String url, Map<String, String> params, Map<String, String> headers,
Integer connTimeout, Integer readTimeout)
throws ConnectTimeoutException, SocketTimeoutException, Exception {

HttpClient client = null;
HttpPost post = new HttpPost(url);
try {
if (params != null && !params.isEmpty()) {
List<NameValuePair> formParams = new ArrayList<org.apache.http.NameValuePair>();
Set<Entry<String, String>> entrySet = params.entrySet();
for (Entry<String, String> entry : entrySet) {
formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams, Consts.UTF_8);
post.setEntity(entity);
}

if (headers != null && !headers.isEmpty()) {
for (Entry<String, String> entry : headers.entrySet()) {
post.addHeader(entry.getKey(), entry.getValue());
}
}
// 设置参数
Builder customReqConf = RequestConfig.custom();
if (connTimeout != null) {
customReqConf.setConnectTimeout(connTimeout);
}
if (readTimeout != null) {
customReqConf.setSocketTimeout(readTimeout);
}
post.setConfig(customReqConf.build());
HttpResponse res = null;
if (url.startsWith("https")) {
// 执行 Https 请求.
client = createSSLInsecureClient();
res = client.execute(post);
} else {
// 执行 Http 请求.
client = HttpClientUtils.client;
res = client.execute(post);
}
return IOUtils.toString(res.getEntity().getContent(), "UTF-8");
} finally {
post.releaseConnection();
if (url.startsWith("https") && client != null && client instanceof CloseableHttpClient) {
((CloseableHttpClient) client).close();
}
}
}

/**
* 发送一个 GET 请求
*
* @param url
* @param charset
* @param connTimeout 建立链接超时时间,毫秒.
* @param readTimeout 响应超时时间,毫秒.
* @return
* @throws ConnectTimeoutException 建立链接超时
* @throws SocketTimeoutException 响应超时
* @throws Exception
*/
public static String get(String url, String charset, Integer connTimeout, Integer readTimeout)
throws ConnectTimeoutException, SocketTimeoutException, Exception {

HttpClient client = null;
HttpGet get = new HttpGet(url);
String result = "";
try {
// 设置参数
Builder customReqConf = RequestConfig.custom();
if (connTimeout != null) {
customReqConf.setConnectTimeout(connTimeout);
}
if (readTimeout != null) {
customReqConf.setSocketTimeout(readTimeout);
}
get.setConfig(customReqConf.build());

HttpResponse res = null;

if (url.startsWith("https")) {
// 执行 Https 请求.
client = createSSLInsecureClient();
res = client.execute(get);
} else {
// 执行 Http 请求.
client = HttpClientUtils.client;
res = client.execute(get);
}

result = IOUtils.toString(res.getEntity().getContent(), charset);
} finally {
get.releaseConnection();
if (url.startsWith("https") && client != null && client instanceof CloseableHttpClient) {
((CloseableHttpClient) client).close();
}
}
return result;
}

/**
* 从 response 里获取 charset
*
* @param ressponse
* @return
*/
@SuppressWarnings("unused")
private static String getCharsetFromResponse(HttpResponse ressponse) {
// Content-Type:text/html; charset=GBK
if (ressponse.getEntity() != null && ressponse.getEntity().getContentType() != null
&& ressponse.getEntity().getContentType().getValue() != null) {
String contentType = ressponse.getEntity().getContentType().getValue();
if (contentType.contains("charset=")) {
return contentType.substring(contentType.indexOf("charset=") + 8);
}
}
return null;
}

/**
* 创建 SSL连接
*
* @return
* @throws GeneralSecurityException
*/
private static CloseableHttpClient createSSLInsecureClient() throws GeneralSecurityException {
try {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
}).build();

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new X509HostnameVerifier() {

@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}

@Override
public void verify(String host, SSLSocket ssl) throws IOException {
}

@Override
public void verify(String host, X509Certificate cert) throws SSLException {
}

@Override
public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
}

});

return HttpClients.custom().setSSLSocketFactory(sslsf).build();

} catch (GeneralSecurityException e) {
throw e;
}
}

public static void main(String[] args) {
try {
String str = post("https://localhost:443/ssl/test.shtml", "name=12&page=34",
"application/x-www-form-urlencoded", "UTF-8", 10000, 10000);
// String str=
// get("https://localhost:443/ssl/test.shtml?name=12&page=34","GBK");
/*
* Map<String,String> map = new HashMap<String,String>(); map.put("name",
* "111"); map.put("page", "222"); String str=
* postForm("https://localhost:443/ssl/test.shtml",map,null, 10000, 10000);
*/
System.out.println(str);
} catch (ConnectTimeoutException e) {
e.printStackTrace();
} catch (SocketTimeoutException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}

}

6. url转码工具类 URLEncodeUtil.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import java.io.UnsupportedEncodingException;

public class URLEncodeUtil {
private final static String ENCODE = "UTF-8";
/**
* URL 解码
*/
public static String getURLDecoderString(String str) {
String result = "";
if (null == str) {
return "";
}
try {
result = java.net.URLDecoder.decode(str, ENCODE);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return result;
}
/**
* URL 转码
*/
public static String getURLEncoderString(String str) {
String result = "";
if (null == str) {
return "";
}
try {
result = java.net.URLEncoder.encode(str, ENCODE);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return result;
}
}

7. Conteoller(实现qq登录层)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
package com.zx.qqlogin.controller;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpSession;

import com.zx.qqlogin.config.Constants;
import com.zx.qqlogin.config.HttpClientUtils;
import com.zx.qqlogin.config.QQUserInfo;
import com.zx.qqlogin.config.URLEncodeUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSON;


/**
* qq登录
*
* @author zx
* @date 2020年3月10日 下午8:04:15
*/
@Controller
public class QQController {

/**
* QQ :读取Appid相关配置信息静态类
*/
@Autowired
private Constants constants;


/**
* 登录页
*/
@GetMapping("/")
public String login() {
return "login";
}

/**
* 获得跳转到qq登录页的url,前台直接a连接访问
*
* @author wangsong
* @date 2019年6月18日 下午8:29:20
* @param session
* @return
* @throws Exception
*
*/
@GetMapping("/getQQCode")
public String getCode(HttpSession session, Model model) throws Exception {
// 拼接url
StringBuilder url = new StringBuilder();
url.append("https://graph.qq.com/oauth2.0/authorize?");
url.append("response_type=code");
url.append("&client_id=" + constants.getQqAppId());
// 回调地址 ,回调地址要进行Encode转码
String redirect_uri = constants.getQqRedirectUrl();
// 转码
url.append("&redirect_uri=" + URLEncodeUtil.getURLEncoderString(redirect_uri));
url.append("&state=ok");
// HttpClientUtils.get(url.toString(), "UTF-8");
System.out.println(url.toString());
return "redirect:" + url;
}



/**
* 开始登录
*
* @param code
* @param
* @param 实际业务:token过期调用刷新 token重新获取token信息
* @param 数据库字段: accessToken,expiresIn,refreshToken,openId
* @return
* @throws Exception
*/
@GetMapping("/connect/qq")
@ResponseBody
public QQUserInfo QQLogin(String code, Model model) throws Exception {
if (code != null) {
System.out.println(code);
}
//获取tocket
Map<String, Object> qqProperties = getToken(code);
//获取openId(每个用户的openId都是唯一不变的)
String openId = getOpenId(qqProperties);
qqProperties.put("openId",openId);

//tocket过期刷新token
//Map<String, Object> refreshToken = refreshToken(qqProperties);

//获取数据
QQUserInfo userInfo = getUserInfo(qqProperties);
return userInfo;
}

/**
* 获得token信息(授权,每个用户的都不一致) --> 获得token信息该步骤返回的token期限为一个月
*
* @param (保存到Map<String,String> qqProperties)
* @author wangsong
* @return
* @throws Exception
* @date 2019年6月18日 下午8:56:45
*/
public Map<String, Object> getToken(String code) throws Exception {
StringBuilder url = new StringBuilder();
url.append("https://graph.qq.com/oauth2.0/token?");
url.append("grant_type=authorization_code");

url.append("&client_id=" + constants.getQqAppId());
url.append("&client_secret=" + constants.getQqAppSecret());
url.append("&code=" + code);
// 回调地址
String redirect_uri = constants.getQqRedirectUrl();
// 转码
url.append("&redirect_uri=" + URLEncodeUtil.getURLEncoderString(redirect_uri));
// 获得token
String result = HttpClientUtils.get(url.toString(), "UTF-8");
System.out.println("url:" + url.toString());
// 把token保存
String[] items = StringUtils.splitByWholeSeparatorPreserveAllTokens(result, "&");
String accessToken = StringUtils.substringAfterLast(items[0], "=");
Long expiresIn = new Long(StringUtils.substringAfterLast(items[1], "="));
String refreshToken = StringUtils.substringAfterLast(items[2], "=");
//token信息
Map<String,Object > qqProperties = new HashMap<String,Object >();
qqProperties.put("accessToken", accessToken);
qqProperties.put("expiresIn", String.valueOf(expiresIn));
qqProperties.put("refreshToken", refreshToken);
return qqProperties;
}

/**
* 刷新token 信息(token过期,重新授权)
*
* @return
* @throws Exception
*/
@GetMapping("/refreshToken")
public Map<String,Object> refreshToken(Map<String,Object> qqProperties) throws Exception {
// 获取refreshToken
String refreshToken = (String) qqProperties.get("refreshToken");
StringBuilder url = new StringBuilder("https://graph.qq.com/oauth2.0/token?");
url.append("grant_type=refresh_token");
url.append("&client_id=" + constants.getQqAppId());
url.append("&client_secret=" + constants.getQqAppSecret());
url.append("&refresh_token=" + refreshToken);
System.out.println("url:" + url.toString());
String result = HttpClientUtils.get(url.toString(), "UTF-8");
// 把新获取的token存到map中
String[] items = StringUtils.splitByWholeSeparatorPreserveAllTokens(result, "&");
String accessToken = StringUtils.substringAfterLast(items[0], "=");
Long expiresIn = new Long(StringUtils.substringAfterLast(items[1], "="));
String newRefreshToken = StringUtils.substringAfterLast(items[2], "=");
//重置信息
qqProperties.put("accessToken", accessToken);
qqProperties.put("expiresIn", String.valueOf(expiresIn));
qqProperties.put("refreshToken", newRefreshToken);
return qqProperties;
}

/**
* 获取用户openId(根据token)
*
* @param 把openId存到map中
* @return
* @throws Exception
*/
public String getOpenId(Map<String,Object> qqProperties) throws Exception {
// 获取保存的用户的token
String accessToken = (String) qqProperties.get("accessToken");
if (!StringUtils.isNotEmpty(accessToken)) {
// return "未授权";
}
StringBuilder url = new StringBuilder("https://graph.qq.com/oauth2.0/me?");
url.append("access_token=" + accessToken);
String result = HttpClientUtils.get(url.toString(), "UTF-8");
String openId = StringUtils.substringBetween(result, "\"openid\":\"", "\"}");
return openId;
}

/**
* 根据token,openId获取用户信息
*/
public QQUserInfo getUserInfo(Map<String,Object> qqProperties) throws Exception {
// 取token
String accessToken = (String) qqProperties.get("accessToken");
String openId = (String) qqProperties.get("openId");
if (!StringUtils.isNotEmpty(accessToken) || !StringUtils.isNotEmpty(openId)) {
return null;
}
//拼接url
StringBuilder url = new StringBuilder("https://graph.qq.com/user/get_user_info?");
url.append("access_token=" + accessToken);
url.append("&oauth_consumer_key=" + constants.getQqAppId());
url.append("&openid=" + openId);
// 获取qq相关数据
String result = HttpClientUtils.get(url.toString(), "UTF-8");
Object json = JSON.parseObject(result, QQUserInfo.class);
QQUserInfo userInfo = (QQUserInfo) json;
return userInfo;
}
}


8.Html页面

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="/getQQCode">qq登录</a>
</body>
</html>


9. 效果

运行点击QQ登录

点击头像第三方登录

点击登录

获取用户信息

用户信息