.net C#微信公众号开发

16 篇文章 0 订阅

.net C#微信公众号开发

#一、开发准备工作

打开微信公众平台,主页左侧找到 “开发”栏目,选择基本配置,获取AppId,appsecret。
在这里插入图片描述开发者密码需要管理员授权查看。

二、服务器配置

1、主页左侧找到 “开发”栏目,选择基本配置,下半页“服务器配置”模块下,点击修改配置,需要填写URL和Token,这两个参数下面会有讲到
在这里插入图片描述URL是指我们用来验证我们服务端和微信发送的Token是否一致,总之就是为了验证服务器资源真实性。注:URL必须是域名下的验证地址。
EncodingAESKey选择随机模式即可;
消息加解密方式根据业务需求,我这边是兼容模式。
下面我们看一下Token验证的实现

 namespace WeiXinWeb.ZCWeChat.sqsb
    {
        public partial class AddCasePage : System.Web.UI.Page
        {
        
            public readonly string Token = "ymcgxm";//与微信公众账号后台的Token设置保持一致,区分大小写。
     
    
            protected void Page_Load(object sender, EventArgs e)
            {
                Valid();
        
            }
            private void Valid()
            {
                string echoStr = Request.QueryString["echoStr"].ToString();//echoStr微信传递的字符串
                WriteLogs("parmlog", "echoStr", echoStr);
                if (CheckSignature())
                {
                    if (!string.IsNullOrEmpty(echoStr))
                    {
                        Response.Write(echoStr);
                        Response.End();
                    }
                }
            }
            private bool CheckSignature()
            {//微信服务端会生成signature、timestamp,nonce三个参数,通过我们本地的Token和timestamp 、nonce 进行加密,生成的结果和signature(微信也是这样生成)是否一样
                string signature = Request.QueryString["signature"].ToString();
                string timestamp = Request.QueryString["timestamp"].ToString();
                string nonce = Request.QueryString["nonce"].ToString();
                string[] ArrTmp = { Token, timestamp, nonce };
                WriteLogs("parmlog", "signature--timestamp", signature.ToString() + "***" + timestamp);
                Array.Sort(ArrTmp);     //字典排序  
                string tmpStr = string.Join("", ArrTmp);
                tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1");
                tmpStr = tmpStr.ToLower();
                if (tmpStr == signature)
                {
                   
                 
                    return true;
                }
                else
                {
                    return false;
                }
            }
    
    
            /// <summary>
            /// 日志部分
            /// </summary>
            /// <param name="fileName"></param>
            /// <param name="type"></param>
            /// <param name="content"></param>
            public static void WriteLogs(string fileName, string type, string content)
            {
                string path = AppDomain.CurrentDomain.BaseDirectory;
                if (!string.IsNullOrEmpty(path))
                {
                    path = AppDomain.CurrentDomain.BaseDirectory + fileName;
                    if (!Directory.Exists(path))
                    {
                        Directory.CreateDirectory(path);
                    }
                    path = path + "\\" + DateTime.Now.ToString("yyyyMMdd");
                    if (!Directory.Exists(path))
                    {
                        Directory.CreateDirectory(path);
                    }
                    path = path + "\\" + DateTime.Now.ToString("yyyyMMdd") + ".txt";
                    if (!File.Exists(path))
                    {
                        FileStream fs = File.Create(path);
                        fs.Close();
                    }
                    if (File.Exists(path))
                    {
                        StreamWriter sw = new StreamWriter(path, true, System.Text.Encoding.Default);
                        sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + type + "-->" + content);
                        //  sw.WriteLine("----------------------------------------");
                        sw.Close();
                    }
                }
            }
    
           
        }
    }

