在微信公眾帳號中進行OAuth授權登陸


微信內收藏文章

假設有微信用戶A君,訂閱了公眾帳號“小道消息”(微信號DbaNotes),每天收到一篇文章推送。A君有時希望能把文章收藏起來,可以稍后閱讀或者反復欣賞。當然,可以有千百種方法來完成收藏這個事,A君是個微信腦殘粉,希望整個收藏過程僅在微信內即可完成。

印象筆記的微信公眾號“我的印象筆記”是基於微信的私有API開發的,可以把消息、文章的轉存為筆記。使用該帳號的基本的步驟是:關注“我的印象筆記”,其會提示用戶綁定印象筆記的帳戶,並發送OAuth授權登陸鏈接,點擊鏈接到印象筆記網站登陸,完成后,給“我的印象筆記”發送的內容會保存為筆記。使用微信內置Web頁面打開文章后,點擊分享按鈕,“我的印象筆記”已經內置其中,可以一鍵保存文章。總體上,“我的印象筆記”是很方便的。如果A君是印象筆記的用戶(注意,Evernote的國際帳號是無法使用的),那么A君有福了。可惜A君是Evernote用戶,而且也不太習慣在Evernote內閱讀文章。

A君是Pocket的忠實粉絲,平時在網上閑逛,遇到有意思的文章,會保存到Pocket閱讀列表,在PC上這個很簡單。A君希望能有一個類似“我的印象筆記”的公眾帳號,綁定自己的Pocket帳戶,通過發送文章鏈接的消息給該帳號,將文章添加至Pocket列表。

我們假設這個公眾帳號叫MyPocket,下面重點敘述,如何將用戶的Pocket帳戶OAuth授權給MyPocket。

節點

在整個的授權登陸過程中,涉及到的節點主要有下面四個:

節點1:微信用戶。例如A君。

節點2:公眾號消息服務器。用戶可見的是公眾帳號,例如MyPocket。

節點3:微信服務器。微信官方服務器,完成1和2之間的消息傳遞。

節點4:Pocket授權登陸服務器,Pocket應用自身的登陸服務器或頁面。

文本消息傳遞步驟

微信用戶節點1發送一條文本消息給公眾號節點2,並得到公眾帳號的回應,消息傳遞的過程如下:

(1),微信用戶節點1發送消息

(2),消息到達節點3,對消息進行封裝通過HTTP POST推送給節點2

(3),消息到達節點2,處理后對HTTP進行響應,返回給節點3,轉發給節點1

(4),消息到達節點1,微信用戶接收到消息回應

注意,目前節點2是無法主動發送消息給用戶的,僅能在收到節點3的消息推送后,進行消息回復。

OAuth授權登陸步驟

和普通的在瀏覽器中完成的OAuth授權登陸有所不同,在微信中OAuth登陸的基本步驟是:

1,微信用戶節點1發送特定表識消息(例如“auth”)開始OAuth授權登陸

2,節點2收到消息后:

(1)記住節點1的標識串FromUserName,需要保存
(2)到節點4獲取request token,需要保存
(3)給節點1消息回復:用戶授權登陸的地址鏈接,地址鏈接中需要包含:用戶表識串FromUserName和授權完成后的回調(callback)地址

3,節點1打開登陸鏈接,微信內置瀏覽器中填寫帳戶,進行授權

4,節點4重定向至節點2的callback地址

5,節點2處理授權登陸callback,根據request token獲取access token,授權完成,需要保存access token。

下面是對該過程的幾點說明:

(1)消息推送中所攜帶的用戶相關信息只有FromUserName,是一個加密后的字符串,形如oGfS0jrOSOwJXqNTIy9B8WI8sEac。因此直接獲取用戶的微信號或者昵稱存在困難。據從網上查詢到的信息看,一個微信用戶發送給某特定的公眾帳號的所有消息,該FromUserName是固定的。可用來唯一標識節點1。

(2)步驟2中的FromUserName、request token和步驟5的access token都需要保存。因為節點2會和節點3,以及節點1的瀏覽器發生HTTP交互,無法使用瀏覽器cookie,此處使用數據庫進行保存操作。

(3)瀏覽器支持。因為OAuth登陸,其中一個步驟要到第三方的登陸授權界面進行登陸,需要用到瀏覽器,微信內置的瀏覽器,可以完美完成此任務。

代碼

本例采用python的flask框架實現了一個小例子,主要的代碼整理如下。授權登陸的步驟2代碼:

@app.route('/weixin', methods=['POST'])
def weixin_msg():
    data = request.data
    msg = parse_msg(data)
    content = msg['Content']
    username = msg['FromUserName']
    if content == 'auth':
        pocket = Pocket(POCKET_CONSUMER_KEY, BASE_URL + url_for('auth_callback') + '?username=' + username)
        code = pocket.get_request_token() #code即為request token
        url = pocket.get_authorize_url(code)
        #保存code和username
        user = User(username)
        user.pocket_code = code
        db.session.add(user)
        db.session.commit()
        rmsg = u'點擊下面鏈接登陸Pocket並授權給給我\n\n' + rmsg.encode('utf-8')
        return response_text_msg(msg, rmsg)
    return help_msg()

步驟2返回的認證地址Authorize Url,是通過微信消息回復給節點1的,由節點1手動點擊鏈接打開,此處無法使用cookie,本例采用數據庫保存session數據。其中BASE_URL + url_for('auth_callback') + '?username=' + username為重定向地址,節點4確認授權以后,重定向至節點2的,新增了"username"參數,可以理解為session id。

步驟5代碼:

@app.route('/auth_callback')
def auth_callback():
    username = request.args.get('username')
    user = User.query.filter_by(username=username).first()
    pocket = Pocket(POCKET_CONSUMER_KEY)
    resp = pocket.get_access_token(user.pocket_code)
    user.pocket_token = resp['access_token']
    user.pocket_username = resp['username']
    db.session.commit()
    return '<html><head></head><body><h1>認證成功,發送文章鏈接給MyPocket,即可保存到Pocket閱讀列表。</h1></body></html>'

 授權完成后,用戶直接發送文章鏈接,節點2匹配到Url地址,即添加到Pocket列表:

def add_item_to_pocket(username, content):
    r = r"(http://[^ ]+)"
    urls = re.findall(r, content)
    rmsg = u''
    user = User.query.filter_by(username=username).first()
    pocket = Pocket(POCKET_CONSUMER_KEY)
    pocket.set_access_token(user.pocket_token)
    for url in urls:
        itemjson = pocket.add(url=url)
        item = json.dumps(itemjson)
        rmsg += u'已添加"%s"至Pocket\n' % item['title']
    return rmsg

用法

A君想要收藏小道君發送的文章“「大概8點20分發」”,在微信中點擊推送消息,內置瀏覽器打開文章,點擊右上角的分享按鈕,點選“復制鏈接”,打開MyPocket,粘貼,發送的鏈接如下:

http://mp.weixin.qq.com/mp/appmsg/show?__biz=MjM5ODIyMTE0MA==&appmsgid=10000250&itemidx=1#wechat_redirect

這樣,A君就可以在3月17日的早晨大概8點20分在Pocket中欣賞這篇好文了。你不妨也試試看:

image

資源

1,Pocket API的python sdk

2,在SAE上搭建微信公眾帳號消息服務器


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM