Senparc.Weixin.MP SDK 微信公衆平臺開發教程(十二):OAuth2.0說明

原文: Senparc.Weixin.MP SDK 微信公衆平臺開發教程(十二):OAuth2.0說明

  緊接上一篇《Senparc.Weixin.MP SDK 微信公衆平臺開發教程(十一):高級接口說明》,這裏專講OAuth2.0。php

理解OAuth2.0

  首先咱們經過一張圖片來了解一下OAuth2.0的運做模式:html

  從上圖咱們能夠看到,整個過程進行了2次「握手」,最終利用受權的AccessToken進行一系列的請求,相關的過程說明以下:git

  • A:由客戶端向服務器發出驗證請求,請求中通常會攜帶這些參數
    • ID標識,例如appId
    • 驗證後跳轉到的URL(redirectUrl)
    • 狀態參數(可選)
    • 受權做用域scope(可選)
    • 響應類型(可選)
  • B:服務器返回一個grant受權標識(微信默認狀況下稱之爲code),相似於一個一次性的臨時字符串密鑰。若是在A中提供了redirectUrl,這裏服務器會作一次跳轉,帶上grant和狀態參數,訪問redirectUrl。
  • C:客戶端的redirectUrl對應頁面,憑藉grant再次發起請求,此次請求一般會攜帶一些敏感信息:
    • ID標識
    • 密碼
    • grant字符串(code)
    • grant類型(可選,微信中默認爲code)
  • D:服務器驗證ID標識、密碼、grant都正確以後,返回AccessToken(注意,這裏的AccessToken和以前通用接口、高級接口介紹的AccessToken沒有關係,不能交叉使用)
  • E:客戶端憑藉AccessToken請求一系列的API,在此過程當中再也不會攜帶appId,Secret,grant等敏感的信息。
  • F:服務器返回請求結果。

微信的OAuth2.0使用

  瞭解了OAuth2.0的基本原理以後,咱們來看一下OAuth2.0在微信中是如何運用的。github

  假設一個場景:用戶進入了一個微信公衆帳號,隨後經過消息中的連接,在微信內嵌瀏覽器中打開了一個遊戲網頁,這個遊戲須要用戶登陸而且記錄用戶的遊戲得分。api

  這種狀況下咱們有兩種處理方式:瀏覽器

  1. 讓用戶在網頁中進行註冊、登陸(而且每次打開這個網頁均可能要從新進行登陸,由於微信內置瀏覽器的cookie保存時間很是短),這個固然是個很坑爹的設計。
  2. 利用OAuth2.0。在用戶進入這個頁面的時候,先判斷用戶是否登陸,若是沒有,自動跳轉到OAuth2.0受權頁面,這個頁面又自動進行了上述ABCD一系列驗證,再經過EF獲得用戶的OpenId甚至更加詳細的信息(包括頭像),自動完成登陸(或必要的註冊)過程,隨後用戶以登陸狀態直接進入遊戲。

  能夠看出,使用OAuth2.0大幅度提升了用戶體驗,而且能夠自動綁定識別用戶微信OpenId。安全

  須要注意的是,上面提到的「OAuth2.0受權頁面」還有兩種形式:服務器

  1. 當請求A中的Scope爲snsapi_base時,整個受權過程自動完成,用戶的客戶端不會有任何中間頁面顯示,可是受權的結果僅能獲取用戶的OpenId(無論用戶是否已關注,固然若是用戶是關注用戶,再次利用高級接口中的用戶信息接口,利用OpenId獲取用戶資料也是能夠的,只不過繞了幾個彎)
  2. 當請求A中的Scope爲snsapi_userinfo時,須要提供一個受權頁面(相似不少網站利用微博帳號、QQ號登錄的那種受權),僅當用戶贊成以後,當即獲取到用戶的詳細信息,這裏的用戶必須是已經關注的用戶。

  也就是說,snsapi_base的方法能夠「神不知鬼不覺」地獲取用戶OpenId,全自動完成登陸註冊過程,可是信息量有限;snsapi_userinfo須要用戶在指定界面上受權以後,自動完成整個過程,這個受權有一個時間段,超過期間後須要從新詢問用戶。微信

Senparc.Weixin.MP OAuth2.0接口

  源文件文件夾:Senparc.Weixin.MP/AdvancedAPIs/OAuthcookie

  相比其餘接口OAuth2.0略微複雜,相關內容將在下一篇專門進行介紹:Senparc.Weixin.MP SDK 微信公衆平臺開發教程(十二):OAuth2.0說明

  源代碼中相關方法以下:

