2010-07-21 24 views
16

Per Facebook FBML App Facebook sta inviando in un parametro signed_request spiegato qui:Come decodificare l'URL base64 in python?

http://developers.facebook.com/docs/authentication/canvas

Hanno dato la versione di PHP di decodificare questa richiesta firmata:

http://pastie.org/1054154

Come fare il lo stesso in Python?

ho provato modulo di base 64, ma io sono sempre errato errore padding:

>>> base64.urlsafe_b64decode("eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOjEyNzk3NDYwMDAsIm9hdXRoX3Rva2VuIjoiMjk1NjY2Njk1MDY0fDIuRXpwem5IRVhZWkJVZmhGQ2l4ZzYzUV9fLjM2MDAuMTI3OTc0NjAwMC0xMDAwMDA0ODMyNzI5MjN8LXJ6U1pnRVBJTktaYnJnX1VNUUNhRzlNdEY4LiIsInVzZXJfaWQiOiIxMDAwMDA0ODMyNzI5MjMifQ") 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/base64.py", line 112, in urlsafe_b64decode 
    return b64decode(s, '-_') 
    File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/base64.py", line 76, in b64decode 
    raise TypeError(msg) 
TypeError: Incorrect padding 
+0

grazie ho provato Base64, ma sto ottenendo questo errore: http://pastie.org/1054201 – kevin

+0

prega in realtà inviare il codice più piccolo che mostra l'errore e l'errore reale. Molti di noi non hanno la pazienza di seguire i link dappertutto. Codice –

+0

e errore aggiunto. – kevin

risposta

20

A quanto pare vi siete persi gli ultimi due caratteri quando si copia la stringa con codifica Base64 originale. Suffix la stringa di input con due is-equal (=) segni e sarà decodificato correttamente.

+1

Geert, grazie per questo. ma questo è esattamente il codice che ho ricevuto da facebook e che non aveva = alla fine. è previsto? – kevin

+2

Questo non è previsto, direi. Tuttavia, è possibile verificare la lunghezza dell'ingresso base64 controllandone la lunghezza: la lunghezza deve sempre essere un multiplo di 4 byte (questo è in realtà il motivo per cui il decodificatore ha generato un errore). Se non lo è, puoi aggiungere is-equal signs fino a quando non lo è e quindi la stringa verrà decodificata correttamente. – Geert

+2

Sembra che '=' il riempimento non è sempre richiesto in tutte le varianti: http://en.wikipedia.org/wiki/Base64 –

22

ho condiviso un frammento di codice per il parsing signed_request parametro in un'applicazione di tela facebook pitone con sede presso http://sunilarora.org/parsing-signedrequest-parameter-in-python-bas:

import base64 
import hashlib 
import hmac 
import simplejson as json 

def base64_url_decode(inp): 
    padding_factor = (4 - len(inp) % 4) % 4 
    inp += "="*padding_factor 
    return base64.b64decode(unicode(inp).translate(dict(zip(map(ord, u'-_'), u'+/')))) 

def parse_signed_request(signed_request, secret): 

    l = signed_request.split('.', 2) 
    encoded_sig = l[0] 
    payload = l[1] 

    sig = base64_url_decode(encoded_sig) 
    data = json.loads(base64_url_decode(payload)) 

    if data.get('algorithm').upper() != 'HMAC-SHA256': 
     log.error('Unknown algorithm') 
     return None 
    else: 
     expected_sig = hmac.new(secret, msg=payload, digestmod=hashlib.sha256).digest() 

    if sig != expected_sig: 
     return None 
    else: 
     log.debug('valid signed request received..') 
return data 
+0

funziona bene, bello! – Anentropic

+0

La soluzione di dae.eklen fa lo stesso ed è più elegante. ('base64.urlsafe_b64decode (s + '=' * (4 - len (s)% 4))') – sax

+1

Grazie. Questo è uno snippet di codice piuttosto breve, sarebbe bello vederlo incluso in questa risposta. – dgel

1
import base64 
import simplejson as json 

def parse_signed_request(signed_request): 
    encoded_sig, payload = signed_request.split('.',2) 
    data = json.loads(base64.b64decode(payload.replace('-_', '+/'))) 
    return data 
20

provare

s = 'iEPX-SQWIR3p67lj_0zigSWTKHg' 
base64.urlsafe_b64decode(s + '=' * (4 - len(s) % 4)) 

come è scritto here

+2

Assicurati che la stringa con cui lavori sia istanza di str-unicode che fallirebbe con errore. Se questo è il tuo caso usa la funzione 'str (s)' per la conversione. – sax

5

Alternativa a @dae La soluzione di .eklen, è possibile aggiungere === ad esso:

s = 'iEPX-SQWIR3p67lj_0zigSWTKHg' 
base64.urlsafe_b64decode(s + '===') 

Questo funziona perché Python si lamenta solo di imbottitura mancante, ma non chilo in più.

+0

Ok, questo ha senso e funziona con il tuo esempio. Sono confuso però, ho una stringa di un multiplo di lunghezza di 4 senza padding che restituisce l'errore di padding errato, quando ho avuto un '=', ho ancora lo stesso problema, ma se avessi almeno '==' Funziona. Cosa succede con quello? – guival

1

Sorprendente, ma la risposta attualmente accettata non è esattamente corretta. Come alcune altre risposte dichiarate, è una cosa chiamata codifica base64url, ed è una parte di RFC7515.

In sostanza, hanno sostituito '+' e '/' caratteri rispettivamente di '-' e '_'; e inoltre rimosso qualsiasi carattere "=" finale, perché puoi sempre sapere quanti caratteri ti mancano, semplicemente osservando la lunghezza della stringa codificata.

Ecco esempio illustrativo da RFC7515:

static string base64urlencode(byte [] arg) 
{ 
    string s = Convert.ToBase64String(arg); // Regular base64 encoder 
    s = s.Split('=')[0]; // Remove any trailing '='s 
    s = s.Replace('+', '-'); // 62nd char of encoding 
    s = s.Replace('/', '_'); // 63rd char of encoding 
    return s; 
} 

static byte [] base64urldecode(string arg) 
{ 
    string s = arg; 
    s = s.Replace('-', '+'); // 62nd char of encoding 
    s = s.Replace('_', '/'); // 63rd char of encoding 
    switch (s.Length % 4) // Pad with trailing '='s 
    { 
    case 0: break; // No pad chars in this case 
    case 2: s += "=="; break; // Two pad chars 
    case 3: s += "="; break; // One pad char 
    default: throw new System.Exception(
     "Illegal base64url string!"); 
    } 
    return Convert.FromBase64String(s); // Standard base64 decoder 
} 
Problemi correlati