C#公众平台(三)—— 生成带参数的二维码

遇到了一个需求,就是要生成客户的专属二维码,要求扫码后能关注订阅号,并且将每个扫码的人和这个二维码所属客户绑定,但是系统用的是商户号,商户号不能绑定订阅号,这就存在了怎么确认是同一个客户的问题。
生成带参数的二维码文档
基础帮助类

unionid 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。
微信官方提供了unionid,在同一个账号主体下,unionid是一样的,前提是需要在开放平台绑定公众号或者小程序,在开放平台认证需要300块人民币。这样在返回用户信息的时候就会返回unionid,如果没有在开放平台绑定,返回的unionid为空。
认证有效期:一年,有效期最后三个月可申请年审即可续期 审核费用:中国大陆地区:300元,非中国大陆地区:120美元

查了下文档,得出一个方案:A是订阅号,B是商户号绑定的服务号,关注A后得到openid,然后获取unionid, 存入系统,之后在B系统登录注册后根据unionid判断是否是同一个人,之后openid绑定到系统账户,当然用unionid也可以,但是之前系统用的是openid,为了减少耦合,就保持原样。

创建二维码的底层方法

public class WxPlatformApi
    {
        /**
        * 
        * 创建二维码ticket https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1443433542
        * @param string access_token 调用公众号接口令牌
        * @param WxPaydata inputObj 提交给生成二维码API的参数
        * @param int timeOut 超时时间
        * @throws WxPayException
        * @return 成功时返回,其他抛异常
        */
        public static WxPayData CreateQRCodeTicket(string access_token, WxPayData inputObj, int timeOut = 6)
        {
            if (string.IsNullOrWhiteSpace(access_token))
            {
                throw new Exception("缺少统一支付接口必填参数out_trade_no!");
            }

            string url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + access_token;
            //检测必填参数

            if (!inputObj.IsSet("action_name"))
            {
                throw new Exception("缺少创建二维码ticket接口必填参数action_name!");
            }
            else if (!inputObj.IsSet("action_info"))
            {
                throw new Exception("缺少创建二维码ticket接口必填参数action_info!");
            }

            string xml = inputObj.ToJson();

            // Log.Debug("WxPayApi", "UnfiedOrder request : " + xml);
            string response = HttpService.PostByJson(xml, url, false, timeOut);
            //Log.Debug("WxPayApi", "UnfiedOrder response : " + response);

            WxPayData result = new WxPayData();
            result.FromJSON(response);

            return result;
        }

        /**
        * 
        * 获取用户基本信息(包括UnionID机制) https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140839
        * @param WxPaydata inputObj 提交给生成二维码API的参数
        * @param int timeOut 超时时间
        * @throws WxPayException
        * @return 成功时返回,其他抛异常
        */
        public static WxPayData GetUserInfo(WxPayData inputObj, int timeOut = 6)
        {
            //检测必填参数
            if (!inputObj.IsSet("access_token"))
            {
                throw new Exception("缺少获取用户基本信息(包括UnionID机制)接口必填参数access_token!");
            }
            else if (!inputObj.IsSet("openid"))
            {
                throw new Exception("缺少获取用户基本信息(包括UnionID机制)接口必填参数openid!");
            }

            string url = "https://api.weixin.qq.com/cgi-bin/user/info?" + inputObj.ToUrl();

            string response = HttpService.Get(url);

            WxPayData result = new WxPayData();
            result.FromJSON(response);

            return result;
        }
    }

二维码生成类

