2010-07-21 12 views
16

Dla Facebook fbml Aplikacji Facebook wysyła w parametrze signed_request wyjaśnione tutaj:Jak rozszyfrować adres URL base64 w pythonie?

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

Dały wersję php dekodowania ten podpisał wniosek:

http://pastie.org/1054154

Jak zrobić to samo w python?

Próbowałem moduł base64 ale jestem coraz Nieprawidłowy błąd 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

dzięki Próbowałem base64, ale otrzymuję ten błąd: http://pastie.org/1054201 – kevin

+0

Proszę faktycznie rozpoczynać najmniejszą kodu, który pokazuje błąd i rzeczywisty błąd. Większość z nas nie ma osób, które mogłyby śledzić linki w różnych miejscach. –

+0

dodano kod i błąd. – kevin

Odpowiedz

20

Najwyraźniej przegapiłeś ostatnie dwa znaki podczas kopiowania oryginalnego base64 zakodowany ciąg. Popraw ciąg znaków wejściowych za pomocą dwóch znaków równości (=) i zostanie poprawnie zdekodowany.

+1

Geert, dzięki za to. ale to jest właśnie kod, który dostałem z Facebooka i na końcu nie miałam. czy to jest oczekiwane? – kevin

+2

Tego nie można się spodziewać. Można jednak sprawdzić długość wejścia base64, sprawdzając jego długość: długość musi zawsze być wielokrotnością 4 bajtów (w rzeczywistości jest to powód, dla którego dekoder zgłosił błąd). Jeśli tak nie jest, możesz dodać znaki równe sobie, aż do momentu, w którym ciąg znaków zostanie poprawnie zdekodowany. – Geert

+2

Wygląda na to, że "padding" nie zawsze jest wymagany we wszystkich wariantach: http://en.wikipedia.org/wiki/Base64 –

22

Mam wspólny fragment kodu do analizowania signed_request parametru w aplikacji płótnie facebook Pythona oparte na 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

działa dobrze, fajnie! – Anentropic

+0

Rozwiązanie autorstwa dae.eklen robi to samo i jest bardziej eleganckie. ('base64.urlsafe_b64decode (s + '=' * (4 - len (s)% 4))') – sax

+1

Dzięki. To dość krótki fragment kodu - dobrze byłoby zobaczyć, że zawiera się w tej odpowiedzi. – 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

spróbować

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

jak jest napisane here

+2

Upewnij się, że ciąg znaków, z którym pracujesz, jest instancją str - unicode, która zawiedzie z błędem. Jeśli tak jest w twoim przypadku użyj funkcji 'str (s)' do konwersji. – sax

5

Alternatywa dla @dae Rozwiązanie .eklen, można dołączyć do niego ===:

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

To działa, ponieważ Python narzeka tylko o brak wyściółkę, ale nie zaokrąglona.

+0

OK, to ma sens i działa z twoim przykładem. Jestem jednak zdezorientowany, mam ciąg wielokrotności długości 4 bez dopełnienia zwracającego nieprawidłowy błąd wypełnienia, gdy miałem '=', wciąż mam ten sam problem, ale gdybym miał co najmniej '==' to działa. Co z tym? – guival

1

Zaskakująca, ale obecnie zaakceptowana odpowiedź nie jest dokładnie poprawna. Podobnie jak w niektórych innych odpowiedziach, jest to coś, co nazywa się kodowaniem base64url i jest częścią RFC7515.

Zasadniczo zamieniły one znaki "+" i "/" odpowiednio na "-" i "_"; i dodatkowo usunięto wszelkie znaki końcowe = =, ponieważ zawsze możesz określić, ilu znaków tracisz, po prostu patrząc na zakodowaną długość ciągu znaków.

Oto przykład ilustracyjny z 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 
}