using System; using System.Collections.Generic; using System.Net; using System.Text; using System.Web; using Quiz.Utility; namespace Quiz.SiteBase { public class WeixinApi { static Dictionary Cache = new Dictionary(); public static string oauthurl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type=code&scope=snsapi_base&state=1#wechat_redirect"; public static string oauthuserinfourl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect"; public static string wapurl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code"; public static string userinfourl = "https://api.weixin.qq.com/sns/userinfo?access_token={0}&openid={1}&lang=zh_CN"; public static WeixinAccount GetWeixinAccount(string actid) { if (!Cache.ContainsKey(actid)) { List wxList = SiteBase.Cache.CacheManage.Weixin.CacheData; if (wxList == null) return null; Models.Weixin wxaccount = wxList.Find(o => o.ActId == actid); //appid等没的话不缓存 account,为了不获取token ticket if (wxaccount == null || string.IsNullOrEmpty(wxaccount.AppId) || string.IsNullOrEmpty(wxaccount.AppSecret)) return null; WeixinAccount account = new WeixinAccount(actid, wxaccount.AppId, wxaccount.AppSecret); account.TokenRefresh += AccountOnTokenRefresh; Cache.Add(actid, account); } return Cache[actid]; } private static void AccountOnTokenRefresh(string actid) { List wxList = SiteBase.Cache.CacheManage.Weixin.CacheData; Models.Weixin wxaccount = wxList.Find(o => o.ActId == actid); if (wxaccount == null || string.IsNullOrEmpty(wxaccount.AppId) || string.IsNullOrEmpty(wxaccount.AppSecret)) Cache.Remove(actid); else if (Cache.ContainsKey(actid)) Cache[actid].Update(wxaccount.AppId, wxaccount.AppSecret); } public static string GetToken(string actid) { try { WeixinAccount account = GetWeixinAccount(actid);//缓存的公众号信息 //返回Token return account == null ? "" : account.AccessToken; } catch (Exception err) { return ""; } } public static string GetJsapiTicket(string actid) { WeixinAccount account = GetWeixinAccount(actid);//缓存的公众号信息 return account == null ? "" : account.JsapiTicket; } } #region 微信公众号信息 public delegate void AccessTokenCallback(string actid); /// /// 微信公众号信息 /// public class WeixinAccount { static WeiXinAction action = new WeiXinAction(); private string app_secret; private string jsapi_ticket; private string access_token; /// /// jsapi_ticket到期时间 /// private DateTime jsapi_ticket_time; /// /// access_token到期时间 /// private DateTime access_token_time; public string Id { get; private set; } /// /// 公众号AppID /// public string AppId { get; private set; } /// /// jsapi_ticket, 有效期为7200秒 /// public string JsapiTicket { get { if (jsapi_ticket_time < DateTime.Now) { var ticket = action.GetJsapiTicket(AccessToken, jsapi_ticket_time); if (ticket == null || ticket.errcode != 0) return string.Empty; jsapi_ticket = ticket.ticket; jsapi_ticket_time = DateTime.Now.AddSeconds(ticket.expires_in); } return jsapi_ticket; } } /// /// access_token, 有效期7200秒 /// public string AccessToken { get { if (access_token_time < DateTime.Now) { OnTokenRefresh(Id); var token = action.GetToken(AppId, app_secret, access_token_time); if (token == null) return string.Empty; access_token = token.access_token; access_token_time = DateTime.Now.AddSeconds(int.Parse(token.expires_in)); } return access_token; } } /// /// 实例化微信公众号 /// /// /// /// public WeixinAccount(string id, string appid, string secret) { Id = id; AppId = appid; app_secret = secret; access_token_time = DateTime.Parse("1970-01-01"); jsapi_ticket_time = DateTime.Parse("1970-01-01"); } public event AccessTokenCallback TokenRefresh; protected virtual void OnTokenRefresh(string actid) { var handler = TokenRefresh; if (handler != null) handler(actid); } public void Update(string appid, string secret) { if (AppId != null || app_secret != secret) { AppId = appid; app_secret = secret; access_token_time = DateTime.Parse("1970-01-01"); jsapi_ticket_time = DateTime.Parse("1970-01-01"); } } } #endregion #region 获取token和jsticket public class WeiXinAction { /// /// 获得Token /// /// /// /// token到期时间,获取的时间+7200 /// 过期了返回新的Access_Token,否则返回空 public Access_Token GetToken(string appid, string secret, DateTime YouXRQ) { if (DateTime.Now > YouXRQ) //过期 { string Str = GetJson(string.Format(new WeiUrlConfig().URL_GetToken, appid, secret)); return JsonHelper.ParseFromJson(Str); } return null; } /// /// 获得JsapiTicket /// /// /// /// public JsapiTicket GetJsapiTicket(string token, DateTime YouXRQ) { if (DateTime.Now > YouXRQ) //过期 { string Str = GetJson(string.Format(new WeiUrlConfig().URL_GetJsapiTicket, token)); return JsonHelper.ParseFromJson(Str); } return null; } private string GetJson(string url) { ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls; //SSL3协议替换成TLS协议 WebClient wc = new WebClient(); wc.Credentials = CredentialCache.DefaultCredentials; wc.Encoding = Encoding.UTF8; string returnText = wc.DownloadString(url); if (returnText.Contains("errcode")) { //可能发生错误 } return returnText; } } #endregion #region 授权类型 public class OAuth_Token { public OAuth_Token() { // //TODO: 在此处添加构造函数逻辑 // } //access_token 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同 //expires_in access_token接口调用凭证超时时间,单位(秒) //refresh_token 用户刷新access_token //openid 用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID //scope 用户授权的作用域,使用逗号(,)分隔 public string access_token { get; set; } public string expires_in { get; set; } public string refresh_token { get; set; } public string openid { get; set; } public string scope { get; set; } } public class Access_Token { public string access_token { get; set; } public string expires_in { get; set; } } public class Ticket { public string ticket { get; set; } public string expire_seconds { get; set; } } public class JsapiTicket { public int errcode { get; set; } public string errmsg { get; set; } public string ticket { get; set; } public int expires_in { get; set; } } #endregion #region 配置信息 public class WeiUrlConfig { public string URL_GetToken = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}"; public string URL_GetJsapiTicket = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=jsapi"; public string URL_User_ALL = "https://api.weixin.qq.com/cgi-bin/user/get?access_token={0}&next_openid={1}"; public string URL_User_One = "https://api.weixin.qq.com/cgi-bin/user/info?access_token={0}&openid={1}&lang=zh_CN"; public string URL_User_GroupCreate = "https://api.weixin.qq.com/cgi-bin/groups/create?access_token={0}"; public string URL_User_GroupALL = "https://api.weixin.qq.com/cgi-bin/groups/get?access_token={0}"; public string URL_User_GroupIDGet = "https://api.weixin.qq.com/cgi-bin/groups/getid?access_token={0}"; public string URL_User_GroupUpdate = "https://api.weixin.qq.com/cgi-bin/groups/update?access_token={0}"; public string URL_User_GroupMove = "https://api.weixin.qq.com/cgi-bin/groups/members/update?access_token={0}"; public string URL_Menu_Greate = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token={0}"; public string URL_Menu_Get = "https://api.weixin.qq.com/cgi-bin/menu/get?access_token={0}"; public string URL_Menu_Delete = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token={0}"; public string URL_GetTicket = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={0}"; public string URL_GetD2Image = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={0}"; public string URL_GetFile = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token={0}&media_id={1}"; public string URL_UploadFile = "http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token={0}&type={1}"; public string URL_UpVideo = "https://file.api.weixin.qq.com/cgi-bin/media/uploadvideo?access_token={0}"; //群发 上传图文 public string URL_SendAllByGroup = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token={0}"; public string URL_SendAllByOpenid = "https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token={0}"; public string URL_UploadArticle = "https://api.weixin.qq.com/cgi-bin/media/uploadnews?access_token={0}"; public string URL_DeleteSendALL = "https://api.weixin.qq.com//cgi-bin/message/mass/delete?access_token={0}"; //48小时内发送客服消息 public string URL_SendMSG = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={0}"; //聊天记录 public string URL_GetChatLog = "https://api.weixin.qq.com/cgi-bin/customservice/getrecord?access_token={0}"; } #endregion }