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

SZW發表於2014-06-02

  緊接上一篇《Senparc.Weixin.MP SDK 微信公眾平臺開發教程(十一):高階介面說明》,這裡專講OAuth2.0。

理解OAuth2.0

  首先我們通過一張圖片來了解一下OAuth2.0的運作模式:

  從上圖我們可以看到,整個過程進行了2次“握手”,最終利用授權的AccessToken進行一系列的請求,相關的過程說明如下:

  • 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在微信中是如何運用的。

  假設一個場景:使用者進入了一個微信公眾賬號,隨後通過訊息中的連結,在微信內嵌瀏覽器中開啟了一個遊戲網頁,這個遊戲需要使用者登入並且記錄使用者的遊戲得分。

  這種情況下我們有兩種處理方式:

  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/OAuth

  原始碼中相關方法如下:

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

  1. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(一):微信公眾平臺註冊
  2. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(二):成為開發者
  3. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(三):微信公眾平臺開發驗證
  4. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(四):Hello World
  5. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(五):使用Senparc.Weixin.MP SDK
  6. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(六):瞭解MessageHandler
  7. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(七):解決使用者上下文(Session)問題
  8. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(八):通用介面說明
  9. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(九):自定義選單介面說明
  10. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(十):多客服介面說明
  11. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(十一):高階介面說明
  12. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(十二):OAuth2.0說明
  13. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(十三):地圖相關介面說明
  14. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(十四):請求訊息去重
  15. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(十五):訊息加密
  16. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(十六):AccessToken自動管理機制
  17. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(十七):個性化選單介面說明
  18. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(十八):Web代理功能
  19. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(十九):MessageHandler 的未知型別訊息處理
  20. Senparc.Weixin.MP SDK 微信公眾平臺開發教程(二十):使用選單訊息功能

 

相關文章