偷影子的人

c# 微信授权登录与微信支付

起因:最近工作上有一个项目需要在公众号页面用到评论然后发起微信支付的操作,之前未接触过微信,

特别记录一下开发过程的一些细节

stemp1:阅读微信公众号开发文档,十分重要

登录授权:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN

微信支付:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_4

2个页面讲解参数是比较清晰的,但是细节方面其实很多开发者都查阅了很多其他文献才能继续调试开发

stemp2: 登录授权需要前台获取到code 然后提交给后台,后台拿到code才能提交到微信拿到

      //通过code获取openid
        private string getToken(string code)
        {
            string _url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appid + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code";
            WebClient wc = new WebClient();
            //取得微信返回的openid,access_token数据  
            String strReturn = wc.DownloadString(_url);
            return strReturn;
        }

此处直接使用WebClient,是比较笨的方法,后来使用了几个统一的方法

多参数使用     string param = JSONHelper.ObjectToJSON(obj);转化后的串

  1 /// <summary>
  2         /// POST方式调用接口
  3         /// </summary>
  4         /// <param name="Url">要请求Url</param>
  5         /// <returns></returns>
  6         public static string RequestUrlByPOST(string Url, string postData = "UTF-8")
  7         {
  8             string strHtml = "";
  9             try
 10             {
 11                 HttpWebRequest wr;
 12                 System.GC.Collect();
 13                 wr = (HttpWebRequest)WebRequest.Create(Url);
 14                 wr.Headers.Add("charset:utf-8");
 15                 var encoding = Encoding.GetEncoding("utf-8");
 16                 byte[] bytes = encoding.GetBytes(postData);
 17                 wr.Method = "POST";
 18                 wr.Timeout = Int32.MaxValue;
 19                 wr.Credentials = CredentialCache.DefaultCredentials;
 20                 wr.ContentType = "text/xml";
 21                 wr.ContentLength = bytes.Length;
 22                 wr.ServicePoint.Expect100Continue = false;
 23                 using (Stream requestStream = wr.GetRequestStream())
 24                 {
 25                     requestStream.Write(bytes, 0, bytes.Length);
 26                 }
 27                 using (HttpWebResponse response = (HttpWebResponse)wr.GetResponse())
 28                 {
 29                     if (response.StatusCode == HttpStatusCode.OK && wr.HaveResponse)
 30                     {
 31                         if (response != null)
 32                         {
 33                             using (Stream stream = response.GetResponseStream())//获取返回的字符流格式
 34                             {
 35                                 using (StreamReader sr = new StreamReader(stream, System.Text.Encoding.UTF8))//解决乱码:设置utf-8字符格式
 36                                 {
 37                                     if (sr != null)
 38                                     {
 39                                         strHtml = sr.ReadToEnd();
 40                                     }
 41                                 }
 42                             }
 43                         }
 44                     }
 45                 }
 46             }
 47             catch (WebException ex)
 48             {
 49                 throw new Exception(ex.Message);
 50             }
 51             return strHtml;
 52         }
 53 
 54         /// <summary>
 55         /// POST方式调用接口
 56         /// </summary>
 57         /// <param name="Url">要请求Url</param>
 58         /// <returns></returns>
 59         public static string RequestUrlByPOSTWithParam(string Url, string Parameter)
 60         {
 61             string strHtml = "";
 62             try
 63             {
 64                 HttpWebRequest wr;
 65                 System.GC.Collect();
 66                 wr = (HttpWebRequest)WebRequest.Create(Url);
 67                 //ASCIIEncoding encoding = new ASCIIEncoding();
 68                 byte[] bytes = Encoding.UTF8.GetBytes(Parameter);//encoding.GetBytes(codestr);
 69                 wr.Method = "POST";
 70                 //wr.KeepAlive = false;
 71                 //wr.ServicePoint.ConnectionLimit = 300;
 72                 //wr.AllowAutoRedirect = true;
 73                 //wr.ReadWriteTimeout = 10000;
 74                 wr.Timeout = Int32.MaxValue;
 75                 wr.Credentials = CredentialCache.DefaultCredentials;
 76                 wr.ContentType = "application/json";
 77                 wr.Accept = "application/xml";
 78                 wr.Headers.Add("X-Auth-Token", HttpUtility.UrlEncode("OpenStack"));
 79                 wr.ContentLength = bytes.Length;
 80                 wr.ServicePoint.Expect100Continue = false;
 81                 using (Stream requestStream = wr.GetRequestStream())
 82                 {
 83                     requestStream.Write(bytes, 0, bytes.Length);
 84                 }
 85                 using (HttpWebResponse response = (HttpWebResponse)wr.GetResponse())
 86                 {
 87                     if (response.StatusCode == HttpStatusCode.OK && wr.HaveResponse)
 88                     {
 89                         if (response != null)
 90                         {
 91                             using (Stream stream = response.GetResponseStream())//获取返回的字符流格式
 92                             {
 93                                 using (StreamReader sr = new StreamReader(stream, System.Text.Encoding.UTF8))//解决乱码:设置utf-8字符格式
 94                                 {
 95                                     if (sr != null)
 96                                     {
 97                                         strHtml = sr.ReadToEnd();
 98                                     }
 99                                 }
100                             }
101                         }
102                     }
103                 }
104             }
105             catch (WebException ex)
106             {
107                 throw new Exception(ex.Message);
108             }
109             return strHtml;
110         }
View Code

