Java微信公众平台开发(十六)--微信网页授权(OAuth2.0授权)获取用户基本信息

时间:2023-01-09 15:11:26

转自:http://www.cuiyongzhi.com/post/78.html

好长时间没有写文章了,主要是最近的工作和生活上的事情比较多而且繁琐,其实到现在我依然还是感觉有些迷茫,最后还是决定静下心来坚持一开始的选择,继续我们的微信系列文章的后续更新,也希望在自己有时间的时候能把更多的内容呈现给大家,前面一系列的文章讲述了很多微信开发相关的基础知识点 【微信系列文章】,那么从这一篇开始将讲述微信较深一层次或者说在产品应用中时刻会用到的一些技术点,那么下面就让我们进入正题吧,这一篇我要讲述的是在微信服务号开发中常用到的微信网页授权(OAuth2.0授权)获取用户基本信息!

我们来说下OAuth2.0授权的一些应用场景,例如:示例①希望用户在点击打开一个网页的时候可以获取该用户的微信昵称,微信头像等;示例②:当某个用户在我们会员系统中,希望用户在直接打开网页的时候展示用户在我们的会员系统中的积分情况和消费信息等...,那么这一系列的应用场景中我们是如何在一个网页中获取微信用户的相关信息的呢?这里我们就要用到微信网页授权的功能来解决我们遇到的难题了!

(一)首先在我们开始应用OAuth2.0授权之前我们先来了解一下它,看他本身的实现流程和机制!

①关于网页授权回调域名的说明

  • 在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的开发者中心页配置授权回调域名。请注意,这里填写的是域名(是一个字符串),而不是URL,因此请勿加 http:// 等协议头;

  • 授权回调域名配置规范为全域名,比如需要网页授权的域名为: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鉴权

  • 如果公众号登录授权给了第三方开发者来进行管理,则不必做任何设置,由第三方代替公众号实现网页授权即可

②关于网页授权的两种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机制)

①开发前的授权域名配置

在进行代码实现之前我们需要配置安全授权域名,具体安全域名的配置目录:【微信公众平台】——>【接口权限】——>【网页授权获取用户基本信息】,简单如下图:

Java微信公众平台开发(十六)--微信网页授权(OAuth2.0授权)获取用户基本信息

②引导用户进入授权页面同意授权,获取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);
    }
}