public class WCQRCode
    {
        /**
        * 创建二维码ticket
        * 页面直接显示为 https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET 
        * @return 创建二维码ticket结果
        * @失败时抛异常WxPayException
        */
        public WxPayData CreateQRCodeTicket(string access_token, string action_name, int scene_id = 0, string scene_str = null)
        {
            if (action_name != "QR_SCENE" && action_name != "QR_STR_SCENE" && action_name != "QR_LIMIT_SCENE" && action_name != "QR_LIMIT_STR_SCENE")
            {
                throw new Exception("action_name参数异常!");
            }

            WxPayData data = new WxPayData();
            //临时二维码需要时间
            if (action_name == "QR_SCENE" || action_name == "QR_STR_SCENE")
            {
                //该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为30秒。
                data.SetValue("expire_seconds", 172800);
            }
            //二维码类型,QR_SCENE为临时的整型参数值,QR_STR_SCENE为临时的字符串参数值,QR_LIMIT_SCENE为永久的整型参数值,QR_LIMIT_STR_SCENE为永久的字符串参数值
            data.SetValue("action_name", action_name);
            //二维码详细信息
            WxPayData actionInfo = new WxPayData();
            WxPayData scene = new WxPayData();
            if (scene_id > 0)
            {
                //场景值ID,临时二维码时为32位非0整型,永久二维码时最大值为100000(目前参数只支持1--100000)
                scene.SetValue("scene_id", scene_id);
                actionInfo.SetValue("scene", scene.m_values);
            }
            else if (!string.IsNullOrWhiteSpace(scene_str))
            {
                //场景值ID(字符串形式的ID),字符串类型,长度限制为1到64
                scene.SetValue("scene_str", scene_str);
                actionInfo.SetValue("scene", scene.m_values);
            }

            data.SetValue("action_info", actionInfo.m_values);

            WxPayData result = WxPlatformApi.CreateQRCodeTicket(access_token, data);
            if (!result.IsSet("ticket") || !result.IsSet("url"))
            {
                //Log.Error(this.GetType().ToString(), "UnifiedOrder response error!");
                throw new Exception("CreateQRCodeTicket response error!");
            }

            return result;
        }

        /**
        * 获取用户基本信息(包括UnionID机制)
        * @return 创建二维码ticket结果
        * @失败时抛异常WxPayException
        */
        public WxPayData GetUserInfo(string access_token, string openid)
        {
            if (string.IsNullOrWhiteSpace(access_token) || string.IsNullOrWhiteSpace(openid))
            {
                throw new Exception("参数异常!");
            }

            WxPayData data = new WxPayData();
            //调用接口凭证
            data.SetValue("access_token", access_token);
            data.SetValue("openid", openid);

            WxPayData result = WxPlatformApi.GetUserInfo(data);
            if (!result.IsSet("openid") || !result.IsSet("nickname"))
            {
                //Log.Error(this.GetType().ToString(), "UnifiedOrder response error!");
                throw new Exception("GetUserInfo response error!");
            }

            return result;
        }

        /// <summary>
        /// 获取AccessToken
        /// http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96access_token
        /// </summary>
        /// <param name="grant_type"></param>
        /// <param name="appid"></param>
        /// <param name="secrect"></param>
        /// <returns>access_toke</returns>
        public string GetJSAPIAccessToken(string appid, string secret)
        {
            WxPayData data = new WxPayData();
            data.SetValue("grant_type", "client_credential");
            data.SetValue("appid", appid);
            data.SetValue("secret", secret);
            string url = "https://api.weixin.qq.com/cgi-bin/token?" + data.ToUrl();

            //请求url以获取数据
            string result = HttpService.Get(url);

            JObject jd = JObject.Parse(result);

            return (string)jd["access_token"];
        }
    }

