微信公众号开发C#帮助类-非全部完善
1 using House.IService.Common; 2 using House.IService.Common.Sign; 3 using House.IService.Model; 4 using Microsoft.AspNetCore.Http; 5 using Newtonsoft.Json; 6 using System; 7 using System.Collections.Generic; 8 using System.Data; 9 using System.IO; 10 using System.Linq; 11 using System.Net; 12 using System.Security.Cryptography; 13 using System.Text; 14 using System.Threading.Tasks; 15 using Config = Data.MSSQL.Common; 16 17 namespace House.Service.Common 18 { 19 /// <summary> 20 /// 后续常量规范化,待修改[标记] 21 /// </summary> 22 public class WinXinSingle : IWeiXinSingle 23 { 24 private IHttpContextAccessor _httpContext = null; 25 private ISignSingle _sign = null; 26 private string AppId => CommonFiled.appID; 27 private string AppSecret => CommonFiled.appSecret; 28 29 public WinXinSingle(IHttpContextAccessor http, ISignSingle sign) 30 { 31 this._httpContext = http; 32 this._sign = sign; 33 } 34 35 #region Private 36 private Microsoft.AspNetCore.Http.HttpContext Current 37 { 38 get 39 { 40 return _httpContext.HttpContext; 41 } 42 } 43 44 private string ParamsQuery(string param) 45 { 46 return this._httpContext.HttpContext.Request.Query[param].FirstOrDefault(); 47 } 48 49 #region Session 操作 50 public string GetSession(string key) 51 { 52 byte[] value = null; 53 if (this._httpContext.HttpContext.Session.TryGetValue(key, out value)) 54 { 55 return System.Text.Encoding.Default.GetString(value); 56 } 57 return null; 58 } 59 60 /// <summary> 61 /// 已经修改其他的授权方式,Session已经不需要了。暂时弃用 62 /// </summary> 63 /// <param name="key"></param> 64 /// <param name="val"></param> 65 [Obsolete] 66 public void SetSession(string key, string val) 67 { 68 byte[] value = System.Text.Encoding.Default.GetBytes(val); 69 this._httpContext.HttpContext.Session.Set(key, value); 70 } 71 #endregion 72 73 #endregion 74 75 76 public async Task<string> CheckServer() 77 { 78 //1 自己的服务器代码接受微信提交过来的4个参数 79 string token = CommonFiled.token; 80 string signature = ParamsQuery("signature"); 81 string timestamp = ParamsQuery("timestamp"); 82 string nonce = ParamsQuery("nonce"); 83 string echostr = ParamsQuery("echostr"); 84 string[] temp = { token, timestamp, nonce }; 85 //字典排序 86 Array.Sort(temp); 87 //3个参数拼接成一个字符串 88 string temp1 = string.Join("", temp); 89 //字符串进行sha1加密 90 string code = this._sign.Sha1(temp1); 91 if (code.ToLower().Equals(signature)) 92 { 93 //比较一致,表示通过微信的效验了,返回echostr字符串 94 return echostr; 95 } 96 else 97 { 98 return "Authorization failed:" + echostr; 99 } 100 } 101 102 /// <summary> 103 /// 获取普通的access_token 104 /// </summary> 105 /// <returns></returns> 106 public AccessToken GetAccessToken() 107 { 108 AccessToken token = new AccessToken(); 109 if (token.access_token == null) 110 { 111 //请求微信服务器得到accessToken 112 string url = string.Format(@"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", 113 AppId, AppSecret); 114 string access_token = SendGet(url); 115 return JsonConvert.DeserializeObject<AccessToken>(access_token); 116 } 117 return token; 118 } 119 120 public string GetCodeUrl(string url) 121 { 122 //对url进行编码 123 url = System.Web.HttpUtility.UrlEncode(url); 124 string CodeUrl = string.Format("https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + AppId 125 + "&redirect_uri=" + url + "&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect"); 126 return CodeUrl; 127 } 128 129 public string GetCurrentFullHost() => _httpContext.HttpContext.Request.Host.Value; 130 131 public string GetOpenId() 132 { 133 string openid = ""; 134 var host1 = _httpContext.HttpContext.Request.Host.Value; 135 var host = CommonFiled.DomainURL; 136 string url = host + _httpContext.HttpContext.Request.Path.Value; 137 //先要判断是否是获取code后跳转过来的 138 string code = ParamsQuery("code"); 139 if (string.IsNullOrEmpty(code)) 140 { 141 //Code为空时,先获取Code 142 string GetCodeUrls = GetCodeUrl(url); 143 _httpContext.HttpContext.Response.Redirect(GetCodeUrls);//先跳转到微信的服务器,取得code后会跳回来这页面的 144 } 145 else 146 { 147 string Code = ParamsQuery("code"); 148 openid = GetOauthAccessOpenId(Code)?.openid;//重新取得用户的openid 149 //SetSession("OpenId", Code); 150 } 151 return openid; 152 } 153 154 public string GetOpenId(out string redUrl) 155 { 156 redUrl = ""; 157 string openid = ""; 158 var host1 = _httpContext.HttpContext.Request.Host.Value; 159 var host = CommonFiled.DomainURL; 160 string url = host + _httpContext.HttpContext.Request.Path.Value; 161 //先要判断是否是获取code后跳转过来的 162 string code = ParamsQuery("code"); 163 if (string.IsNullOrEmpty(code)) 164 { 165 //Code为空时,先获取Code 166 redUrl = GetCodeUrl(url); 167 //_httpContext.HttpContext.Response.Redirect(GetCodeUrls);//先跳转到微信的服务器,取得code后会跳回来这页面的 168 } 169 else 170 { 171 string Code = ParamsQuery("code"); 172 openid = GetOauthAccessOpenId(Code)?.openid;//重新取得用户的openid 173 //SetSession("OpenId", Code); 174 } 175 return openid; 176 } 177 178 /// <summary> 179 /// 通过code换取网页授权access_token 180 /// </summary> 181 /// <param name="code"></param> 182 /// <returns></returns> 183 public OAuthToken GetOauthAccessOpenId(string code) 184 { 185 string url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + AppId + "&secret=" + AppSecret + "&code=" + code + "&grant_type=authorization_code"; 186 string access_token = SendGet(url); 187 OAuthToken ac = JsonConvert.DeserializeObject<OAuthToken>(access_token); 188 return ac; 189 } 190 191 192 public string GetRawUrl() 193 { 194 return string.Format("http://{0}{1}", GetCurrentFullHost(), _httpContext.HttpContext.Request.PathBase); 195 } 196 197 public int GetTime() 198 { 199 200 DateTime dateStart = new DateTime(1970, 1, 1, 8, 0, 0); 201 return (int)(DateTime.Now - dateStart).TotalSeconds; 202 } 203 204 public void MusicMessage(string touserName, string formUserName, string title, string remark, string url) 205 { 206 string msg = string.Format(@"<xml> 207 <ToUserName><![CDATA[{0}]]></ToUserName> 208 <FromUserName><![CDATA[{1}]]></FromUserName> 209 <CreateTime>{2}</CreateTime> 210 <MsgType><![CDATA[music]]></MsgType> 211 <Music> 212 <Title><![CDATA[{3}]]></Title> 213 <Description><![CDATA[{4}]]></Description> 214 <MusicUrl><![CDATA[{5}]]></MusicUrl> 215 <HQMusicUrl><![CDATA[{5}]]></HQMusicUrl> 216 </Music> 217 </xml>", formUserName, touserName, GetTime(), title, remark, url); 218 _httpContext.HttpContext.Response.WriteAsync(msg); // 如果需要同步这里再修改 219 } 220 221 public void NewsMessage(string tosuerName, string fromUserName, DataTable dt) 222 { 223 StringBuilder sb = new StringBuilder(); 224 for (int i = 0; i < dt.Rows.Count; i++) 225 { 226 sb.AppendFormat(@"<item> 227 <Title><![CDATA[{0}]]></Title> 228 <Description><![CDATA[{1}]]></Description> 229 <PicUrl><![CDATA[{2}]]></PicUrl> 230 <Url><![CDATA[{3}]]></Url> 231 </item>", dt.Rows[i]["Title"].ToString(), dt.Rows[i]["Remark"].ToString(), dt.Rows[i]["PicUrl"].ToString(), dt.Rows[i]["Url"].ToString()); 232 } 233 string msg = string.Format(@"<xml> 234 <ToUserName><![CDATA[{0}]]></ToUserName> 235 <FromUserName><![CDATA[{1}]]></FromUserName> 236 <CreateTime>{2}</CreateTime> 237 <MsgType><![CDATA[news]]></MsgType> 238 <ArticleCount>{4}</ArticleCount> 239 <Articles> 240 {3} 241 </Articles> 242 </xml> ", fromUserName, tosuerName, GetTime(), sb.ToString(), dt.Rows.Count); 243 _httpContext.HttpContext.Response.WriteAsync(msg); 244 } 245 246 public string SendGet(string url) 247 { 248 //模拟一个浏览器的请求 249 //1.创建一个请求对象 250 WebRequest request = WebRequest.Create(url); 251 request.Method = "GET"; 252 request.ContentType = "applicatoin/x-www/form-urlencoded"; 253 string str = null;//保存请求服务器以后返回的结果 254 //得到 响应的内容 255 WebResponse response = request.GetResponse(); 256 if (response != null) 257 { 258 using (Stream stream = response.GetResponseStream()) 259 { 260 using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) 261 { 262 str = reader.ReadToEnd(); 263 } 264 } 265 } 266 return str; 267 } 268 269 public string SendPost(string url, string requestData) 270 { 271 WebRequest request = WebRequest.Create(url); 272 request.Method = "POST"; 273 byte[] postDatas = null; 274 request.ContentType = "application/x-www-form-urlencoded"; 275 postDatas = Encoding.UTF8.GetBytes(requestData); 276 request.ContentLength = postDatas.Length; 277 using (Stream stream = request.GetRequestStream()) 278 { 279 stream.Write(postDatas, 0, postDatas.Length); 280 } 281 string responseData = null;//服务器响应的数据 282 WebResponse response = request.GetResponse(); 283 if (response != null) 284 { 285 using (Stream st = response.GetResponseStream()) 286 { 287 using (StreamReader reader = new StreamReader(st, Encoding.UTF8)) 288 { 289 responseData = reader.ReadToEnd(); 290 } 291 } 292 } 293 return responseData; 294 } 295 296 public void TextMessage(string toUserName, string formUserName, string content) 297 { 298 string msg = string.Format(@"<xml> 299 <ToUserName><![CDATA[{0}]]></ToUserName> 300 <FromUserName><![CDATA[{1}]]></FromUserName> 301 <CreateTime>{2}</CreateTime> 302 <MsgType><![CDATA[text]]></MsgType> 303 <Content><![CDATA[{3}]]></Content> 304 </xml>", formUserName, toUserName, GetTime(), content); 305 _httpContext.HttpContext.Response.WriteAsync(msg); 306 } 307 308 /// <summary> 309 /// 获取签名用于JS-SDK的调用 310 ///出于安全考虑,开发者必须在服务器端实现签名的逻辑。 311 /// </summary> 312 public string GetJsApiSign(string noncestr, string jsapi_ticket, string timestamp, string url) 313 { 314 //将字段添加到列表中。 315 string[] arr = new[] 316 { 317 string.Format("noncestr={0}",noncestr), 318 string.Format("jsapi_ticket={0}",jsapi_ticket), 319 string.Format("timestamp={0}",timestamp), 320 string.Format("url={0}",url) 321 }; 322 //字典排序 323 Array.Sort(arr); 324 //使用URL键值对的格式拼接成字符串 325 var temp = string.Join("&", arr); 326 return this._sign.Sha1(temp).ToLower(); 327 } 328 329 public JsApiTicket GetHsJsApiTicket(string accessToken) 330 { 331 JsApiTicket ticket = new JsApiTicket(); 332 if (ticket.ticket == null) 333 { 334 var url = string.Format("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=jsapi", accessToken); 335 string ticketjson = SendGet(url); 336 return JsonConvert.DeserializeObject<JsApiTicket>(ticketjson); 337 } 338 return ticket; 339 } 340 341 public object JsApiSignature(string requestUrl) { 342 AccessToken accessToken = GetAccessToken(); 343 JsApiTicket ticket = GetHsJsApiTicket(accessToken.access_token); 344 string nonceStr = CommonFiled.guid; 345 string timestamp = CommonFiled.unixTime10; 346 var WxConfig = new 347 { 348 debug = false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 349 appId = CommonFiled.appID, // 必填,公众号的唯一标识 350 timestamp, // 必填,生成签名的时间戳 351 nonceStr, // 必填,生成签名的随机串 352 jsApiList = new string[] { "chooseImage", "previewImage", "getLocation" }, // 必填,需要使用的JS接口列表 353 signature = GetJsApiSign(nonceStr, ticket.ticket, timestamp, requestUrl) 354 }; 355 return WxConfig; 356 } 357 358 } 359 }