微信公衆號開發Django-JSSDK受權

上篇已經介紹過網頁受權的基本操做,在進行網頁開發的時候
也會遇到JSSDK受權的問題php

警示:此JSSDK受權可能坑比較多~
如出現各類問題,能夠到文末檢查html

部分代碼上一篇文章已經提到解釋,能夠參考
另外若是出現非官方網頁的提示,則不要在微信客戶端調試
使用微信web開發者工具就能夠了前端

獲取ticket部分

此處官方文檔明確提到用戶須要緩存jsapi_ticket
由於其api調用次數很是有限,根據文檔說明我把獲取基礎支持的acess_token和ticket寫到了一塊兒
代碼以下python

#xgc.wechat.py
app_id=os.environ.get('APP_ID')
app_secret=os.environ.get('APP_SECRET')
#基礎受權部分
base_get_access_token = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s'%(app_id,app_secret)
get_ticket = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token='

#views.py
class base_authorization():

    @classmethod
    def get_ticket(cls):
        key = 'ticket'
        if cache.has_key(key):
            ticket  = cache.get(key)
        else:
            if cache.has_key('access_token'):
                access_token = cache.get('access_token')
            else:
                access_token = cls.get_access_token()
            from xgc.wechat import get_ticket
            ticket = requests.get(get_ticket+access_token).json()['ticket']
            cache.set(key,ticket,110*60)
        return ticket

    @staticmethod
    def get_access_token():
        from xgc.wechat import base_get_access_token
        key = 'access_token'
        access_token = requests.get(base_get_access_token).json()['access_token']
        cache.set(key,access_token,110*60)
        return access_token

signature生成

首先咱們signature生成須要一下幾個參數noncestr(隨機字符串), 有效的jsapi_ticket, timestamp(時間戳), url(當前網頁的URL,不包含#及其後面部分)
其中官方提供了signature生成的python例子,以下的signature類,其中jsapi_ticket取自上方的ticketgit

class signature(View):

    def __init__(self,url):
        self.ret = {
            'nonceStr': self.__create_nonce_str(),
            'jsapi_ticket': base_authorization.get_ticket(),
            'timestamp': self.__create_timestamp(),
            'url': url
        }

    def __create_nonce_str(self):
        return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(15))

    def __create_timestamp(self):
        return int(time.time())

    def sign(self):
        string = '&'.join(['%s=%s' % (key.lower(), self.ret[key]) for key in sorted(self.ret)]).encode('utf-8')
        self.ret['signature'] = hashlib.sha1(string).hexdigest()
        return self.ret

wx接口驗證

# urls.py
url(r'^activity', views.activity.as_view(), name='activity'),

# views.py
class activity(View):

    def get(self, request):
        return render(request, 'activaty.html')

    def post(self,request,*args, **kwargs):
        request_type = request.POST.get('type')
        if not request_type:
            request_body = json.loads(request.body.decode())
            pathname = request_body['url']
            sign = signature(unquote(pathname))
            sign = json.dumps(sign.sign())
            return HttpResponse(sign, content_type="application/json")
        elif request_type == 'image/jpeg':
            pass #傳圖片的時候會用到

首先咱們先設置和前端進行交互的路由,而後咱們利用下面的js進行wx初始配置web

function csrfSafeMethod(method) {
        // these HTTP methods do not require CSRF protection
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }

    $.ajaxSetup({
        beforeSend: function (xhr, settings) {
            if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                xhr.setRequestHeader("X-CSRFToken", '{{ csrf_token }}');
            }
        },
    });
    //上方爲Django-Ajax-CSRF設置

    let wxStatus = 0

    $(document).ready(function () {
        $.ajax({
            type: 'POST',
            url: "http://test.flywinky.top/activity", // class activity設置的連接
            data: JSON.stringify({ 'url': encodeURIComponent(location.href.split('#')[0]) }),
            headers: { 'Content-Type': 'application/json' },
            success: function (res) {
                wx.config({
                    debug: false,
                    appId: 'wx4f35679866a1b3a6',
                    timestamp: res['timestamp'],
                    nonceStr: res['nonceStr'],
                    signature: res['signature'],
                    jsApiList: ['chooseImage', 'uploadImage']
                })
            }
        });
        wx.ready(function () {
            wxStatus = 1
        })
        wx.error(function (res) {
            wxStatus = 2
        })

正常的狀況以下圖
ajax

而後就能夠調用官方的各個接口了,只要你有相應的權限
接口列表在網頁下方算法

Django-Ajax-CSRF

Django默認開啓了CSRF驗證
在進行Ajax請求POST的時候須要注意csrf_token的設置
官網文檔這樣寫的
也能夠按照我上方的代碼,在html裏django

{% load static %}
{{ csrf_token }} //就能夠直接這樣引入了

各類問題

首先推薦一篇帖子微信公衆平臺, config:invalid signature一直爆這個錯誤,求教如何解決?json

官網文檔總結:

invalid signature簽名錯誤。建議按以下順序檢查:

  • 確認簽名算法正確,可用http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 頁面工具進行校驗。
  • 確認config中nonceStr(js中駝峯標準大寫S), timestamp與用以簽名中的對應noncestr, timestamp一致。
  • 確認url是頁面完整的url(請在當前頁面alert(location.href.split('#')[0])確認),包括'http(s)://'部分,以及'?'後面的GET參數部分,但不包括'#'hash後面的部分。
  • 確認 config 中的 appid 與用來獲取 jsapi_ticket 的 appid 一致。
  • 確保必定緩存access_token和jsapi_ticket。
  • 確保你獲取用來簽名的url是動態獲取的,動態頁面可參見實例代碼中php的實現方式。若是是html的靜態頁面在前端經過ajax將url傳到後臺簽名,前端須要用js獲取當前頁面除去'#'hash部分的連接(可用location.href.split('#')[0]獲取,並且須要encodeURIComponent),由於頁面一旦分享,微信客戶端會在你的連接末尾加入其它參數,若是不是動態獲取當前連接,將致使分享後的頁面簽名失敗。

還有:

  • 獲取微信的jsapi_ticket有兩個URL地址,一個是:https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=wx_card
    另一個是:https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=jsapi
    第一個微信卡券的地址,應該是用第二個地址。
  • 此處的access_token爲基礎支持的access_token,和網頁受權的不一樣
  • url在JavaScript中千萬別忘記「encodeURIComponent」!不然後果很詭異,遇到過初始化的時候報invalid signature,可是API接口又能調用的狀況。
相關文章
相關標籤/搜索