转自:http://www.cuiyongzhi.com/post/78.htmlphp
好长时间没有写文章了,主要是最近的工做和生活上的事情比较多并且繁琐,其实到如今我依然仍是感受有些迷茫,最后仍是决定静下心来坚持一开始的选择,继续咱们的微信系列文章的后续更新,也但愿在本身有时间的时候能把更多的内容呈现给你们,前面一系列的文章讲述了不少微信开发相关的基础知识点 【微信系列文章】,那么从这一篇开始将讲述微信较深一层次或者说在产品应用中时刻会用到的一些技术点,那么下面就让咱们进入正题吧,这一篇我要讲述的是在微信服务号开发中经常使用到的微信网页受权(OAuth2.0受权)获取用户基本信息!html
咱们来讲下OAuth2.0受权的一些应用场景,例如:示例①但愿用户在点击打开一个网页的时候能够获取该用户的微信昵称,微信头像等;示例②:当某个用户在咱们会员系统中,但愿用户在直接打开网页的时候展现用户在咱们的会员系统中的积分状况和消费信息等...,那么这一系列的应用场景中咱们是如何在一个网页中获取微信用户的相关信息的呢?这里咱们就要用到微信网页受权的功能来解决咱们遇到的难题了!前端
(一)首先在咱们开始应用OAuth2.0受权以前咱们先来了解一下它,看他自己的实现流程和机制!java
①关于网页受权回调域名的说明web
在微信公众号请求用户网页受权以前,开发者须要先到公众平台官网中的开发者中心页配置受权回调域名。请注意,这里填写的是域名(是一个字符串),而不是URL,所以请勿加 http:// 等协议头;json
受权回调域名配置规范为全域名,好比须要网页受权的域名为:www.qq.com,配置之后此域名下面的页面http://www.qq.com/music.html 、 http://www.qq.com/login.html 均可以进行OAuth2.0鉴权。但http://pay.qq.com 、 http://music.qq.com 、 http://qq.com没法进行OAuth2.0鉴权api
若是公众号登陆受权给了第三方开发者来进行管理,则没必要作任何设置,由第三方代替公众号实现网页受权便可安全
②关于网页受权的两种scope的区别说明服务器
以snsapi_base为scope发起的网页受权,是用来获取进入页面的用户的openid的,而且是静默受权并自动跳转到回调页的。用户感知的就是直接进入了回调页(每每是业务页面)微信
以snsapi_userinfo为scope发起的网页受权,是用来获取用户的基本信息的。但这种受权须要用户手动赞成,而且因为用户赞成过,因此无须关注,就可在受权后获取该用户的基本信息。
用户管理类接口中的“获取用户基本信息接口”,是在用户和公众号产生消息交互或关注后事件推送后,才能根据用户OpenID来获取用户基本信息。这个接口,包括其余微信接口,都是须要该用户(即openid)关注了公众号后,才能调用成功的。
③关于网页受权access_token和普通access_token的区别(参见:微信开发中的token获取)
微信网页受权是经过OAuth2.0机制实现的,在用户受权给公众号后,公众号能够获取到一个网页受权特有的接口调用凭证(网页受权access_token),经过网页受权access_token能够进行受权后接口调用,如获取用户基本信息;
其余微信接口,须要经过基础支持中的“获取access_token”接口来获取到的普通access_token调用。
④关于UnionID机制(参见:开发中微信公众平台/开放平台/商户平台的关联)
请注意,网页受权获取用户基本信息也遵循UnionID机制。即若是开发者有在多个公众号,或在公众号、移动应用之间统一用户账号的需求,须要前往微信开放平台(open.weixin.qq.com)绑定公众号后,才可利用UnionID机制来知足上述需求。
UnionID机制的做用说明:若是开发者拥有多个移动应用、网站应用和公众账号,可经过获取用户基本信息中的unionid来区分用户的惟一性,由于同一用户,对同一个微信开放平台下的不一样应用(移动应用、网站应用和公众账号),unionid是相同的。
⑤关于特殊场景下的静默受权
上面已经提到,对于以snsapi_base为scope的网页受权,就静默受权的,用户无感知;
对于已关注公众号的用户,若是用户从公众号的会话或者自定义菜单进入本公众号的网页受权页,即便是scope为snsapi_userinfo,也是静默受权,用户无感知。
(二)OAuth2.0受权获取用户微信信息的具体实现
在整个的受权获取用户信息的流程中能够分为如下几步:
开发前的受权域名配置
引导用户进入受权页面赞成受权,获取code
经过code换取网页受权access_token(与基础支持中的access_token不一样)并经过网页受权access_token和openid获取用户基本信息(支持UnionID机制)
①开发前的受权域名配置
在进行代码实现以前咱们须要配置安全受权域名,具体安全域名的配置目录:【微信公众平台】——>【接口权限】——>【网页受权获取用户基本信息】,简单以下图:
②引导用户进入受权页面赞成受权,获取code
这一步在整个的网页受权过程当中是很是重要的一步,由于只有引导用户受权获取到code才能开始后面信息的获取,在这里须要注意的是咱们在配置受权连接中的redirect_uri必须是咱们在第一步中配置的安全域名,参考链接以下:
1
2
3
4
|
Scope为snsapi_base
Scope为snsapi_userinfo
https:
//open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=redirect_uri&response_type=code&scope=snsapi_userinfo&state=2#wechat_redirect
|
参数 | 是否必须 | 说明 |
---|---|---|
appid | 是 | 公众号的惟一标识 |
redirect_uri | 是 | 受权后重定向的回调连接地址,请使用urlencode对连接进行处理 |
response_type | 是 | 返回类型,请填写code |
scope | 是 | 应用受权做用域,snsapi_base (不弹出受权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出受权页面,可经过openid拿到昵称、性别、所在地。而且,即便在未关注的状况下,只要用户受权,也能获取其信息) |
state | 否 | 重定向后会带上state参数,开发者能够填写a-zA-Z0-9的参数值,最多128字节 |
#wechat_redirect | 是 | 不管直接打开仍是作页面302重定向时候,必须带此参数 |
注:code做为换取access_token的票据,每次用户受权带上的code将不同,code只能使用一次,5分钟未被使用自动过时!
由于oauth2.0受权机制是在腾讯机器会将最终的url带上code中转到咱们所配置的redirect_uri上,因此在咱们的服务端咱们须要在Controller加入一个weiXinOauth方法用于接收腾讯服务器中转过来的参数code和state,简单实现以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/**
* @Description: 微信受权登陆
* @param @param request
* @param @param response
* @param @param code
* @param @param state
* @author dapengniao
* @date 2016年4月26日 上午9:40:18
*/
@RequestMapping
(
"weixinOauth"
)
public
void
weiXinOauth(HttpServletRequest request,
HttpServletResponse response,
@RequestParam
(value =
"code"
, required =
true
) String code,
@RequestParam
(value =
"state"
, required =
true
) String state) {
System.out.println(
"Code============="
+code+
"==========state======="
+state);
}
|
此时到这里咱们对code的获取就完成了,下面继续下一步操做;
③经过code换取网页受权access_token(与基础支持中的access_token不一样)并经过网页受权access_token和openid获取用户基本信息(支持UnionID机制)
在前面咱们经过方法获取到了在受权中须要用到的code,那么咱们接下来要作的就是经过code获取token+openid,这里若是咱们采用的是snsapi_userinfo的方式受权的话,那么后面咱们能够经过token+openid获取用户信息了,在这里我写了一个实用的方法OauthCode_GetUseInfo来实现这些步骤,简单代码以下:
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
|
package
com.cuiyongzhi.wechat.common;
import
java.util.HashMap;
import
com.cuiyongzhi.web.util.GlobalConstants;
import
com.cuiyongzhi.wechat.util.HttpUtils;
import
net.sf.json.JSONObject;
/**
* ClassName: OauthCode_GetUseInfo
* @Description: 用户oauth2.0受权登陆 经过code获取用户真实信息
* @author dapengniao
* @date 2016年4月26日 上午9:54:55
*/
public
class
OauthCode_GetUseInfo {
private
String openid;
private
String access_token;
private
String code;
private
String unionid;
private
HashMap<String, String> params =
new
HashMap<String, String>();
public
OauthCode_GetUseInfo(String code) {
this
.code = code;
params.put(
"appid"
, GlobalConstants.getInterfaceUrl(
"appid"
));
params.put(
"secret"
, GlobalConstants.getInterfaceUrl(
"AppSecret"
));
}
/**
*
* @param @return hashmap {subscribe是否关注 0没有关注,1关注 unionid openid nickname昵称
* sex性别 province省份 city城市 headimgurl图像地址}
* @param @throws Exception
* @author dapengniao
* @date 2016年4月26日 上午9:54:55
*/
public
HashMap<String, String> getUserInfo()
throws
Exception {
// 将用户信息获取拼装成map
// 经过code获取access_token,openid,unionid
params.put(
"code"
, code);
params.put(
"grant_type"
,
"authorization_code"
);
String tokenrs = HttpUtils.sendGet(
GlobalConstants.getInterfaceUrl(
"OauthCodeUrl"
), params);
System.out.println(
"tokenrs======================"
+tokenrs);
access_token = JSONObject.fromObject(tokenrs).getString(
"access_token"
);
openid = JSONObject.fromObject(tokenrs).getString(
"openid"
);
unionid = JSONObject.fromObject(tokenrs).getString(
"unionid"
);
// 经过用户openid信息获取用户详细信息
params.clear();
params.put(
"access_token"
, access_token);
params.put(
"openid"
, openid);
params.put(
"lang"
,
"zh_CN"
);
String useinfors = HttpUtils.sendGet(
GlobalConstants.getInterfaceUrl(
"OauthInfoUrl"
), params);
// 经过用户的openid判断用户是否关注公众帐号
params.clear();
params.put(
"access_token"
, GlobalConstants.getInterfaceUrl(
"access_token"
)
);
params.put(
"openid"
, openid);
params.put(
"lang"
,
"zh_CN"
);
String subscribers =
""
;
subscribers = HttpUtils.sendGet(
GlobalConstants.getInterfaceUrl(
"SubscribeUrl"
), params);
// 将用户信息获取拼装成map
System.out.println(subscribers);
params.clear();
params.put(
"subscribe"
,
JSONObject.fromObject(subscribers).getString(
"subscribe"
));
params.put(
"unionid"
, unionid);
params.put(
"openid"
, openid);
params.put(
"nickname"
,
JSONObject.fromObject(useinfors).getString(
"nickname"
));
params.put(
"sex"
, JSONObject.fromObject(useinfors).getString(
"sex"
));
params.put(
"province"
,
JSONObject.fromObject(useinfors).getString(
"province"
));
params.put(
"city"
, JSONObject.fromObject(useinfors).getString(
"city"
));
params.put(
"headimgurl"
,
JSONObject.fromObject(useinfors).getString(
"headimgurl"
));
return
params;
}
/**
* @Description: 经过openid获取用户信息
* @param @param openid
* @param @return
* @param @throws Exception
* @author dapengniao
* @date 2016年4月26日 上午9:53:40
*/
public
static
HashMap<String, String> Openid_userinfo(String openid)
throws
Exception {
HashMap<String, String> params =
new
HashMap<String, String>();
params.put(
"access_token"
,
GlobalConstants.getInterfaceUrl(
"access_token"
));
params.put(
"openid"
, openid);
params.put(
"lang"
,
"zh_CN"
);
String subscribers = HttpUtils.sendGet(
GlobalConstants.getInterfaceUrl(
"SubscribeUrl"
), params);
params.clear();
params.put(
"nickname"
,
JSONObject.fromObject(subscribers).getString(
"nickname"
));
params.put(
"headimgurl"
,
JSONObject.fromObject(subscribers).getString(
"headimgurl"
));
params.put(
"sex"
, JSONObject.fromObject(subscribers).getString(
"sex"
));
return
params;
}
@SuppressWarnings
(
"unused"
)
private
static
String create_timestamp() {
return
Long.toString(System.currentTimeMillis() /
1000
);
}
}
|
经过方法咱们只须要传入code,就能够将我的的用户信息以Map的形式返回,用于咱们在前端的使用,在这里咱们将Controller的代码作简单的修改,用于对OauthCode_GetUseInfo中方法对用户信息的获取,以下:
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
|
/**
* @Description: 微信受权登陆
* @param @param request
* @param @param response
* @param @param code
* @param @param state
* @author dapengniao
* @date 2016年4月26日 上午9:40:18
*/
@RequestMapping
(
"weixinOauth"
)
public
void
weiXinOauth(HttpServletRequest request,
HttpServletResponse response,
@RequestParam
(value =
"code"
, required =
true
) String code,
@RequestParam
(value =
"state"
, required =
true
) String state) {
System.out.println(
"Code============="
+code+
"==========state======="
+ state);
try
{
// 用code取得微信用户的基本信息
OauthCode_GetUseInfo weixin =
new
OauthCode_GetUseInfo(code);
Map<String, String> wmap = weixin.getUserInfo();
System.out.println(
"用户昵称================================="
+ wmap.get(
"nickname"
));
}
catch
(Exception e) {
logger.error(e.toString(), e);
}
}
|