1.准备工作
移动应用微信登录是基于OAuth2.0协议标准 构建的微信OAuth2.0授权登录系统。
在进行微信OAuth2.0授权登录接入之前,在微信开放平台注册开发者帐号,并拥有一个已审核通过的移动应用,并获得相应的AppID和AppSecret,申请微信登录且通过审核后,可开始接入流程。
2.授权流程说明
第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数;
通过code参数加上AppID和AppSecret等,通过API换取access_token;
通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。
3. 获取access_token时序图:
在这里插入图片描述
4. maven依赖
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<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>
<version>3.4</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.38</version>
</dependency>
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
5.在application.yml文件中配置你的
#第三方微信登录(用你自己的)
#appID App的ID
#appSecret
weixinconfig:
weixinappID: wxf7865421a3c4d5f
weixinappSecret: 6cdbe6d4ce6sbcf0593c913d8a0ce12
创建配置类
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix="weixinconfig")
public class WeixinLoginProperties {
private String weixinappID; // 商户appid
private String weixinappSecret; // 私钥 pkcs8格式的
public String getWeixinappID() {
return weixinappID;
}
public void setWeixinappID(String weixinappID) {
this.weixinappID = weixinappID;
}
public String getWeixinappSecret() {
return weixinappSecret;
}
public void setWeixinappSecret(String weixinappSecret) {
this.weixinappSecret = weixinappSecret;
}
}
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
6.第一步:请求CODE
这一步客户端会把code传过来 ,不用你操心
7.第二步:通过code获取access_token
package io.renren.api.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.configurationprocessor.json.JSONException;
import org.springframework.boot.configurationprocessor.json.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import io.renren.api.dao.TpAccesstokenMapper;
import io.renren.api.dao.TpUsersMapper;
import io.renren.api.entity.TpAccesstoken;
import io.renren.api.entity.TpAccesstokenExample;
import io.renren.api.entity.TpAccumulativeAward;
import io.renren.api.entity.TpUsers;
import io.renren.api.entity.TpUsersExample;
import io.renren.api.properties.WeixinLoginProperties;
import io.renren.api.service.TpAccesstokenService;
import io.renren.api.service.TpAccumulativeAwardService;
import io.renren.api.service.TpUsersService;
import io.renren.common.utils.R;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.URI;
import java.util.List;
import javax.annotation.Resource;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
/**
* 第三方微信登录
* @author Administrator
*
*/
@SuppressWarnings("deprecation")
@Controller
@RequestMapping("/api")
public class WeXinController {
//微信公众平台申请
//应用唯一标识,在微信开放平台提交应用审核通过后获得 appID
//应用密钥AppSecret,在微信开放平台提交应用审核通过后获得 appSecret
//TpAccesstoken 用来保存微信返回的用户信息oppid等
@Resource
private WeixinLoginProperties weixinLoginProperties;
@Autowired
TpUsersService tpUsersService;
@Autowired
TpUsersMapper tpUsersMapper;
@Autowired
TpAccesstokenService tpAccesstokenService;
@Autowired
TpAccesstokenMapper tpAccesstokenMapper;
@Autowired
TpAccumulativeAwardService tpAccumulativeAwardService;
/**
* 获取accessToken,该步骤返回的accessToken期限为一个月
*
* @param code
* @return
* @throws Exception
*/
@SuppressWarnings("all")
@RequestMapping("weixincallback")
@ResponseBody
public R getAccessToken(String code) throws Exception {
String appID = weixinLoginProperties.getWeixinappID();
String appSecret = weixinLoginProperties.getWeixinappSecret();
String accesstoken;
String openid = null;
String refreshtoken;
int expiresIn;
String unionid;//可通过获取用户基本信息中的unionid来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号,
//用户的unionid是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。
if (code != null) {
System.out.println(code);
}
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+appID+"&secret="+appSecret+"&code="+code+"&grant_type=authorization_code";
URI uri = URI.create(url);
org.apache.http.client.HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(uri);
HttpResponse response;
try {
response = client.execute(get);
if (response.getStatusLine().getStatusCode() == 200) {
HttpEntity entity = response.getEntity();
BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8"));
StringBuilder sb = new StringBuilder();
for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) {
sb.append(temp);
}
JSONObject object = new JSONObject(sb.toString().trim());
System.out.println("object:"+object);
accesstoken = object.getString("access_token");
System.out.println("accesstoken:"+accesstoken);
openid = object.getString("openid");
System.out.println("openid:"+openid);
refreshtoken = object.getString("refresh_token");
System.out.println("refreshtoken:"+refreshtoken);
expiresIn = (int) object.getLong("expires_in");
unionid = object.getString("unionid");
// 将用户信息保存到数据库
//1.先查询用户是否是第一次第三方登录如果是第一次那么是将用户信息添加到数据库 如果不是那么是更新到数据库
TpUsers userInfo = getUserInfo(accesstoken,openid);
Integer userId = userInfo.getUserId();
TpAccesstokenExample example = new TpAccesstokenExample();
example.createCriteria().andOpenidEqualTo(openid);
List<TpAccesstoken> list = tpAccesstokenMapper.selectByExample(example);
if(list!=null&&list.size()>0) {
//那么该用户不是第一次 执行更新操作
TpAccesstoken tpAccesstoken = list.get(0);
tpAccesstoken.setAccesstoken(accesstoken);
tpAccesstoken.setUserId(userId);
tpAccesstoken.setExpiresIn(expiresIn);
tpAccesstoken.setOpenid(openid);
tpAccesstoken.setRefreshtoken(refreshtoken);
tpAccesstokenService.save(tpAccesstoken);
}else {
TpAccesstoken tpAccesstoken=new TpAccesstoken();
tpAccesstoken.setUserId(userId);
tpAccesstoken.setAccesstoken(accesstoken);
tpAccesstoken.setExpiresIn(expiresIn);
tpAccesstoken.setOpenid(openid);
tpAccesstoken.setRefreshtoken(refreshtoken);
tpAccesstokenService.save(tpAccesstoken);
//tpAccesstokenService.insertAccesstoken(userId,openid, accesstoken, expiresIn, refreshtoken);
}
//refreshAccessToken(openid);
System.out.println("Openid"+userInfo.getOpenid());
return R.ok().put("userInfo", userInfo).put("openid", openid);
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return R.ok().put("openid", openid);
}
/*
*
* 1 { 2 "access_token":"ACCESS_TOKEN", 3 "expires_in":7200, 4
* "refresh_token":"REFRESH_TOKEN", 5 "openid":"OPENID", 6 "scope":"SCOPE", 7
* "unionid":"o6_bmasdasdsad6_2sgVt7hMZOPfL" 8 } 复制代码 复制代码 参数 说明 access_token
* 接口调用凭证 expires_in access_token 接口调用凭证超时时间,单位(秒) refresh_token
* 用户刷新access_token openid 授权用户唯一标识 scope 用户授权的作用域,使用逗号(,)分隔 unionid
* 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。
*
*/
/**
* 刷新token
*
* @param openID
* @return
*/
@SuppressWarnings({ "unused", "resource" })
private void refreshAccessToken(String openid) {
String refreshtoken=null;
TpAccesstoken tpAccesstoken=new TpAccesstoken();
String appID = weixinLoginProperties.getWeixinappID();
String appSecret = weixinLoginProperties.getWeixinappSecret();
TpAccesstokenExample example = new TpAccesstokenExample();
example.createCriteria().andOpenidEqualTo(openid);
List<TpAccesstoken> list = tpAccesstokenMapper.selectByExample(example);
if(list!=null&&list.size()>0) {
tpAccesstoken = list.get(0);
refreshtoken = tpAccesstoken.getRefreshtoken();
}
String uri = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid="+appID+"&grant_type=refresh_token&refresh_token="+refreshtoken;
org.apache.http.client.HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(URI.create(uri));
try {
HttpResponse response = client.execute(get);
if (response.getStatusLine().getStatusCode() == 200) {
BufferedReader reader = new BufferedReader(
new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
StringBuilder builder = new StringBuilder();
for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) {
builder.append(temp);
}
JSONObject object = new JSONObject(builder.toString().trim());
String accessToken = object.getString("access_token");
String refreshToken = object.getString("refresh_token");
openid = object.getString("openid");
int expires_in = (int) object.getLong("expires_in");
tpAccesstoken.setAccesstoken(accessToken);
tpAccesstoken.setExpiresIn(expires_in);
tpAccesstoken.setOpenid(openid);
tpAccesstoken.setRefreshtoken(refreshToken);
tpAccesstokenService.save(tpAccesstoken);
}
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 根据accessToken获取用户信息
*
* @param accessToken
* @param openID
* @return
* @throws Exception
*/
@SuppressWarnings({ "unused", "resource" })
public TpUsers getUserInfo(String accessToken, String openID) throws Exception {
String appID = weixinLoginProperties.getWeixinappID();
String appSecret = weixinLoginProperties.getWeixinappSecret();
String uri = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openID;
org.apache.http.client.HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(URI.create(uri));
try {
HttpResponse response = client.execute(get);
if (response.getStatusLine().getStatusCode() == 200) {
BufferedReader reader = new BufferedReader(
new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
StringBuilder builder = new StringBuilder();
for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) {
builder.append(temp);
}
JSONObject object = new JSONObject(builder.toString().trim());
String country = object.getString("country");
String nikeName = object.getString("nickname");
String unionid = object.getString("unionid");
String province = object.getString("province");
String city = object.getString("city");
String openid = object.getString("openid");
String sex = object.getString("sex");
String headimgurl = object.getString("headimgurl");
String language = object.getString("language");
BigDecimal bigDecimal=new BigDecimal(0.0);
TpUsersExample example=new TpUsersExample();
example.createCriteria().andOpenidEqualTo(openid);
List<TpUsers> list = tpUsersMapper.selectByExample(example);
if(list!=null&&list.size()>0) {
TpUsers tpUsers = list.get(0);
System.out.println("---------");
return tpUsers;
}else {
TpUsers tpUsers=new TpUsers();
tpUsers.setOauth("wx");
tpUsers.setOpenid(openid);
tpUsers.setUnionid(unionid);
tpUsers.setUserName(nikeName);
tpUsers.setUserMoney(bigDecimal);
tpUsersService.save(tpUsers);
System.out.println("+++++++");
return tpUsers;
}
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
@RequestMapping("/isaccesstoken")
@SuppressWarnings({ "resource" })
private boolean isAccessTokenIsInvalid(String accessToken,String openID) {
String url = "https://api.weixin.qq.com/sns/auth?access_token=" + accessToken + "&openid=" + openID;
URI uri = URI.create(url);
org.apache.http.client.HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(uri);
HttpResponse response;
try {
response = client.execute(get);
if (response.getStatusLine().getStatusCode() == 200) {
HttpEntity entity = response.getEntity();
BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8"));
StringBuilder sb = new StringBuilder();
for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) {
sb.append(temp);
}
JSONObject object = new JSONObject(sb.toString().trim());
/* {
"errcode":0,"errmsg":"ok"
}
错误的Json返回示例:
{
"errcode":40003,"errmsg":"invalid openid"
}*/
int errorCode = object.getInt("errcode");
if (errorCode == 0) {
return true;
}
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return false;
}
}
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
获取第一步的code后,请求以下链接进行refresh_token:
https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
参数说明
参数 是否必须 说明
appid 是 应用唯一标识
grant_type 是 填refresh_token
refresh_token 是 填写通过access_token获取到的refresh_token参数
返回说明
正确的返回:
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE"
}
参数 说明
access_token 接口调用凭证
expires_in access_token接口调用凭证超时时间,单位(秒)
refresh_token 用户刷新access_token
openid 授权用户唯一标识
scope 用户授权的作用域,使用逗号(,)分隔
错误返回样例:
{"errcode":40030,"errmsg":"invalid refresh_token"}
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
刷新或续期access_token使用
接口说明
access_token是调用授权关系接口的调用凭证,由于access_token有效期(目前为2个小时)较短,当access_token超时后,可以使用refresh_token进行刷新,access_token刷新结果有两种:
1.若access_token已超时,那么进行refresh_token会获取一个新的access_token,新的超时时间;
2.若access_token未超时,那么进行refresh_token不会改变access_token,但超时时间会刷新,相当于续期access_token。
refresh_token拥有较长的有效期(30天)且无法续期,当refresh_token失效的后,需要用户重新授权后才可以继续获取用户头像昵称。
请求方法
使用/sns/oauth2/access_token接口获取到的refresh_token进行以下接口调用:
http请求方式: GET
https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
参数说明
参数 是否必须 说明
appid 是 应用唯一标识
grant_type 是 填refresh_token
refresh_token 是 填写通过access_token获取到的refresh_token参数
返回说明
正确的返回:
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE"
}
参数 说明
access_token 接口调用凭证
expires_in access_token接口调用凭证超时时间,单位(秒)
refresh_token 用户刷新access_token
openid 授权用户唯一标识
scope 用户授权的作用域,使用逗号(,)分隔
错误返回样例:
{
"errcode":40030,"errmsg":"invalid refresh_token"
}
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
获取用户个人信息(UnionID机制)
接口说明
此接口用于获取用户个人信息。开发者可通过OpenID来获取用户基本信息。特别需要注意的是,如果开发者拥有多个移动应用、网站应用和公众帐号,可通过获取用户基本信息中的unionid来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号,用户的unionid是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。请注意,在用户修改微信头像后,旧的微信头像URL将会失效,因此开发者应该自己在获取用户信息后,将头像图片保存下来,避免微信头像URL失效后的异常情况。
请求说明
http请求方式: GET
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
参数说明
参数 是否必须 说明
access_token 是 调用凭证
openid 是 普通用户的标识,对当前开发者帐号唯一
lang 否 国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语,默认为zh-CN
返回说明
正确的Json返回结果:
{
"openid":"OPENID",
"nickname":"NICKNAME",
"sex":1,
"province":"PROVINCE",
"city":"CITY",
"country":"COUNTRY",
"headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
"privilege":[
"PRIVILEGE1",
"PRIVILEGE2"
],
"unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
参数 说明
openid 普通用户的标识,对当前开发者帐号唯一
nickname 普通用户昵称
sex 普通用户性别,1为男性,2为女性
province 普通用户个人资料填写的省份
city 普通用户个人资料填写的城市
country 国家,如中国为CN
headimgurl 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空
privilege 用户特权信息,json数组,如微信沃卡用户为(chinaunicom)
unionid 用户统一标识。针对一个微信开放平台帐号下的应用,同一用户的unionid是唯一的。
建议:
开发者最好保存unionID信息,以便以后在不同应用之间进行用户信息互通。
错误的Json返回示例:
{
"errcode":40003,"errmsg":"invalid openid"
}
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
工具类
package io.renren.common.utils;
import java.util.HashMap;
import java.util.Map;
/**
* 返回数据
*
* @author chenshun
* @email [email protected]
* @date 2016年10月27日 下午9:59:27
*/
public class R extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
public R() {
put("code", 0);
put("msg", "success");
}
public static R error() {
return error(500, "未知异常,请联系管理员");
}
public static R error(String msg) {
return error(500, msg);
}
public static R error(int code, String msg) {
R r = new R();
r.put("code", code);
r.put("msg", msg);
return r;
}
public static R ok(String msg) {
R r = new R();
r.put("msg", msg);
return r;
}
public static R ok(Map<String, Object> map) {
R r = new R();
r.putAll(map);
return r;
}
public static R ok() {
return new R();
}
@Override
public R put(String key, Object value) {
super.put(key, value);
return this;
}
}
————————————————
原文链接:https://blog.csdn.net/weixin_42694286/java/article/details/84344786
SpringBoot 实现App第三方微信登录
猜你喜欢
转载自www.cnblogs.com/uzxin/p/13385264.html
今日推荐
周排行