C#微信公衆平臺開發一網頁受權前端
在開發公衆號時常常會遇到有些功能須要用戶登陸後才能使用,咱們本身編寫的程序或許有自帶登陸頁面,但用戶每次都要輸入帳號密碼非常麻煩,因此考慮可否用微信帳號受權登陸,這樣只要受權過了,除非受權過時,不然都不須要從新登陸,接下來咱們來研究如何完成受權操做。web
1、爲了實現網頁受權功能,須要解決的問題api
一、微信網頁受權是經過在微信客戶端調用受權接口,用戶贊成受權後微信調用咱們指定的回調函數進行後續業務操做,在這裏比較特殊的是回調函數必須是在某個域名下,因此開發者須要先到公衆平臺官網中的「開發 - 接口權限 - 網頁服務 - 網頁賬號 - 網頁受權獲取用戶基本信息」的配置選項中,修改受權回調域名。安全
二、經過開發者ID及密碼調用獲取access_token接口時,須要設置訪問來源IP(上述域名所在服務器的外網IP地址)爲白名單,可在 開發 -> 基本配置 -> 公衆號開發信息 -> IP白名單 進行設置。服務器
2、實現步驟微信
1 第一步:用戶贊成受權,獲取codeapp
在確保微信公衆帳號擁有受權做用域(scope參數)的權限的前提下(服務號得到高級接口後,默認擁有scope參數中的snsapi_base和snsapi_userinfo),引導關注者打開以下頁面,能夠經過微信客戶端打開或使用微信web開發者工具打開:微信公衆平臺
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect 若提示「該連接沒法訪問」,請檢查參數是否填寫錯誤,是否擁有scope參數對應的受權做用域權限。
尤爲注意:因爲受權操做安全等級較高,因此在發起受權請求時,微信會對受權連接作正則強匹配校驗,若是連接的參數順序不對,受權頁面將沒法正常訪問函數
參考實例(微信web開發者工具)工具
參數說明
參數 | 是否必須 | 說明 |
---|---|---|
appid | 是 | 公衆號的惟一標識(能夠點開 開發-> 基本配置 查看) |
redirect_uri | 是 | 受權後重定向的回調連接地址, 請使用 urlEncode 對連接進行處理(前面已經說過,咱們的回調函數需部署到域名下,這裏的地址就回調函數的地址) |
response_type | 是 | 返回類型,請填寫code |
scope | 是 | 應用受權做用域,snsapi_base (不彈出受權頁面,直接跳轉,只能獲取用戶openid),snsapi_userinfo (彈出受權頁面,可經過openid拿到暱稱、性別、所在地。而且, 即便在未關注的狀況下,只要用戶受權,也能獲取其信息 ) |
state | 否 | 重定向後會帶上state參數,開發者能夠填寫a-zA-Z0-9的參數值,最多128字節 |
#wechat_redirect | 是 | 不管直接打開仍是作頁面302重定向時候,必須帶此參數 |
2 第二步:經過code換取網頁受權access_token
HttpWebRequest 請求方法
/// <summary> /// postweb請求 /// </summary> /// <param name="postUrl"></param> /// <param name="paramData"></param> /// <param name="dataEncode"></param> /// <returns></returns> public static string PostWebRequest(string postUrl, string paramData) { string ret = string.Empty; try { byte[] byteArray = Encoding.UTF8.GetBytes(paramData); HttpWebRequest webReq = WebRequest.Create(postUrl) as HttpWebRequest; webReq.Method = "GET"; HttpWebResponse response = (HttpWebResponse)webReq.GetResponse(); StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8); ret = sr.ReadToEnd(); sr.Close(); response.Close(); } catch (Exception ex) { throw ex; } return ret; }
調用微信接口獲取access_token信息
public Dictionary<string, object> get_access_token(string code) { JavaScriptSerializer Jss = new JavaScriptSerializer(); string url = string.Format("https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code", "AppID", "AppSecret", code); Dictionary<string, object> respDic = (Dictionary<string, object>)Jss.DeserializeObject(PostWebRequest(url, "")); return respDic; }
3 第三步:刷新access_token(若是須要)
因爲access_token有,涉及access_token的獲取access_token的接口是有次數限制的,因此我推薦你們作一個全局變量存儲,定時刷新,請參考《C#微信公衆平臺開發—access_token的獲取存儲與更新》
4 第四步:拉取用戶信息(需scope爲 snsapi_userinfo)
根據第二步獲取到的access_token調用微信接口獲取用戶信息
/// <summary> /// 用openid換取用戶信息 /// </summary> /// <param name="openid">微信標識id</param> /// <returns></returns> public Dictionary<string, object> GetUserInfo(string code) { JavaScriptSerializer Jss = new JavaScriptSerializer(); Dictionary<string, object> access_info = get_access_token(code);//獲取access_token string url = string.Format("https://api.weixin.qq.com/sns/userinfo?access_token={0}&openid={1}&lang=zh_CN", access_info["access_token"], access_info["openid"]); Dictionary<string, object> respDic = (Dictionary<string, object>)Jss.DeserializeObject(PostWebRequest(url, "")); return respDic; }
5 第五步:將上述獲取的用戶信息展現到客戶端上
在受權回調函數中完成相關業務
/// <summary> /// 受權回調函數 /// </summary> /// <returns></returns> public ActionResult Index() { try { var code = Request.QueryString["code"]; //獲取回調返回的code if (!string.IsNullOrEmpty(code)) { Dictionary<string, object> DicJson = GetUserInfo(code.ToString()); //獲取用戶信息 ViewBag.nickname = DicJson["nickname"]; ViewBag.openid = DicJson["openid"]; ViewBag.province = DicJson["province"]; ViewBag.city = DicJson["city"]; ViewBag.country = DicJson["country"]; switch (DicJson["sex"].ToString()) { case "1":ViewBag.sex = "男";break; case "2": ViewBag.sex = "女"; break; default: ViewBag.sex = "未知"; break; } ViewBag.Error = "獲取用戶信息成功"; } else { ViewBag.nickname = ""; ViewBag.openid = ""; ViewBag.province = ""; ViewBag.city = ""; ViewBag.unionid = ""; ViewBag.code = ""; ViewBag.Error = "code沒找到!"; } } catch (Exception ex) { ViewBag.nickname = ""; ViewBag.openid = ""; ViewBag.province = ""; ViewBag.city = ""; ViewBag.unionid = ""; ViewBag.Error = ex.Message; } return View(); }
前端代碼參考(這裏主要是爲了測試,因此沒有細調樣式,你們湊合着看)
@{ ViewBag.Title = "Home Page"; } <div class="jumbotron"> <h1>獲取用戶信息</h1> </div> <div class="row"> <div class="col-md-4"> <h2>用戶名</h2> <p>@ViewBag.nickname</p> </div> <div class="col-md-4"> <h2>OpenID</h2> <p>@ViewBag.openid</p> </div> <div class="col-md-4"> <h2>性別</h2> <p>@ViewBag.sex</p> </div> </div> <div class="row"> <div class="col-md-4"> <h2>國家</h2> <p>@ViewBag.country</p> </div> <div class="col-md-4"> <h2>省份</h2> <p>@ViewBag.province</p> </div> <div class="col-md-4"> <h2>城市</h2> <p>@ViewBag.city</p> </div> </div> <div class="row"> <div class="col-md-12"> <h2>錯誤信息</h2> <p>@ViewBag.Error</p> </div> </div>