2010-07-21 12 views
16

Para Facebook FBML Aplicaciones Facebook es el envío de un parámetro signed_request se explica aquí:Cómo decodificar url base64 en python?

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

Han dado la versión PHP de decodificar esta firmado solicitud:

http://pastie.org/1054154

Cómo hacer el lo mismo en Python?

Probé módulo de base 64 pero estoy consiguiendo error de relleno incorrecta:

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

gracias base 64 que probamos, pero estoy recibiendo este error: http://pastie.org/1054201 – kevin

+0

Por favor enviar el código en realidad más pequeña que muestra el error y el error real. La mayoría de nosotros no tenemos la paciencia para seguir enlaces por todo el lugar. –

+0

código y error agregado. – kevin

Respuesta

20

Al parecer, se ha perdido los dos últimos caracteres al copiar la cadena original codificado en base 64. Sufija la cadena de entrada con dos signos is-equal (=) y se decodificará correctamente.

+1

Geert, gracias por esto. pero ese es exactamente el código que obtuve de Facebook y que no tuvo = al final. es esto esperado? – kevin

+2

Esto no es de esperar, diría yo. Sin embargo, puede verificar la longitud de la entrada base64 comprobando la longitud de la misma: la longitud siempre debe ser un múltiplo de 4 bytes (esta es en realidad la razón por la cual el decodificador arrojó un error). Si no es así, puede agregar signos iguales hasta que esté y luego la cadena se decodificará correctamente. – Geert

+2

Parece que '=' el relleno no siempre se requiere en todas las variantes: http://en.wikipedia.org/wiki/Base64 –

22

he compartido un fragmento de código para analizar signed_request parámetro en una aplicación de lona facebook basado pitón en 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

funciona bien, buena! – Anentropic

+0

La solución de dae.eklen hace lo mismo y es más elegante. ('base64.urlsafe_b64decode (s + '=' * (4 - len (s)% 4))') – sax

+1

Gracias. Es un fragmento de código bastante corto: sería genial verlo incluido en esta respuesta. – 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

tratar

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

como está escrito here

+2

Asegúrate de que la cadena con la que trabajas es instancia de str - Unicode fallará con error. Si ese es su caso, use la función 'str (s)' para la conversión. – sax

5

Alternativa a @dae La solución de .eklen, puede anexar === a ella:

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

Esto funciona porque Python sólo se queja de falta de relleno, pero no carnes de más.

+0

Ok, esto tiene sentido y funciona con tu ejemplo. Sin embargo, estoy confundido, tengo una cadena de un múltiplo de longitud de 4 sin relleno que devuelve el error de relleno incorrecto, cuando tenía un '=', todavía tengo el mismo problema, pero si tenía al menos '==' funciona. ¿Que pasa con eso? – guival

1

Sorprendente, pero la respuesta actualmente aceptada no es exactamente correcta. Como algunas otras respuestas indicadas, es algo llamado codificación base64url, y es parte de RFC7515.

Básicamente, reemplazaron los caracteres '+' y '/' por '-' y '_' respectivamente; y además quitó cualquier carácter '=' posterior, porque siempre puedes decir cuántos caracteres te faltan, simplemente mirando la longitud de la cadena codificada.

Aquí es ejemplo ilustrativo de 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 
} 
Cuestiones relacionadas