使用到的方法,刚开始写的时候不注意统一,后来需要时间优化

基础方法与获取微信相关信息并返回

 1      #region 获取AccessToken
 2         public static string GetAccessToken()
 3         {
 4             string tokenUrl = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type={0}&appid={1}&secret={2}", grant_type, appid, secret);
 5             var wc = new WebClient();
 6             var strReturn = wc.DownloadString(tokenUrl);
 7             return strReturn;
 8         }
 9         #endregion
10         #region 获取Jsapi_Ticket 
11         public static string GetWeiXinJsapi_Ticket(string accessToken)
12         {
13             string tokenUrl = string.Format("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type={1}", accessToken, type);
14             var wc = new WebClient();
15             var strReturn = wc.DownloadString(tokenUrl); //取得微信返回的json数据  
16             return strReturn;
17         }
18         #endregion
19         #region 基础字符
20         private static string[] strs = new string[]
21                                {
22                                   "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
23                                   "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"
24                                };
25         #endregion
26         #region 创建随机字符串
27         public static string CreatenNonce_str()
28         {
29             Random r = new Random();
30             var sb = new StringBuilder();
31             var length = strs.Length;
32             for (int i = 0; i < 15; i++)
33             {
34                 sb.Append(strs[r.Next(length - 1)]);
35             }
36             return sb.ToString();
37         }
38         #endregion
39         #region  创建时间戳
40         public static long CreatenTimestamp()
41         {
42             return (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
43         }
44         #endregion
45         #region 签名算法
46         /// <summary>
47         /// 签名算法
48         ///本代码来自开源微信SDK项目:https://github.com/night-king/weixinSDK
49         /// </summary>
50         /// <param name="jsapi_ticket">jsapi_ticket</param>
51         /// <param name="noncestr">随机字符串(必须与wx.config中的nonceStr相同)</param>
52         /// <param name="timestamp">时间戳(必须与wx.config中的timestamp相同)</param>
53         /// <param name="url">当前网页的URL,不包含#及其后面部分(必须是调用JS接口页面的完整URL)</param>
54         /// <returns></returns>
55         public static string GetSignature(string jsapi_ticket, string noncestr, long timestamp, string url, out string string1)
56         {
57             var string1Builder = new StringBuilder();
58             string1Builder.Append("jsapi_ticket=").Append(jsapi_ticket).Append("&")
59                           .Append("noncestr=").Append(noncestr).Append("&")
60                           .Append("timestamp=").Append(timestamp).Append("&")
61                           .Append("url=").Append(url.IndexOf("#") >= 0 ? url.Substring(0, url.IndexOf("#")) : url);
62             string1 = string1Builder.ToString();
63             return FormsAuthentication.HashPasswordForStoringInConfigFile(string1, "SHA1");
64             //return Util.Sha1(string1);
65         }
66         #endregion
View Code
 1    //GET api/GetInfoMation
 2         /// <summary>
 3         ///初始化的数据调用微信接口返回参数
 4         /// </summary>
 5         /// <returns></returns>
 6         [AllowAnonymous]
 7         [ActionName("GetInfoMation")]
 8         [HttpGet]
 9         public IHttpActionResult GetInfoMation(string ID, string url = "")
10         {
11             try
12             {
13                 //生成tokcen
14                 string tocken = GetAccessToken();
15                 JObject TokenJO = (JObject)JsonConvert.DeserializeObject(tocken);
16                 //验证签名
17                 string Jsapi_Ticket = GetWeiXinJsapi_Ticket(TokenJO["access_token"].ToString());
18                 JObject Jsapi_TicketJo = (JObject)JsonConvert.DeserializeObject(Jsapi_Ticket);
19                 #region
20                 string rtn = "";
21                 string jsapi_ticket = Jsapi_TicketJo["ticket"].ToString();
22                 string noncestr = CreatenNonce_str();
23                 long timestamp = CreatenTimestamp();
24                 string outstring = "";
25                 string JS_SDK_Result = GetSignature(jsapi_ticket, noncestr, timestamp, url, out outstring);
26 //拼接json串返回前台
27                 rtn = "{\"appid\":\"" + appid + "\",\"jsapi_ticket\":\"" + jsapi_ticket + "\",\"noncestr\":\"" + noncestr + "\",\"timestamp\":\"" + timestamp + "\",\"outstring\":\"" + outstring + "\",\"signature\":\"" + JS_SDK_Result.ToLower() + "\"}";
28                 #endregion
29                 return Json(Success(rtn));
30             }
31             catch (CustomException ce)
32             {
33                 return Json(getException(ce.Message));
34             }
35             catch (Exception ex)
36             {
37                 return Json(getException(ex));
38             }
39         }
View Code

获取公众号下的微信会员信息

 1    //GET api/Login/getCweixinInfo
 2         /// <summary>
 3         ///获取网页授权并返回微信账号信息同时更新微信信息
 4         /// </summary>
 5         /// <param name="code">code</param>
 6         /// <param name="UserId">对象ID</param>
 7         /// <param name="Type">对象类型</param>
 8         /// <returns></returns>
 9         [AllowAnonymous]
10         [ActionName("getCweixinInformation")]
11         [HttpGet]
12         public IHttpActionResult getCweixinInformation(string code, string UserId, string Type = "1")
13         {
14             try
15             {
16                 int uid = UserId.ToIntForPage();
17                 string strReturn = "";
18                 DateTime dtnow = DateTime.Now;
19                 string openId = "";
20                 string accessToken = "";
21                 var log = dbo.mf_Weixinlog.OrderByDescending(c => c.ID).FirstOrDefault();
22                 var user = dbo.mf_User.Where(c => c.UserId == uid).FirstOrDefault();
23                 //if (uid > 0 && log != null && dtnow < log.PastTime && !string.IsNullOrEmpty(user.openid) && user.openid != "oW9b7t-XCA5B2VblXh9rt5bYBo9s")
24                 //{
25                 //    openId = user.openid;
26                 //    accessToken = log.Token;
27                 //}
28                 //else
29                 {
30                     strReturn = getToken(code);
31                     //转换成Json
32                     Newtonsoft.Json.Linq.JObject TickectJO = (Newtonsoft.Json.Linq.JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(strReturn);
33                     openId = TickectJO["openid"].ToString();
34                     accessToken = TickectJO["access_token"].ToString();
35                     Weixinlog model = new Weixinlog
36                     {
37                         Itime = DateTime.Now,
38                         Token = accessToken,
39                         Openid = openId,
40                         Seconds = 7200,
41                         State = 0,
42                         PastTime = DateTime.Now.AddSeconds(7080),
43                         Ticket = "",
44                         UserId = uid
45                     };
46                     dbo.mf_Weixinlog.Add(model);
47                 }
48                 string rnt = "";
49 
50                 strReturn = getWeiXinInfo(accessToken, openId);
51 
52                 rnt = strReturn;
53 
54                 #region 更新微信信息操作
55                 //更新表 User
56                 Newtonsoft.Json.Linq.JObject Cweinxin = (Newtonsoft.Json.Linq.JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(strReturn);
57                 int id = UserId.ToIntForPage();
58                 if (id > 0)
59                 {
60                     if (Type == "1")
61                     {
62                         User usermodel = dbo.User.Where(c => c.UserId == id).FirstOrDefault();
63                         if (usermodel != null)
64                         {
65                             usermodel.updateTime = DateTime.Now;
66                             usermodel.openid = Cweinxin["openid"].ToString();
67                             usermodel.NickName = Cweinxin["nickname"].ToString();
68                             usermodel.Headimgurl = Cweinxin["headimgurl"].ToString();
69                             usermodel.City = Cweinxin["city"].ToString();
70                             usermodel.Province = Cweinxin["province"].ToString();
71                             usermodel.Sex = Cweinxin["sex"].ToString();
72                             dbo.Entry(usermodel).State = System.Data.Entity.EntityState.Modified;
73                             //dbo.SaveChanges();
74                         }
75                     }
76                 #endregion
77 
78                 int r = dbo.SaveChanges();
79                 return Json(rnt);
80             }
81             catch (CustomException ce)
82             {
83                 return Json(getException(ce.Message));
84             }
85             catch (Exception ex)
86             {
87                 return Json(getException(ex));
88             }
89         }
View Code

到此 微信基本信息已获取完毕,需要获取更详细的信息则需要更多的权限

当时做这个的时候,由于开发项目是前后端分离,测试的时候各种疑难杂症,前后台的问题交叉在一起,终究还是获益良多

 

posted @ 2017-07-20 20:17  肉!快到碗里来  阅读(2802)  评论(0编辑  收藏  举报