namespace Senparc.Weixin.MP.AdvancedAPIs
{
    //官方文檔:http://mp.weixin.qq.com/wiki/index.php?title=%E7%BD%91%E9%A1%B5%E6%8E%88%E6%9D%83%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF#.E7.AC.AC.E4.B8.80.E6.AD.A5.EF.BC.9A.E7.94.A8.E6.88.B7.E5.90.8C.E6.84.8F.E6.8E.88.E6.9D.83.EF.BC.8C.E8.8E.B7.E5.8F.96code

    /// <summary>
    /// 應用受權做用域
    /// </summary>
    public enum OAuthScope
    {
        /// <summary>
        /// 不彈出受權頁面,直接跳轉,只能獲取用戶openid
        /// </summary>
        snsapi_base,
        /// <summary>
        /// 彈出受權頁面,可經過openid拿到暱稱、性別、所在地。而且,即便在未關注的狀況下,只要用戶受權,也能獲取其信息
        /// </summary>
        snsapi_userinfo
    }

    public static class OAuth
    {
        /// <summary>
        /// 獲取驗證地址
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="redirectUrl"></param>
        /// <param name="state"></param>
        /// <param name="scope"></param>
        /// <param name="responseType"></param>
        /// <returns></returns>
        public static string GetAuthorizeUrl(string appId, string redirectUrl, string state, OAuthScope scope, string responseType = "code")
        {
            var url =
                string.Format("https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type={2}&scope={3}&state={4}#wechat_redirect",
                                appId, redirectUrl.UrlEncode(), responseType, scope, state);

            /* 這一步發送以後,客戶會獲得受權頁面,不管贊成或拒絕,都會返回redirectUrl頁面。
             * 若是用戶贊成受權,頁面將跳轉至 redirect_uri/?code=CODE&state=STATE。這裏的code用於換取access_token(和通用接口的access_token不通用)
             * 若用戶禁止受權,則重定向後不會帶上code參數,僅會帶上state參數redirect_uri?state=STATE
             */
            return url;
        }

        /// <summary>
        /// 獲取AccessToken
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="secret"></param>
        /// <param name="code">code做爲換取access_token的票據,每次用戶受權帶上的code將不同,code只能使用一次,5分鐘未被使用自動過時。</param>
        /// <param name="grantType"></param>
        /// <returns></returns>
        public static OAuthAccessTokenResult GetAccessToken(string appId, string secret, string code, string grantType = "authorization_code")
        {
            var url =
                string.Format("https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type={3}",
                                appId, secret, code, grantType);

            return CommonJsonSend.Send<OAuthAccessTokenResult>(null, url, null, CommonJsonSendType.GET);
        }

        /// <summary>
        /// 刷新access_token(若是須要)
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="refreshToken">填寫經過access_token獲取到的refresh_token參數</param>
        /// <param name="grantType"></param>
        /// <returns></returns>
        public static OAuthAccessTokenResult RefreshToken(string appId, string refreshToken, string grantType = "refresh_token")
        {
            var url =
                string.Format("https://api.weixin.qq.com/sns/oauth2/refresh_token?appid={0}&grant_type={1}&refresh_token={2}",
                                appId, grantType, refreshToken);

            return CommonJsonSend.Send<OAuthAccessTokenResult>(null, url, null, CommonJsonSendType.GET);
        }

        public static OAuthUserInfo GetUserInfo(string accessToken,string openId)
        {
            var url = string.Format("https://api.weixin.qq.com/sns/userinfo?access_token={0}&openid={1}",accessToken,openId);
            return CommonJsonSend.Send<OAuthUserInfo>(null, url, null, CommonJsonSendType.GET);
        }
    }
}

  具體的示例方法見Senparc.Weixin.MP.Sample/Controllers/OAuth2Controller.cs,以及對應視圖的代碼。

注意點

  1. 必須是經過認證的服務號纔可使用OAuth接口。
  2. 接口中用到的AccessToken和高級接口(包括通用接口)中用到的AccessToken互不相關,即便他們都是經過相同的AppId和Secret獲得的。
  3. 目前官方的受權頁面不是100%穩定,有時候須要多點幾回才能順利經過,若是發現此類狀況,須要作一些判斷反覆請求,至少在表面上能夠不讓用戶看到錯誤頁面。
  4. 出於安全,在使用OAuth2.0以前,須要進入到微信後臺的【個人服務】對回調頁面的域名進行設置:

 

 

  系列教程索引:http://www.cnblogs.com/szw/archive/2013/05/14/weixin-course-index.html

相關文章
相關標籤/搜索