第一部分:基礎配置api
第一步:註冊微信公衆帳號安全
若是開發測試階段能夠打開測試連接地址,註冊測試公衆號。測試帳號除了不能與正式帳號通訊外其餘什麼高級接口的均可以實現。服務器
測試號管理地址:http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login微信
帳號開通成功後系統會分配兩個帳號信息:appID、appsecret做爲此帳號的標識。app
第二步:接口配置信息測試
這裏的接口配置主要爲保證微信能與你所建的站點進行數據交互,而且數據的傳遞要符合規則。this
這裏須要完成兩個參數配置:加密
URL:你能夠在本身的項目中新建一個action或者其餘在微信訪問此地址時能返回數據就行。url
Token:一個創建二者對話的口令,設置完成後項目中也須要配置一樣的Token方可正常通訊。spa
這裏你能夠在定義的URL中直接返回微信的請求「echostr」參數值,固然正常狀況下是須要按照規則驗證數據的請求安全後返回。
能夠在請求的URL指定的Action中按照微信官方提示,作以下簽名驗證(這樣作屬於安全的):
public ActionResult Webcatch() { string token = "loyung"; if (string.IsNullOrWhiteSpace(token)) { return null; } string echoStr = Request.QueryString["echoStr"];//隨機字符串 string signature = Request.QueryString["signature"];//微信加密簽名 string timestamp = Request.QueryString["timestamp"];//時間戳 string nonce = Request.QueryString["nonce"];//隨機數 string[] ArrTmp = { token, timestamp, nonce }; Array.Sort(ArrTmp); //字典排序 string tmpStr = string.Join("", ArrTmp); tmpStr = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1"); tmpStr = tmpStr.ToLower(); if (tmpStr == signature) { return Content(echoStr); } else { return Content("false"); } }
第三步:JS接口安全域名配置
按照頁面的提示,配置上須要作微信接口的域名配置。
第二部分:關於微信操做類的封裝
以上第一部分爲入門級的簡單操做,若是要把微信的整個接口開發完,固然要思考怎樣把微信的每一個接口無縫對接到現有系統。
思路:1.將接口的經常使用返回值做爲一種類型去接收。
2.微信接口均可以使用GET請求,能夠封裝Get數據請求處理工廠。
3.最重要的莫過於每次請求都須要有效的access_token,因爲access_token的有效期只有兩個小時,這裏咱們採用文件的形式記錄access_token,並在每次使用前檢查access_token是否可用。
4.代碼文件:Model WeiXinModel.cs存放數據要被序列化的實體類結構,Control WeChat.cs用來封裝全部接口的調用以及對access_token的處理。View 直接調用WeChat封裝接口。
因爲全部接口實在太多,這裏作一個獲取全部關注粉絲信息的Demo。
Model WeiXinModel.cs
/* * 建立時間:2016-07-19 * 建立人:劉自洋 * 說明:此文件下包含全部微信實體類 */ using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace Ecio_Admin.Models { #region 系統返回信息 /// <summary> /// 系統返回信息 /// </summary> /// <typeparam name="T">指定返回類型</typeparam> public class wx_backdata<T> { /// <summary> /// 接口返回數據狀態true成功|false失敗 /// </summary> public bool ResponseState; /// <summary> /// 接口返回正確數據 /// </summary> public T ResponseData; /// <summary> /// 接口返回錯誤時間 /// </summary> public wx_apperror ErrorData; } #endregion #region 微信接口返回錯誤類 /// <summary> /// 微信接口返回錯誤類 /// </summary> public class wx_apperror { /// <summary> /// 接口錯誤代碼 /// </summary> public string errcode; /// <summary> /// 接口錯誤消息 /// </summary> public string errmsg; } #endregion #region 獲取接口返回Token /// <summary> /// 獲取接口返回憑證Token /// </summary> public class wx_access_token { /// <summary> /// 獲取到的憑證 /// </summary> public string access_token; /// <summary> /// 憑證有效時間,單位:秒 /// </summary> public string expires_in; } #endregion #region 獲取此用戶OpenID /// <summary> /// 獲取用戶OpenID列表 /// </summary> public class wx_openidlist { /// <summary> /// 關注該公衆帳號的總用戶數 /// </summary> public string total; /// <summary> /// 拉取的OPENID個數,最大值爲10000 /// </summary> public string count; /// <summary> /// 列表數據,OPENID的列表 /// </summary> public data data; /// <summary> /// 拉取列表的最後一個用戶的OPENID /// </summary> public string next_openid; } /// <summary> /// openid對象 /// </summary> public class data { /// <summary> /// 用戶標識 /// </summary> public List<string> openid; } #endregion #region 獲取用戶我的信息 public class wx_user_info { /// <summary> /// 是否訂閱該公衆號0沒有關注|1已關注 /// </summary> public string subscribe; /// <summary> /// 用戶的標識,對當前公衆號惟一 /// </summary> public string openid; /// <summary> /// 用戶的暱稱 /// </summary> public string nickname; /// <summary> /// 用戶的性別0未知|1男性|2女性 /// </summary> public string sex; /// <summary> /// 用戶所在城市 /// </summary> public string city; /// <summary> /// 用戶所在國家 /// </summary> public string country; /// <summary> /// 用戶所在省份 /// </summary> public string province; /// <summary> /// 用戶的語言 /// </summary> public string language; /// <summary> /// 用戶頭像,最後一個數值表明正方形頭像大小(有0、4六、6四、9六、132數值可選,0表明640*640正方形頭像) /// </summary> public string headimgurl; /// <summary> /// 用戶關注時間 /// </summary> public string subscribe_time; /// <summary> /// 綁定到微信開放平臺惟一標識 /// </summary> public string unionid; /// <summary> /// 粉絲備註 /// </summary> public string remark; /// <summary> /// 用戶所在的分組ID(兼容舊的用戶分組接口) /// </summary> public string groupid; /// <summary> /// 用戶被打上的標籤ID列表 /// </summary> public List<string> tagid_list; } #endregion }
Control WeChat.cs
/* * 建立時間:2016-07-18 * 建立人:劉自洋 * 說明:此類包含微信相關配置,接口憑據獲取、更新,以及經常使用接口調用。 */ using Ecio_Admin.Models; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Xml; namespace Ecio_Admin.Common { /// <summary> /// 微信配置、操做類 /// </summary> public class WeChat { #region 【構造】微信配置 /// <summary> /// 初始化微信參數配置 /// </summary> public WeChat() { XmlDocument Xml = new XmlDocument(); Xml.Load(HttpContext.Current.Server.MapPath("~/App_Data/Config/WeiXin.config")); XmlNode appid = Xml.SelectSingleNode("weixin/appid"); XmlNode appsecret = Xml.SelectSingleNode("weixin/appsecret"); XmlNode accesstoken = Xml.SelectSingleNode("weixin/accesstoken"); XmlNode token = Xml.SelectSingleNode("weixin/token"); if (appid != null) { this.appid = appid.InnerText; } if (appsecret != null) { this.secret = appsecret.InnerText; } if (accesstoken != null) { if (check_access_token()) { this.accesstoken = accesstoken.InnerText; } else { var backdate = get_access_token(); //更新當前access_token if (backdate.ResponseState) { this.accesstoken = backdate.ResponseData.access_token; accesstoken.InnerText = backdate.ResponseData.access_token; Xml.Save(HttpContext.Current.Server.MapPath("~/App_Data/Config/WeiXin.config")); } } } if (token != null) { this.token = token.InnerText; } } #endregion #region 【配置】微信基礎參數 /// <summary> /// 服務器標識 /// </summary> private string token = "loyung"; /// <summary> /// 開發者ID(AppID(應用ID)) /// </summary> private string appid = "wx**********"; /// <summary> /// (AppSecret(應用密鑰)) /// </summary> private string secret = "************ "; /// <summary> ///接口鏈接憑據 /// </summary> private string accesstoken = ""; #endregion #region 【驗證】微信簽名 /// <summary> /// 微信簽名驗證 /// </summary> /// <param name="nonce">隨機字符串 </param> /// <param name="timestamp">時間戳 </param> /// <param name="signature">微信加密簽名</param> /// <returns>驗籤是否成功true成功|false失敗</returns> public bool CheckSign(string nonce, string timestamp, string signature) { string[] ArrTmp = { token, timestamp, nonce }; Array.Sort(ArrTmp); //字典排序 string tmpStr = string.Join("", ArrTmp); tmpStr = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1"); tmpStr = tmpStr.ToLower(); if (tmpStr == signature) { return true; } else { return false; } } #endregion #region 【驗證】access_token是否失效 /// <summary> /// 根據接口返回代碼42001驗證是否可用 /// </summary> /// <returns>true可用|false失效</returns> public bool check_access_token() { XmlDocument Xml = new XmlDocument(); Xml.Load(HttpContext.Current.Server.MapPath("~/App_Data/Config/WeiXin.config")); XmlNode access_token = Xml.SelectSingleNode("weixin/accesstoken"); if (access_token != null) { this.accesstoken = access_token.InnerText; } string Url = "https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=" + this.accesstoken; string GetResult = ToolKit.GetData(Url); if (GetResult.IndexOf("errcode") != -1) { var ErrorMessage = JsonConvert.DeserializeObject<wx_apperror>(GetResult); if (ErrorMessage.errcode == "42001") { return false; } return false; } else { return true; } } #endregion #region 【通用】獲取可用接口憑據 /// <summary> /// 獲取可用的接口憑據 /// </summary> public string Accesstoken() { if (!check_access_token()) { XmlDocument Xml = new XmlDocument(); Xml.Load(HttpContext.Current.Server.MapPath("~/App_Data/Config/WeiXin.config")); XmlNode access_token = Xml.SelectSingleNode("weixin/accesstoken"); if (access_token != null) { var backdate = get_access_token(); //更新當前access_token if (backdate.ResponseState) { this.accesstoken = backdate.ResponseData.access_token; access_token.InnerText = backdate.ResponseData.access_token; Xml.Save(HttpContext.Current.Server.MapPath("~/App_Data/Config/WeiXin.config")); } } } return this.accesstoken; } #endregion #region【通用】獲取JSON指定類型返回值 /// <summary> /// 【通用】獲取JSON指定類型返回值 /// </summary> /// <typeparam name="T">指定非錯誤的返回類型</typeparam> /// <param name="JsonData">序列化前JSON字符</param> /// <returns>JSON序列化後數據</returns> public wx_backdata<T> GetJson<T>(string JsonData) { var result = new wx_backdata<T>(); if (JsonData.IndexOf("errcode") != -1) { result.ResponseState = false; result.ErrorData = JsonConvert.DeserializeObject<wx_apperror>(JsonData); } else { result.ResponseState = true; result.ResponseData = JsonConvert.DeserializeObject<T>(JsonData); } return result; } #endregion #region 【access_token】獲取惟一接口調用憑據 /// <summary> /// 獲取惟一接口調用憑據access_token /// </summary> /// <returns>access_token獲取結果對象</returns> public wx_backdata<wx_access_token> get_access_token() { string Url = "https://api.weixin.qq.com/cgi-bin/token?"; string grant_type = "client_credential"; string GetResult = ToolKit.GetData(Url + "grant_type=" + grant_type + "&appid=" + appid + "&secret=" + secret); return GetJson<wx_access_token>(GetResult); } #endregion #region【OpenId】 獲取用戶列表 /// <summary> /// 獲取粉絲微信OpenId /// </summary> /// <returns>接口返回值</returns> public wx_backdata<wx_openidlist> GetOpenIdList() { string Url = "https://api.weixin.qq.com/cgi-bin/user/get?"; string GetResult = ToolKit.GetData(Url + "access_token=" + this.Accesstoken() + "&next_openid="); return GetJson<wx_openidlist>(GetResult); } #endregion #region 【用戶信息】獲取指定用戶信息 /// <summary> /// 獲取指定用戶信息 /// </summary> /// <param name="openid">用戶標識</param> /// <returns>接口返回值</returns> public wx_backdata<wx_user_info> GetUserInfo(string openid) { string Url = "https://api.weixin.qq.com/cgi-bin/user/info?"; string GetResult = ToolKit.GetData(Url + "access_token=" + this.Accesstoken() + "&openid=" + openid + "&lang=zh_CN"); return GetJson<wx_user_info>(GetResult); } #endregion } }
View UserList.cshtm
public ActionResult GetUserList(int? page, int? take) { List<wx_user_info> Users = new List<wx_user_info>(); var OpenList = new WeChat().GetOpenIdList(); if (OpenList.ResponseState) { foreach (var item in OpenList.ResponseData.data.openid) { var backdata = new WeChat().GetUserInfo(item); if (backdata.ResponseState) { Users.Add(backdata.ResponseData); } } ViewBag.Tip = OpenList.ResponseData.count + "人"; } else { ViewBag.Tip = "系統異常,編號:" + OpenList.ErrorData.errcode + "錯誤信息:" + OpenList.ErrorData.errmsg; } var PageUseras = Users.Where(ua=>true); return View(PageUseras); }
File WeiXin.config
<?xml version="1.0" encoding="utf-8"?> <weixin> <appid>wx**********</appid> <appsecret>*********</appsecret> <accesstoken>_VqnWkCBEOch4vUgNB7ssBkYIzcsYgW3azkztMLur-OUqKk95U-Sfaqv9XNvGiToAWee2nybxXCtC5x3ipRoT8WotxmM_vZr-WqmD0_XJ9szMZXsqx57EkndVprc1dBtBAQaAFAMLB</accesstoken> <token>loyung</token> </weixin>
效果:
後面其餘接口及返回,就按照一樣的方式添加代碼。