代码完成以后,在服务器上发布验证网站,设置用域名访问,回到微信公众号服务器配置下,配置改地址,点击提交,成功表示通过验证,否则失败,失败原因可以通过微信端调试工具查看原因,《微信web开发工具》。
2、完成服务器验证以后,进入正式开发阶段,为了方便配置,我们将Appid,appsecret配置到web.config下
在这里插入图片描述
第一步获取关注者用户信息


    namespace WeiXinWeb.ZCWeChat.sqsb
    {
        public partial class CaseRegiestPage : System.Web.UI.Page
        {
            public string openid = "2121212";
    
            //公众号信息部分
            public string appid = ConfigurationManager.AppSettings["AppId"];
            public string appsecret = ConfigurationManager.AppSettings["AppSecret"];
            public string redirect_uri = HttpUtility.UrlEncode("http://域名/ZCWeChat/sqsb/CaseRegiestPage.aspx");
            public string scope = "snsapi_base";//以snsapi_userinfo为scope发起的网页授权,是用来获取用户的基本信息的。但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息。
            public string accesstoken = "";
    
            public static string access_token = "";//票据所需的token
     
            public string nickname;
            public string sex;
            public string headimgurl;
            public string province;
            public string country;
            public string language;
            public string city;
    
            protected void Page_Load(object sender, EventArgs e)
            {
    
                string code = Request.QueryString["code"].ToString();
                
                if (string.IsNullOrEmpty(code))
                {
                    //如果code没获取成功,重新拉取一遍
                    OpenAccess();
    
                }
    
                GetWXConfig();
                WriteLogs("access_token", "access_token====", access_token);
                GetAuthriseAccess_Token(code);
          
            }
    
            /// <summary>
            /// 获取网页授权用户信息
            /// </summary>
            public void GetAuthriseAccess_Token(string code)
            {
                string UserInfo = "";
                string html = string.Empty;
                string url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appid + "&secret=" + appsecret + "&code=" + code + "&grant_type=authorization_code";
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
                request.Method = "GET";
                HttpWebResponse response = request.GetResponse() as HttpWebResponse;
                Stream ioStream = response.GetResponseStream();
                StreamReader sr = new StreamReader(ioStream, Encoding.UTF8);
                html = sr.ReadToEnd();
                sr.Close();
                ioStream.Close();
                response.Close();
                JObject outputObj = JObject.Parse(html);
                openid = outputObj["openid"].ToString();
                accesstoken = outputObj["access_token"].ToString();
                // accesstoken = AccessTokenDAL.IsExistAccess_Token();
                WriteLogs("用户get结果", "Useropen", html);
                WriteLogs("openid", "signature--openid", code.ToString() + "***" + openid);
                Session["openid"] = outputObj["openid"];
    
                UserInfo = GetUserInfos();
    
                JObject outputObj1 = JObject.Parse(UserInfo);
                nickname = outputObj1["nickname"].ToString(); //昵称
                sex = outputObj1["sex"].ToString(); //性别什么的
                headimgurl = outputObj1["headimgurl"].ToString(); //头像url
                province = outputObj1["province"].ToString(); ;
                country = outputObj1["country"].ToString(); ;
                language = outputObj1["language"].ToString(); ;
                city = outputObj1["city"].ToString();
                GetWXConfig();
                WriteLogs("UserINfos", "nickname", nickname.ToString() + "***" + openid);
            
            }
    
            //获取微信客户端需要的配置文件参数
            public string signature = "";
            public string timestamp = "";
            public string nonce = "";
            public string jsapi_ticket = "";
    
            public void GetWXConfig() {
                string url = Request.Url.ToString();
                jsapi_ticket = AccessTokenDAL.GetTicket();
                timestamp = GetTimeStamp();
                nonce = GenerateCheckCodeNum(16);
                string[] ArrTmp = { timestamp, nonce };
            //    WriteLogs("urllog", "url====", url);
                Array.Sort(ArrTmp);     //字典排序  
                string tmpStr = string.Join("", ArrTmp);
                string wxconfigStr = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonce + "&timestamp=" + timestamp + "&url=" + url + "";
                tmpStr = AccessTokenDAL.Sha1(wxconfigStr);
                WriteLogs("wxconfigStr", "wxconfigStr====", wxconfigStr);
                signature = tmpStr;
            }
    
            /// <summary>
            /// 获取时间戳
            /// </summary>
            /// <returns></returns>
            public static string GetTimeStamp()
            {
                TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
                return Convert.ToInt64(ts.TotalSeconds).ToString();
            }
    
    
            /// 
            /// 生成随机数字字符串
            /// 
            /// 待生成的位数
            /// 生成的数字字符串
            /// 
            private int rep = 0;
            private string GenerateCheckCodeNum(int codeCount)
            {
                string str = string.Empty;
                long num2 = DateTime.Now.Ticks + this.rep;
                this.rep++;
                Random random = new Random(((int)(((ulong)num2) & 0xffffffffL)) | ((int)(num2 >> this.rep)));
                for (int i = 0; i < codeCount; i++)
                {
                    int num = random.Next();
                    str = str + ((char)(0x30 + ((ushort)(num % 10)))).ToString();
                }
                return str;
            } 
    
            public string  GetUserInfos()
            {
                string UserURL = string.Format("https://api.weixin.qq.com/sns/userinfo?access_token={0}&openid={1}&lang=zh_CN", accesstoken, openid);
                string html = string.Empty;
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(UserURL);
                request.Method = "GET";
                HttpWebResponse response = request.GetResponse() as HttpWebResponse;
                Stream ioStream = response.GetResponseStream();
                StreamReader sr = new StreamReader(ioStream, Encoding.UTF8);
                 html = sr.ReadToEnd();
                 WriteLogs("userlog", "userlog====", html);
                sr.Close();
                ioStream.Close();
                response.Close();
                return html;
            }
    
    
    
            public void OpenAccess()
            {
                //判断session不存在
                if (Session["openid"] == null)
                {
                    //认证第一步:重定向跳转至认证网址
                    string url = string.Format("https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&&response_type=code&scope=snsapi_userinfo&m=oauth2#wechat_redirect", appid, redirect_uri);
                    Response.Redirect(url);
                }
                //判断session存在
                else
                {
                    //跳转到前端页面.aspx
                    Response.Redirect(Request.Url.ToString());
                }
            }
    
    
            /// <summary>
            /// 日志部分
            /// </summary>
            /// <param name="fileName"></param>
            /// <param name="type"></param>
            /// <param name="content"></param>
            public static void WriteLogs(string fileName, string type, string content)
            {
                string path = AppDomain.CurrentDomain.BaseDirectory;
                if (!string.IsNullOrEmpty(path))
                {
                    path = AppDomain.CurrentDomain.BaseDirectory + fileName;
                    if (!Directory.Exists(path))
                    {
                        Directory.CreateDirectory(path);
                    }
                    path = path + "\\" + DateTime.Now.ToString("yyyyMMdd");
                    if (!Directory.Exists(path))
                    {
                        Directory.CreateDirectory(path);
                    }
                    path = path + "\\" + DateTime.Now.ToString("yyyyMMdd") + ".txt";
                    if (!File.Exists(path))
                    {
                        FileStream fs = File.Create(path);
                        fs.Close();
                    }
                    if (File.Exists(path))
                    {
                        StreamWriter sw = new StreamWriter(path, true, System.Text.Encoding.Default);
                        sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + type + "-->" + content);
                        //  sw.WriteLine("----------------------------------------");
                        sw.Close();
                    }
                }
            }
        }
    }

