微信公众平台开发(四)——微信网页授权:获取用户openid&用户基本信息
作者:mmseoamin日期:2023-12-25

目录

  • 微信网页授权
    • 微信网页授权开发步骤
    • 运行结果
    • 获取用户openid和用户基本信息
      • 网页授权获取用户信息
      • 基础公众号关注获取用户信息
      • 源码下载

        微信网页授权

        在开发中,如果web产品需要使用到微信的功能,比如微信授权登录、微信支付、微信投票等,我是开发的东东是一个web项目,然而如果需要接入微信的话,就需要使用道微信的微信网页开发相关的功能。

        其中我们需要的东西就是拿到微信服务器的回调,比如用户扫码登录我们的web项目时,用户正确授权之后,微信服务器能回调到我们期望的url并且返回相应的参数信息。

        网页授权流程分为四步:

        1. 引导用户进入授权页面同意授权,获取code
        2. 通过code换取网页授权access_token(与基础支持中的access_token不同)
        3. 如果需要,开发者可以刷新网页授权access_token,避免过期
        4. 通过网页授权access_token和openid获取用户基本信息(支持UnionID机制)

          具体的接口和参数说明参考官方文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html

        其中需要注意的时: 第一步获取code时,scope参数的设置,当scope参数值为snsapi_base时 (不弹出授权页面,直接跳转,只能获取用户openid),当scope参数值为snsapi_userinfo时 (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 )

        微信网页授权开发步骤

        这里我直接贴开发及代码步骤:

        0. 在微信公众号后台配置域名

        需要注意的是只有微信认证的服务号才有微信网页授权的权限。

        在开发的时候我们可以使用申请的测试号进行调试开发,测试号拥有大部分服务号有的接口权限。

        然后需要在这两个地方设置JS接口的安全域名(开发阶段可以使用内网穿透域名):

        第一处:

        微信公众平台开发(四)——微信网页授权:获取用户openid&用户基本信息,在这里插入图片描述,第1张

        第二处(向下拉):

        微信公众平台开发(四)——微信网页授权:获取用户openid&用户基本信息,在这里插入图片描述,第2张

        分别设置好就可以使用安全域名开始开发了

        在后端写代码时,一般会使用官方的SDK:weixin-java-mp(如果向官网那样每一个步骤发送请求拼接参数真的太不友好了)

        1. 引入下面坐标
                
                
                    com.github.binarywang
                    weixin-java-mp
                    2.7.0
                
        
        1. 在配置文件application.yml中加入
        wechat:
          mpAppId: wx90a9158b6acc5584
          mpAppSecret: ec23a5d78f12afa569c64794570d753c
          // 后端项目回调地址
          projecturl: http://uhi4iv.natappfree.cc/
        
        1. 编写两个配置文件注入spring

          WechatAccountConfig.java

        package cn.kt.mywxdemo.wechatmp.config;
        import lombok.Data;
        import org.springframework.boot.context.properties.ConfigurationProperties;
        import org.springframework.stereotype.Component;
        import java.util.Map;
        /**
         * Created by tao.
         * Date: 2023/3/21 15:02
         * 描述:
         */
        @Data
        @Component
        //从配置文件里获取
        @ConfigurationProperties(prefix = "wechat")
        public class WechatAccountConfig {
            /**
             * 公众平台id
             */
            private String mpAppId;
            /**
             * 公众平台密钥
             */
            private String mpAppSecret;
            /**
             * 微信模版id
             */
            private Map templateId;
        }
        

        WechatMpConfig.java

        package cn.kt.mywxdemo.wechatmp.config;
        import me.chanjar.weixin.mp.api.WxMpConfigStorage;
        import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
        import me.chanjar.weixin.mp.api.WxMpService;
        import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.context.annotation.Bean;
        import org.springframework.stereotype.Component;
        /**
         * Created by tao.
         * Date: 2023/3/21 15:00
         * 描述:
         */
        @Component
        public class WechatMpConfig {
            @Autowired
            private WechatAccountConfig accountConfig;
            /**
             * @author :tao
             * @date :Created in 2021/3/12 10:15
             * @param: :
             * @return: WxMpService 对象
             * 配置wxMpConfigStorage,返回 WxMpService 对象
             */
            @Bean
            public WxMpService wxMpService() {
                WxMpService wxMpService = new WxMpServiceImpl();
                wxMpService.setWxMpConfigStorage(wxMpConfigStorage());
                return wxMpService;
            }
            /**
             * @author :tao
             * @date :Created in 2021/3/12 10:20
             * @param: :
             * @return: WxMpConfigStorage 对象
             * 配置AppId、和AppSecret,获取WxMpConfigStorage 对象
             */
            @Bean
            public WxMpConfigStorage wxMpConfigStorage() {
                WxMpInMemoryConfigStorage wxMpConfigStorage = new WxMpInMemoryConfigStorage();
                wxMpConfigStorage.setAppId(accountConfig.getMpAppId());
                wxMpConfigStorage.setSecret(accountConfig.getMpAppSecret());
                return wxMpConfigStorage;
            }
        }
        
        1. 编写和微信服务器交互的controller

          WxJsController.java

        package cn.kt.mywxdemo.wechatmp.controller;
        import lombok.extern.slf4j.Slf4j;
        import me.chanjar.weixin.common.api.WxConsts;
        import me.chanjar.weixin.common.exception.WxErrorException;
        import me.chanjar.weixin.mp.api.WxMpService;
        import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
        import me.chanjar.weixin.mp.bean.result.WxMpUser;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.beans.factory.annotation.Value;
        import org.springframework.stereotype.Controller;
        import org.springframework.web.bind.annotation.*;
        import java.io.UnsupportedEncodingException;
        import java.net.URLEncoder;
        /**
         * Created by tao.
         * Date: 2023/3/21 15:04
         * 描述:
         */
        @Controller
        @RequestMapping("/wechat")
        @Slf4j
        public class WxJsController {
            @Autowired
            private WxMpService wxMpService;
            @Value("${wechat.projecturl}")
            private String projectUrl;
            @GetMapping("/auth")
            @ResponseBody
            public String auth(@RequestParam(value = "echostr", defaultValue = "没有获取到") String echostr) {
                return echostr;
            }
            /**
             * @author :tao
             * @param: :
             * @return: 重定向到获取用户信息的类
             * 微信授权登录
             */
            @GetMapping("/authorize")
            public String authorize(@RequestParam(value = "returnUrl", defaultValue = "https://qkongtao.cn/") String returnUrl) throws UnsupportedEncodingException {
                log.info("【微信网页授权】进来了,参数={}", returnUrl);
                System.out.println("进来了:" + returnUrl);
                //1. 配置
                //2. 调用方法
                String url = projectUrl + "wechat/userInfo";
                /*
                 * 相当于这种形式
                 * URLEncoder.decode(returnUrl,"UTF-8"
                 * https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
                 */
                String redirectUrl = wxMpService.oauth2buildAuthorizationUrl(url, WxConsts.OAUTH2_SCOPE_USER_INFO, URLEncoder.encode(returnUrl, "utf-8"));
                log.info("【微信网页授权】获取code,result={}", redirectUrl);
                return "redirect:" + redirectUrl;
            }
            /**
             * @author :tao
             * @param: :
             * @return: 重定向
             * 获取用户信息类,最后重定向到指定url
             */
            @GetMapping("/userInfo")
            public String userInfo(@RequestParam("code") String code,
                                   @RequestParam("state") String returnUrl) throws WxErrorException {
                /*当用户同意授权后,会回调所设置的url并把authorization code传过来,
                然后用这个code获得access token,其中也包含用户的openid等信息*/
                WxMpOAuth2AccessToken wxMpOAuth2AccessToken = new WxMpOAuth2AccessToken();
                try {
                    //获取access token
                    wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code);
                    log.info("【AccessToken:】{}", wxMpOAuth2AccessToken.getAccessToken());
                } catch (WxErrorException e) {
                    log.error("【微信网页授权】{}", e);
                }
                // 拿到openid
                String openId = wxMpOAuth2AccessToken.getOpenId();
                log.info("【openid:】{}", openId);
                log.info("【我是前端要回调的地址:】{}", returnUrl + "&openid=" + openId);
                // 顺便获取一下用户信息
                WxMpUser wxMpUser = wxMpService.oauth2getUserInfo(wxMpOAuth2AccessToken, "zh_CN");
                log.info("【用户信息:】{}", wxMpUser.toString());
                //注意拼接参数,第一个参数需要加问号,之后参数使用&拼接的问题
                //return "redirect:" + returnUrl + "/#/?openid=" + openId;
                return "redirect:" + returnUrl + "&openid=" + openId;
            }
        }
        

        运行结果

        上述代码已经处理好了微信授权的流程,我们调用只需要使用/authorize接口,并且传入回调url(授权之后需要重定向的路径)即可进行授权

        示例如下

        uhi4iv.natappfree.cc为后台绑定域名

        http://uhi4iv.natappfree.cc/wechat/authorize?returnUrl=https://qkongtao.cn?1=1

        使用微信打开结果:

        微信公众平台开发(四)——微信网页授权:获取用户openid&用户基本信息,在这里插入图片描述,第3张

        由于我已经刚刚授权过了,就进行了静默授权。否则将弹出授权选项需要用户确认。

        微信公众平台开发(四)——微信网页授权:获取用户openid&用户基本信息,在这里插入图片描述,第4张

        获取用户openid和用户基本信息

        需要提前说明:

        1. 在网页授权中的openid和基础公众号关注后得到的openid的是不一样的
        2. 网页授权access_token和普通access_token的区别
        • 微信网页授权是通过OAuth2.0机制实现的,在用户授权给公众号后,公众号可以获取到一个网页授权特有的接口调用凭证(网页授权access_token),通过网页授权access_token可以进行授权后接口调用,如获取用户基本信息;
        • 其他微信接口,需要通过基础支持中的“获取access_token”接口来获取到的普通access_token调用。
          1. 在关注者与公众号产生消息交互后,公众号可获得关注者的openid(加密后的微信号,每个用户对每个公众号的openid是唯一的。对于不同公众号,同一用户的openid不同)。公众号可通过本接口来根据openid获取用户基本信息,包括语言和关注时间。
          2. UnionID机制说明:开发者可通过openid来获取用户基本信息。特别需要注意的是,如果开发者拥有多个移动应用、网站应用和公众帐号,可通过获取用户基本信息中的unionid来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号,用户的unionid是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。
          3. 目前基础公众号关注后获取到openid,后台是无法根据openid和access_token获取到用户头像、昵称信息、地址等信息;必须通过OAuth2.0机制的微信网页授权,在用户确认授权之后才可以获取到用户头像、昵称信息、地址等信息。

          网页授权获取用户信息

          参考官方文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#3

          如果网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_token和openid拉取用户信息了。

          请求方法:

          http:GET(请使用https协议):

          https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN

          参数说明:

          微信公众平台开发(四)——微信网页授权:获取用户openid&用户基本信息,在这里插入图片描述,第5张

          请求结果:

          微信公众平台开发(四)——微信网页授权:获取用户openid&用户基本信息,在这里插入图片描述,第6张

          昵称乱码需要使用utf8重新编码:String result = new String(nickname, “utf-8”);

          在上面的controller中也顺便把用户信息也进行获取了一下:

          微信公众平台开发(四)——微信网页授权:获取用户openid&用户基本信息,在这里插入图片描述,第7张

          后台输出结果如下:

          微信公众平台开发(四)——微信网页授权:获取用户openid&用户基本信息,在这里插入图片描述,第8张

          基础公众号关注获取用户信息

          官方文档:https://developers.weixin.qq.com/doc/offiaccount/User_Management/Get_users_basic_information_UnionID.html#UinonId

          其实和上面差不多,也是通过openid和access_token换取用户信息

          接口如下:

          接口调用请求说明 http请求方式: GET https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN

          参数说明:

          微信公众平台开发(四)——微信网页授权:获取用户openid&用户基本信息,在这里插入图片描述,第9张

          结果如下:

          微信公众平台开发(四)——微信网页授权:获取用户openid&用户基本信息,在这里插入图片描述,第10张

          可以看出相比较微信网页授权,基础公众号关注可获取用户信息相对少了很多。

          源码下载

          源码链接:https://gitee.com/qkongtao/my-wx-demo