获取二维码ticket接口

        /// <summary>
        /// 获取二维码ticket, 显示: https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET
        /// </summary>
        public Hashtable CreateQRCodeTicket()
        {
            int scene_id = GetInt("scene_id");
            string scene_str = GetStr("scene_str");
            bool isForever = GetBool("isForever");

            try
            {
                Authentication au = new Authentication();
                string access_token = au.GetJSAPIAccessToken();

                WCQRCode qrcode = new WCQRCode();
                WxPayData result = new WxPayData();

                if (isForever)
                {
                    if (scene_id > 0)
                    {
                        result = qrcode.CreateQRCodeTicket(access_token, "QR_LIMIT_SCENE", scene_id, scene_str);
                    }
                    else if (!string.IsNullOrWhiteSpace(scene_str))
                    {
                        result = qrcode.CreateQRCodeTicket(access_token, "QR_LIMIT_STR_SCENE", scene_id, scene_str);
                    }
                }
                else
                {
                    if (scene_id > 0)
                    {
                        result = qrcode.CreateQRCodeTicket(access_token, "QR_SCENE", scene_id, scene_str);
                    }
                    else if (!string.IsNullOrWhiteSpace(scene_str))
                    {
                        result = qrcode.CreateQRCodeTicket(access_token, "QR_STR_SCENE", scene_id, scene_str);
                    }
                }

                //获取H5调起JS API参数       
                return result.ToHashtable();
            }
            catch (Exception)
            {
                throw new Exception("获取二维码ticket失败!");
            }
        }

Authentication的GetJSAPIAccessToken方法,跟WCQRCode的GetJSAPIAccessToken是基本一样的,可以根据需求整理下,这边是原先有的,就不换方法了

	/// <summary>
        /// 获取AccessToken
        /// http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96access_token
        /// </summary>
        /// <param name="grant_type"></param>
        /// <param name="appid"></param>
        /// <param name="secrect"></param>
        /// <returns>access_toke</returns>
        public string GetJSAPIAccessToken()
        {
            WxPayData data = new WxPayData();
            data.SetValue("grant_type", "client_credential");
            data.SetValue("appid", Config.AppID);
            data.SetValue("secret", Config.AppSecret);
            string url = "https://api.weixin.qq.com/cgi-bin/token?" + data.ToUrl();

            //请求url以获取数据
            string result = HttpService.Get(url);

            JObject jd = JObject.Parse(result);

            return (string)jd["access_token"];
        }

接收推送事件逻辑,具体C#公众平台(二)—— 接收事件推送之关注回调

case "event":
                        string eventType = data.GetValue("Event").ToString();
                        switch (eventType)
                        {
                            case "subscribe":
                                //用户未关注的情况下KEY值: qrscene_为前缀,后面为二维码的参数值
                                string eventKey = data.GetValue("EventKey").ToString();

                                if (!string.IsNullOrEmpty(eventKey))
                                {
                                    //获取二维码的分销商ID
                                    int CusID = CInt(eventKey.Substring(eventKey.IndexOf("qrscene_") + 8));

                                    //记录OPENID
                                    string openID = data.GetValue("FromUserName").ToString();

                                    //根据OPENID获取UnionID
                                    WCQRCode WCQRCode = new WCQRCode();
                                    string access_token = string.Empty;
                                    if (string.IsNullOrWhiteSpace(Config.SubscriptionAppID))
                                    {
                                        access_token = WCQRCode.GetJSAPIAccessToken(Config.AppID, Config.AppSecret);
                                    }
                                    else
                                    {
                                        access_token = WCQRCode.GetJSAPIAccessToken(Config.SubscriptionAppID, Config.SubscriptionAppSecret);
                                    }
                                    
                                    WxPayData userInfo = WCQRCode.GetUserInfo(access_token, openID);
                                    string unionid = string.Empty;

                                    //是否使用了微信企业模式,使用了就会有unionid
                                    if (userInfo.IsSet("unionid"))
                                    {
                                        unionid = userInfo.GetValue("unionid").ToString();
                                    }
                                    //判断是否存在,记录到数据库
                                    WeChatSubscribeDAO dao = new WeChatSubscribeDAO();
                                    bool isExists = dao.Exists(openID);
                                    if (!isExists)
                                    {
                                        //存入数据库
                                    }
                                }
                                break;

需要注意的是这边的access_token是指操作公众号接口的access_token,而用户授权登录的时候的access_token是指获取用户信息的access_token,两个是不一样的,别弄混了。
还有要获取用户的unionid需要用户关注这个企业下面任意的公众号才可以获取到,否则为空。坑还是不少的,慢慢爬把。。。

猜你喜欢

转载自blog.csdn.net/qwt7896541230/article/details/84951221
今日推荐