注:通过上面代码可以获取关注者的昵称、省市,头像的微信基本信息。```
由于获取用户信息时需要先获取Access_Token,以及他的有效期expires_in,同时也有一定次数限制,客户端的每个动作都会去访问服务器,导致Access_Token一直是变化的,会出现无效token,因此需要将Access_Token,expires_in存储起来,进行比对,如果超过时限,再去服务端获取新的Access_Token,expires_in同时替换原来的,具体代码如下

    ```
    namespace WeiXinWeb.BaseManager.DALClass
    {
        public class AccessTokenDAL
        {
            /// <summary>
            /// 根据当前日期 判断Access_Token 是否超期  如果超期返回新的Access_Token   否则返回之前的Access_Token
            /// </summary>
            /// <param name="datetime"></param>
            /// <returns></returns>
            public static string IsExistAccess_Token()
            {
                string Token = string.Empty;
                DateTime YouXRQ;
                // 读取XML文件中的数据,并显示出来 ,注意文件路径
                string filepath = HttpContext.Current.Server.MapPath("../") + "\\Access_token.xml";
    
                StreamReader str = new StreamReader(filepath, Encoding.UTF8);
                XmlDocument xml = new XmlDocument();
                xml.Load(str);
                str.Close();
                str.Dispose();
                Token = xml.SelectSingleNode("xml").SelectSingleNode("Access_Token").InnerText;
                YouXRQ = Convert.ToDateTime(xml.SelectSingleNode("xml").SelectSingleNode("Access_YouXRQ").InnerText);
    
                //TimeSpan st1 = new TimeSpan(YouXRQ.Ticks); //最后刷新的时间
                //TimeSpan st2 = new TimeSpan(DateTime.Now.Ticks); //当前时间
                //TimeSpan st = st2 - st1; //两者相差时间
                if (DateTime.Now > YouXRQ)
                {
                    DateTime _youxrq = DateTime.Now;
                    Access_token mode = GetAccess_token();
                    xml.SelectSingleNode("xml").SelectSingleNode("Access_Token").InnerText = mode.access_token;
                    _youxrq = _youxrq.AddSeconds(int.Parse(mode.expires_in));
                    xml.SelectSingleNode("xml").SelectSingleNode("Access_YouXRQ").InnerText = _youxrq.ToString();
                    xml.Save(filepath);
                    Token = mode.access_token;
    
                  
                }
                CaseRegiestPage.access_token = Token;
                return Token;
            }
    
    
            /// <summary>
            /// 获取Access_token
            /// </summary>
            /// <returns></returns>
            private static Access_token GetAccess_token()
            {
                string appid = ConfigurationManager.AppSettings["AppId"];//微信公众号appid
                string secret = ConfigurationManager.AppSettings["AppSecret"]; //微信公众号appsecret
                string strUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret;
                Access_token mode = new Access_token();
    
                HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(strUrl);  //用GET形式请求指定的地址 
                req.Method = "GET";
    
                using (WebResponse wr = req.GetResponse())
                {
                    //HttpWebResponse myResponse = (HttpWebResponse)req.GetResponse();  
                    StreamReader reader = new StreamReader(wr.GetResponseStream(), Encoding.UTF8);
                    string content = reader.ReadToEnd();
                    reader.Close();
                    reader.Dispose();
    
                    //在这里对Access_token 赋值  
                    Access_token token = new Access_token();
                    token = JsonHelper.ParseFromJson<Access_token>(content);
                    mode.access_token = token.access_token;
                    mode.expires_in = token.expires_in;
                }
                return mode;
            }
            /// <summary>
            /// 基于Sha1的自定义加密字符串方法:输入一个字符串,返回一个由40个字符组成的十六进制的哈希散列(字符串)。
            /// </summary>
            /// <param name="str">要加密的字符串</param>
            /// <returns>加密后的十六进制的哈希散列(字符串)</returns>
            public static string Sha1(string str)
            {
                var buffer = Encoding.UTF8.GetBytes(str);
                var data = SHA1.Create().ComputeHash(buffer);
    
                var sb = new StringBuilder();
                foreach (var t in data)
                {
                    sb.Append(t.ToString("x2"));
                }
    
                return sb.ToString();
            }
            /// <summary>
            /// 获取js票据
            /// </summary>
            /// <param name="token"></param>
            /// <returns></returns>
            public static string GetTicket() {
                string token = IsExistAccess_Token();
                string jsapi_ticket = "";//唯一凭证
                string jsurl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + token + "&type=jsapi";
                HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(jsurl);  //用GET形式请求指定的地址 
                req.Method = "GET";
    
                using (WebResponse wr = req.GetResponse())
                {
                    //HttpWebResponse myResponse = (HttpWebResponse)req.GetResponse();  
                    StreamReader reader = new StreamReader(wr.GetResponseStream(), Encoding.UTF8);
                    string content = reader.ReadToEnd();
                    //jsapi_ticket = content;
                    reader.Close();
                    reader.Dispose();
    
                    JObject outputObj = JObject.Parse(content);
                    jsapi_ticket = outputObj["ticket"].ToString();
                }
                WriteLogs("piaoju","ticket",jsapi_ticket);
                return jsapi_ticket;
            
            }
             /// <summary>
            /// 日志部分
            /// </summary>
            /// <param name="fileName"></param>
            /// <param name="type"></param>
            /// <param name="content"></param>
            public static void WriteLogs(string fileName, string type, string content)
            {
                string path = AppDomain.CurrentDomain.BaseDirectory;
                if (!string.IsNullOrEmpty(path))
                {
                    path = AppDomain.CurrentDomain.BaseDirectory + fileName;
                    if (!Directory.Exists(path))
                    {
                        Directory.CreateDirectory(path);
                    }
                    path = path + "\\" + DateTime.Now.ToString("yyyyMMdd");
                    if (!Directory.Exists(path))
                    {
                        Directory.CreateDirectory(path);
                    }
                    path = path + "\\" + DateTime.Now.ToString("yyyyMMdd") + ".txt";
                    if (!File.Exists(path))
                    {
                        FileStream fs = File.Create(path);
                        fs.Close();
                    }
                    if (File.Exists(path))
                    {
                        StreamWriter sw = new StreamWriter(path, true, System.Text.Encoding.Default);
                        sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + type + "-->" + content);
                        //  sw.WriteLine("----------------------------------------");
                        sw.Close();
                    }
                }
    
            }
        }
    }

