1 微信开放平台:https://open.weixin.qq.com/
2 微信官方教程:https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN
4. 通过官方提供的文档,我们可以看出一共分4个步骤
第一步:请求CODE
第二步:通过code获取access_token
第三步:通过access_token调用接口
第4步:获取用户个人信息(UnionID机制)
5.源码下载地址:http://pan.baidu.com/s/1pLyG66J
因代码加密:现贴出代码如下(下载后替换):
Controllers--》DefaultController.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Configuration; 4 using System.Text; 5 using System.Web; 6 using System.Web.Mvc; 7 8 using WebWeChat.Models; 9 10 namespace WebWeChat.Controllers 11 { 12 public class DefaultController : Controller 13 { 14 #region 微信登录 15 16 ///17 /// 微信登录 18 /// 19 public ActionResult WeChat() 20 { 21 //获得配置信息 22 string oauthAppId = ConfigurationManager.AppSettings["oauth_app_id"]; 23 string redirectUri = ConfigurationManager.AppSettings["Redirect_uri"]; 24 if (oauthAppId == null) 25 { 26 return this.Content("出错了,您尚未配置微信相关的API信息!"); 27 } 28 string state = Guid.NewGuid().ToString().Replace("-", ""); 29 this.Session["oauth_state"] = state; 30 string sendUrl = 31 "https://open.weixin.qq.com/connect/qrconnect?appid=" + oauthAppId + 32 "&redirect_uri=" + HttpUtility.UrlEncode(redirectUri.ToLower()) + 33 "&response_type=code&scope=snsapi_login&state=" + state + 34 "#wechat_redirect"; 35 36 //开始发送 37 return this.Redirect(sendUrl); //跳转到微信自己 指定的关联登陆页面 38 } 39 40 /// 41 /// 微信登录返回action 42 /// 43 public ActionResult WeChatReturnUrl(string state, string code) 44 { 45 //取得返回参数 46 47 if (this.Session["oauth_state"] == null || this.Session["oauth_state"].ToString() == "" || 48 state != this.Session["oauth_state"].ToString() || string.IsNullOrEmpty(code)) //若返回参数中未包含code或者state没有通过验证则提示出错 49 { 50 return this.Content("出错啦,state未初始化!"); 51 } 52 53 //第一步:通过code来获取Access Token以及openid 54 Dictionary<string, object> dic1 = WeixinHelper.get_access_token(code, state); 55 if (dic1 == null || !dic1.ContainsKey("access_token")) 56 { 57 return this.Content("错误代码:,无法获取Access Token,请检查App Key是否正确!"); 58 } 59 if (!dic1.ContainsKey("openid")) 60 { 61 return dic1.ContainsKey("errmsg") 62 ? this.Content("errcode:" + dic1["errcode"] + ",errmsg:" + dic1["errmsg"]) 63 : this.Content("出错啦,无法获取用户授权Openid!"); 64 } 65 66 var accessToken = dic1["access_token"].ToString(); 67 var refreshToken = dic1["refresh_token"].ToString(); 68 var openid = dic1["openid"].ToString(); 69 70 //储存获取数据用到的信息 71 this.Session["oauth_name"] = "webchat"; 72 this.Session["oauth_access_token"] = accessToken; 73 this.Session["oauth_openid"] = openid; 74 this.Session["oauth_refresh_token"] = refreshToken; 75 76 #region todo 将获取到的用户信息保存到数据库中 77 78 #endregion 79 80 //第二步:通过Access Token以及openid来获取用户的基本信息 81 //Dictionary dic2 = weixin_helper.get_user_info(access_token,openid); 82 83 //第三步:跳转到指定页面 84 return this.Content(this.WeChatResultJson()); 85 } 86 87 ///88 /// 微信登录返回action, 处理用户信息 89 /// 90 public string WeChatResultJson() 91 { 92 if (this.Session["oauth_name"] == null || this.Session["oauth_access_token"] == null || 93 this.Session["oauth_openid"] == null) 94 { 95 return "{\"ret\":\"1\", \"msg\":\"出错啦,Access Token已过期或不存在!\"}"; 96 } 97 var oauthName = this.Session["oauth_name"].ToString(); 98 var oauthAccessToken = this.Session["oauth_access_token"].ToString(); 99 var oauthOpenid = this.Session["oauth_openid"].ToString(); 100 var oauthRefreshToken = this.Session["oauth_refresh_token"].ToString(); 101 102 if (!WeixinHelper.check_access_token(oauthAccessToken)) //调用access_token前需判断是否过期 103 { 104 Dictionary<string, object> dic1 = WeixinHelper.get_refresh_token(oauthRefreshToken); //如果已过期则重新换取新的access_token 105 if (dic1 == null || !dic1.ContainsKey("access_token")) 106 { 107 return "{\"openid\":\"0\", \"msg\":\"出错啦,无法获取access_token!\"}"; 108 } 109 oauthAccessToken = dic1["access_token"].ToString(); 110 } 111 112 Dictionary<string, object> dic = WeixinHelper.get_user_info(oauthAccessToken, oauthOpenid); 113 if (dic == null) 114 { 115 return "{\"openid\":\"0\", \"msg\":\"出错啦,无法获取授权用户信息!\"}"; 116 } 117 try 118 { 119 StringBuilder str = new StringBuilder(); 120 str.Append("{"); 121 str.Append("\"openid\": \"" + dic["openid"] + "\", "); 122 str.Append("\"nickname\": \"" + dic["nickname"] + "\", "); 123 str.Append("\"sex\": \"" + dic["sex"] + "\", "); 124 str.Append("\"province\": \"" + dic["province"] + "\", "); 125 str.Append("\"city\": \"" + dic["city"] + "\", "); 126 str.Append("\"country\": \"" + dic["country"] + "\", "); 127 str.Append("\"headimgurl\": \"" + dic["headimgurl"] + "\", "); 128 str.Append("\"privilege\": \"" + dic["privilege"] + "\", "); 129 str.Append("\"unionid\": \"" + dic["unionid"] + "\""); 130 str.Append("\"oauth_name\": \"" + oauthName + "\""); 131 str.Append("\"oauth_access_token\": \"" + oauthAccessToken + "\""); 132 str.Append("\"oauth_openid\": \"" + oauthOpenid + "\""); 133 str.Append("}"); 134 return str.ToString(); 135 } 136 catch 137 { 138 return "{\"ret\":\"0\", \"msg\":\"出错啦,无法获取授权用户信息!\"}"; 139 } 140 } 141 142 #endregion 143 } 144 }
Models---》HttpMethods
1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 using System.Net; 5 using System.Text; 6 7 namespace WebWeChat.Models 8 { 9 //////////////////////////////////////////////////////////////////////////////////////////////////// 10 ///A HTTP methods. 11 /// 12 /// xiaop, 2014/12/16. 13 //////////////////////////////////////////////////////////////////////////////////////////////////// 14 public static class HttpMethods 15 { 16 #region POST 17 18 /// 19 /// HTTP POST方式请求数据 20 /// 21 /// URL. 22 /// POST的数据 23 /// 24 public static string HttpPost(string url, string param) 25 { 26 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 27 request.Method = "POST"; 28 request.ContentType = "application/x-www-form-urlencoded"; 29 request.Accept = "*/*"; 30 request.Timeout = 15000; 31 request.AllowAutoRedirect = false; 32 33 string responseStr; 34 35 var requestStream = new StreamWriter(request.GetRequestStream()); 36 requestStream.Write(param); 37 requestStream.Close(); 38 39 var response = request.GetResponse(); 40 { 41 // ReSharper disable once AssignNullToNotNullAttribute 42 StreamReader reader = new StreamReader(stream: response.GetResponseStream(), encoding: Encoding.UTF8); 43 responseStr = reader.ReadToEnd(); 44 reader.Close(); 45 } 46 47 return responseStr; 48 } 49 50 #endregion 51 52 #region Get 53 54 /// 55 /// HTTP GET方式请求数据. 56 /// 57 /// URL. 58 /// 59 public static string HttpGet(string url) 60 { 61 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 62 request.Method = "GET"; 63 64 //request.ContentType = "application/x-www-form-urlencoded"; 65 request.Accept = "*/*"; 66 request.Timeout = 15000; 67 request.AllowAutoRedirect = false; 68 69 string responseStr; 70 71 var response = request.GetResponse(); 72 73 { 74 // ReSharper disable once AssignNullToNotNullAttribute 75 StreamReader reader = new StreamReader(stream: response.GetResponseStream(), encoding: Encoding.UTF8); 76 responseStr = reader.ReadToEnd(); 77 reader.Close(); 78 } 79 80 return responseStr; 81 } 82 83 #endregion 84 85 #region Post With Pic 86 87 public static string HttpPost(string url, IDictionary<object, object> param, string filePath) 88 { 89 string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x"); 90 byte[] boundarybytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n"); 91 92 HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url); 93 wr.ContentType = "multipart/form-data; boundary=" + boundary; 94 wr.Method = "POST"; 95 wr.KeepAlive = true; 96 wr.Credentials = CredentialCache.DefaultCredentials; 97 98 Stream rs = wr.GetRequestStream(); 99 string responseStr = null; 100 101 string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}"; 102 foreach (string key in param.Keys) 103 { 104 rs.Write(boundarybytes, 0, boundarybytes.Length); 105 string formitem = string.Format(formdataTemplate, key, param[key]); 106 byte[] formitembytes = Encoding.UTF8.GetBytes(formitem); 107 rs.Write(formitembytes, 0, formitembytes.Length); 108 } 109 rs.Write(boundarybytes, 0, boundarybytes.Length); 110 111 string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n"; 112 string header = string.Format(headerTemplate, "pic", filePath, "text/plain"); 113 byte[] headerbytes = Encoding.UTF8.GetBytes(header); 114 rs.Write(headerbytes, 0, headerbytes.Length); 115 116 FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read); 117 byte[] buffer = new byte[4096]; 118 int bytesRead; 119 while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0) 120 { 121 rs.Write(buffer, 0, bytesRead); 122 } 123 fileStream.Close(); 124 125 byte[] trailer = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n"); 126 rs.Write(trailer, 0, trailer.Length); 127 rs.Close(); 128 129 WebResponse wresp = null; 130 try 131 { 132 wresp = wr.GetResponse(); 133 Stream stream2 = wresp.GetResponseStream(); 134 if (stream2 != null) 135 { 136 StreamReader reader2 = new StreamReader(stream2); 137 responseStr = reader2.ReadToEnd(); 138 } 139 140 //logger.Debug(string.Format("File uploaded, server response is: {0}", responseStr)); 141 } 142 catch (Exception) 143 { 144 //logger.Error("Error uploading file", ex); 145 if (wresp != null) 146 { 147 wresp.Close(); 148 } 149 } 150 return responseStr; 151 } 152 153 #endregion 154 155 #region Post With Pic 156 157 /// 158 /// HTTP POST方式请求数据(带图片) 159 /// 160 /// URL 161 /// POST的数据 162 /// 图片 163 /// 164 public static string HttpPost(string url, IDictionary<object, object> param, byte[] fileByte) 165 { 166 string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x"); 167 byte[] boundarybytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n"); 168 169 HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url); 170 wr.ContentType = "multipart/form-data; boundary=" + boundary; 171 wr.Method = "POST"; 172 wr.KeepAlive = true; 173 wr.Credentials = CredentialCache.DefaultCredentials; 174 175 Stream rs = wr.GetRequestStream(); 176 string responseStr = null; 177 178 string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}"; 179 foreach (string key in param.Keys) 180 { 181 rs.Write(boundarybytes, 0, boundarybytes.Length); 182 string formitem = string.Format(formdataTemplate, key, param[key]); 183 byte[] formitembytes = Encoding.UTF8.GetBytes(formitem); 184 rs.Write(formitembytes, 0, formitembytes.Length); 185 } 186 rs.Write(boundarybytes, 0, boundarybytes.Length); 187 188 string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n"; 189 string header = string.Format(headerTemplate, "pic", fileByte, "text/plain"); //image/jpeg 190 byte[] headerbytes = Encoding.UTF8.GetBytes(header); 191 rs.Write(headerbytes, 0, headerbytes.Length); 192 193 rs.Write(fileByte, 0, fileByte.Length); 194 195 byte[] trailer = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n"); 196 rs.Write(trailer, 0, trailer.Length); 197 rs.Close(); 198 199 WebResponse wresp = null; 200 try 201 { 202 wresp = wr.GetResponse(); 203 Stream stream2 = wresp.GetResponseStream(); 204 if (stream2 != null) 205 { 206 StreamReader reader2 = new StreamReader(stream2); 207 responseStr = reader2.ReadToEnd(); 208 } 209 210 // logger.Error(string.Format("File uploaded, server response is: {0}", responseStr)); 211 } 212 catch (Exception) 213 { 214 //logger.Error("Error uploading file", ex); 215 if (wresp != null) 216 { 217 wresp.Close(); 218 } 219 } 220 return responseStr; 221 } 222 223 #endregion 224 } 225 }
Models---》WeixinHelper
1 using System.Collections.Generic; 2 using System.Configuration; 3 4 using Newtonsoft.Json; 5 6 namespace WebWeChat.Models 7 { 8 public static class WeixinHelper 9 { 10 #region 获得配置信息 11 12 private static readonly string OauthAppId = ConfigurationManager.AppSettings["oauth_app_id"]; 13 private static readonly string OauthAppKey = ConfigurationManager.AppSettings["oauth_app_key"]; 14 15 #endregion 16 17 ///18 /// 根据AppID和AppSecret获得access token(默认过期时间为2小时) 19 /// 20 /// Dictionary 21 public static Dictionary<string, object> get_access_token() 22 { 23 string sendUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + 24 WeixinHelper.OauthAppId + "&secret=" + WeixinHelper.OauthAppKey + ""; 25 26 //发送并接受返回值 27 string result = HttpMethods.HttpGet(sendUrl); 28 if (result.Contains("errmsg")) 29 { 30 return null; 31 } 32 try 33 { 34 Dictionary<string, object> dic = JsonConvert.DeserializeObject string, object>>(result); 35 return dic; 36 } 37 catch 38 { 39 return null; 40 } 41 } 42 43 /// 44 /// 取得临时的Access Token(默认过期时间为2小时) 45 /// 46 /// 临时Authorization Code 47 /// 防止CSRF攻击,成功授权后回调时会原样带回 48 /// Dictionary 49 public static Dictionary<string, object> get_access_token(string code, string state) 50 { 51 string sendUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + 52 WeixinHelper.OauthAppId + "&secret=" + WeixinHelper.OauthAppKey + "&code=" + code + 53 "&grant_type=authorization_code"; 54 55 //发送并接受返回值 56 string result = HttpMethods.HttpGet(sendUrl); 57 if (result.Contains("errmsg")) 58 { 59 return null; 60 } 61 try 62 { 63 Dictionary<string, object> dic = JsonConvert.DeserializeObject string, object>>(result); 64 return dic; 65 } 66 catch 67 { 68 return null; 69 } 70 } 71 72 /// 73 /// 根据access_token判断access_token是否过期 74 /// 75 /// 76 /// true表示未失效 77 public static bool check_access_token(string accessToken) 78 { 79 string sendUrl = "https://api.weixin.qq.com/sns/auth?access_token=" + accessToken + "&openid=" + WeixinHelper.OauthAppId; 80 81 //发送并接受返回值 82 string result = HttpMethods.HttpGet(sendUrl); 83 try 84 { 85 Dictionary<string, object> dic = JsonConvert.DeserializeObject string, object>>(result); 86 if (dic.ContainsKey("errmsg")) 87 { 88 return dic["errmsg"].ToString() == "ok"; 89 } 90 return false; 91 } 92 catch 93 { 94 return false; 95 } 96 } 97 98 /// 99 /// 若fresh_token已过期则根据refresh_token取得新的refresh_token 100 /// 101 /// refresh_token 102 /// Dictionary 103 public static Dictionary<string, object> get_refresh_token(string refreshToken) 104 { 105 string sendUrl = 106 "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=" + 107 WeixinHelper.OauthAppId + "&grant_type=refresh_token&refresh_token=" + refreshToken; 108 109 //发送并接受返回值 110 string result = HttpMethods.HttpGet(sendUrl); 111 if (result.Contains("errmsg")) 112 { 113 return null; 114 } 115 try 116 { 117 return JsonConvert.DeserializeObject string, object>>(result); 118 } 119 catch 120 { 121 return null; 122 } 123 } 124 125 /// 126 /// 获取登录用户自己的基本资料 127 /// 128 /// 临时的Access Token 129 /// 用户openid 130 /// Dictionary 131 public static Dictionary<string, object> get_user_info(string accessToken, string openId) 132 { 133 //发送并接受返回值 134 string sendUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openId; 135 136 //发送并接受返回值 137 string result = HttpMethods.HttpGet(sendUrl); 138 if (result.Contains("errmsg")) 139 { 140 return null; 141 } 142 143 //反序列化JSON 144 Dictionary<string, object> dic = JsonConvert.DeserializeObject string, object>>(result); 145 return dic; 146 } 147 } 148 }
我的签名:坚持赚钱,顺便理想。