Java微信公众平台开发(十六)--微信网页授权(OAuth2.0授权)获取用户基本信息的更多相关文章

  1. Java微信公众平台开发&lpar;十二&rpar;--微信用户信息的获取

    转自:http://www.cuiyongzhi.com/post/56.html 前面的文章有讲到微信的一系列开发文章,包括token获取.菜单创建等,在这一篇将讲述在微信公众平台开发中如何获取微信 ...

  2. Java微信公众平台开发&lpar;十五&rpar;--微信JSSDK的使用

    转自:http://www.cuiyongzhi.com/post/63.html 在前面的文章中有介绍到我们在微信web开发过程中常常用到的 [微信JSSDK中Config配置] ,但是我们在真正的 ...

  3. Java微信公众平台开发&lpar;十二&rpar;--微信JSSDK的使用

    在前面的文章中有介绍到我们在微信web开发过程中常常用到的 [微信JSSDK中Config配置],但是我们在真正的使用中我们不仅仅只是为了配置Config而已,而是要在我们的项目中真正去使用微信JS- ...

  4. Java微信公众平台开发&lpar;十&rpar;--微信用户信息的获取

    前面的文章有讲到微信的一系列开发文章,包括token获取.菜单创建等,在这一篇将讲述在微信公众平台开发中如何获取微信用户的信息,在上一篇我们有说道微信用户和微信公众账号之间的联系可以通过Openid关 ...

  5. Java微信公众平台开发&lpar;一&rpar;--接入微信公众平台

    转自:http://www.cuiyongzhi.com/post/38.html (一)接入流程解析 在我们的开发过程中无论如何最好的参考工具当然是我们的官方文档了:http://mp.weixin ...

  6. 夺命雷公狗---微信开发51----网页授权(oauth2&period;0)获取用户基本信息接口(1)

    如果用户在微信客户端访问第三方网页,公众号可以通过微信网页授权机制,来获取用户基本信息,从而实现业务逻辑. 一般我们用来“数据采集”,“市场调查”,“投票”,只要授权了第三方网页,微信用户无需注册就可 ...

  7. Java微信公众平台开发&lpar;十&rpar;--微信自定义菜单的创建实现

    转自:http://www.cuiyongzhi.com/post/48.html 自定义菜单这个功能在我们普通的编辑模式下是可以直接在后台编辑的,但是一旦我们进入开发模式之后我们的自定义菜单就需要自 ...

  8. Java微信公众平台开发&lpar;十四&rpar;【番外篇】--微信web开发者工具使用

    转自:http://www.cuiyongzhi.com/post/58.html 为帮助开发者更方便.更安全地开发和调试基于微信的网页,微信推出了 web 开发者工具.它是一个桌面应用,通过模拟微信 ...

  9. 微信公众平台开发——为何不能在网页调用微信jsapi?

    说到这问题,相信大部分程序员老手都会轻蔑一笑,当然是跨域导致的啊!但是为了一些小白,我觉得还是很有必要再说一次的. 首先介绍什么是跨域,由于浏览器的同源策略,出于防范跨站脚本的攻击,禁止客户端脚本( ...

随机推荐

  1. strncpy&comma;strcpy

    strncpy不会为des自动添加“\0” strcpy遇空结束,自动添加结束符 结论: 1.使用strcpy时一定不能用于无结束符的字符串,因为strcpy依赖\0判断源字符串的结束 2.使用str ...

  2. &lbrack;每日电路图&rsqb; 1、基于AT89C52单片机最小系统接口电路【转】

              come from:http://www.21ic.com/dianlu/basis/interface/2015-04-21/621607.htm AT89C52是美国Atmel ...

  3. Docker 容器中&OpenCurlyDoubleQuote;TERM environment variable not set&period;”问题解决

    在查容器内部资源利用情况时候,发现top命令无法使用,报错“TERM environment variable not set.”.从网上找到了解决方案,如下. [root@localhost ~]# ...

  4. 看京东如何把Intel RealSense技术用在物流上

    提起Intel RealSense 3D 深度摄像头,总是离不开无人机.机器人等前沿硬件产品,比如 CES 2016 上让人眼前一亮的自动避障无人机Yuneec “台风 H”,Segway.Nineb ...

  5. 【学习总结】整理一下int&comma; NSInteger 等概念

    基本需要知道的 : unsigned : 没符号的 signed  : 有符号的 int : 整型 看看OC的定义 : #if __LP64__ || (TARGET_OS_EMBEDDED &amp ...

  6. JavaScript&ldquo&semi;闭包&rdquo&semi;精解

    一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. 详细了解 Javascript语言的特殊之处,就在于函数内部可以直接读 ...

  7. C&num; - 线程操作

    代码: using System; using System.Collections.Generic; using System.Linq; using System.Text; using Syst ...

  8. LVS(二)NAT模型配置

    NAT配置模式 环境说明 LVS服务器(在eth0:0上设置VIP为:192.168.159.200/24) Eth0:192.168.159.133/24   GW:192.168.159.2 Et ...

  9. Mysql哪些字段适合建立索引

    数据库建立索引常用的规则如下: 1.表的主键.外键必须有索引: 2.数据量超过300的表应该有索引: 3.经常与其他表进行连接的表,在连接字段上应该建立索引: 4.经常出现在Where子句中的字段,特 ...

  10. &lbrack;SQL Server&rsqb;从 varchar 数据类型到 datetime 数据类型的转换产生一个超出范围的值。

    见下图sql, 使用dateadd()转换时报如题错误, 原因是数据库表中存入的数据格式不正确,  数据格式不正确,  数据格式不正确,  重要的事情讲3遍!! ca.batch_no的前8位必须是日 ...