```我的存储方式是将这两个值存在文件中

  

      <?xml version="1.0" encoding="utf-8"?>
        <xml>
          <Access_Token>15_6fpcNNpRI8NIQz1BdV6UF4-5uEhP93yaUju50U3YH8mK3_XgHYJLP_eq1RHsxe60HMDUjfS89AVy5KXOrAz_bhDEiTl2OyetAiWn_T9lLqXUC5lcutpm0bKpLzUBTKjAJAHZQ</Access_Token>
          <Access_YouXRQ>2018/11/23 20:37:51</Access_YouXRQ>
        </xml>

  以上代码基本实现微信公众号的验证和用户信息的获取,我们将代码发布到域名下,下面进行白名单配置,客户端要访问Access_Token需要将服务端的IP设置为白名单,具体如下
  ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190114202432715.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM4MDA0MTc3,size_16,color_FFFFFF,t_70)多个ip换行即可(enter键)
接下来我们需要配置自己的菜单,用来在客户端进行访问
点击 微信公众号 左侧主菜单 “自定义菜单”项目,添加菜单即可
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190114201112793.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM4MDA0MTc3,size_16,color_FFFFFF,t_70)添加域名下的网址,如果需要获取用户信息,网址需要带上验证参数,如下
https://open.weixin.qq.com/connect/oauth2/authorize?appid=appid&redirect_uri=http://域名/ZCWeChat/sqsb/CaseRegiestPage.aspx&response_type=code&scope=snsapi_userinfo&m=oauth2&connect_redirect=1#wechat_redirect
即可获得昵称 头像等信息。

接下来需要在微信公众号接口权限下配置域名访问权限,具体如下
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190114201653125.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM4MDA0MTc3,size_16,color_FFFFFF,t_70)接口权限下进行配置,点击修改
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190114201811943.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzM4MDA0MTc3,size_16,color_FFFFFF,t_70)
设置以上三个域名地址,完成域名设置。





  • 8
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值