简体   繁体   English

如何在 python 中解码 base64 url?

[英]How to decode base64 url in python?

For Facebook fbml Apps Facebook is sending in a signed_request parameter explained here:对于 Facebook fbml 应用程序 Facebook 正在发送此处解释的签名请求参数:

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

They have given the php version of decoding this signed request:他们给出了解码此签名请求的 php 版本:

http://pastie.org/1054154 http://pastie.org/1054154

How to do the same in python?如何在 python 中做同样的事情?

I tried base64 module but I am getting Incorrect padding error:我尝试了 base64 模块,但我收到了不正确的填充错误:

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

I have shared a code snippet for parsing signed_request parameter in a python based facebook canvas application at http://sunilarora.org/parsing-signedrequest-parameter-in-python-bas : 我在http://sunilarora.org/parsing-signedrequest-parameter-in-python-bas中共享了一个基于Python的Facebook canvas应用程序中的signed_request参数解析代码段:

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

try 尝试

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

as it is written here 正如写在这里

Apparently you missed the last two characters when copying the original base64-encoded string. 显然,在复制原始的base64编码的字符串时,您错过了最后两个字符。 Suffix the input string with two is-equal (=) signs and it will be decoded correctly. 给输入字符串加上两个等号(=)后缀,它将被正确解码。

Alternative to @dae.eklen's solution, you can append === to it: 替代@ dae.eklen解决方案,您可以在其后附加===

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

This works because Python only complains about missing padding, but not extra padding. 之所以有效,是因为Python仅抱怨缺少填充,而没有抱怨多余的填充。

Surprising, but currently accepted answer is not exactly correct. 令人惊讶,但目前接受的答案并不完全正确。 Like some other answers stated, it's something called base64url encoding, and it's a part of RFC7515 . 像其他一些答案一样,它称为base64url编码,它是RFC7515的一部分。

Basically, they replaced '+' and '/' chars by '-' and '_' respectively; 基本上,它们分别用'-'和'_'替换'+'和'/'字符; and additionally removed any trailing '=' chars, because you can always tell how many chars you're missing, just by looking at the encoded string length. 并另外删除了所有结尾的'='字符,因为您始终可以通过查看编码的字符串长度来知道缺少了多少个字符。

Here's illustrative example from RFC7515 in C#: 这是C#中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
 }
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

This is the right solution. 这是正确的解决方案。 In python there is base64.b64encode but that only base64 encodes and its is different from base64 url encoding. 在python中,有base64.b64encode,但只有base64编码,它与base64 url​​编码不同。 Here is the right set to of steps to convert form base64encoded to base64urlencoded string: 这是将base64encoded格式转换为base64urlencoded字符串的步骤的正确设置:
1. From the resultant string, replace "/" with "_" and "+" with "-" 1.从结果字符串中,将“ /”替换为“ _”,将“ +”替换为“-”
2. Strip the trailing "==". 2.删除尾随的“ ==”。

Et voila! 瞧! That will make it a valid string for base64 url decoding. 这将使其成为base64 url​​解码的有效字符串。 Btw, that link in @dae.eklen 's answer above is broken now. 顺便说一句,@ dae.eklen在上面的答案中的链接现在已断开。

If you are sending your base64 string from .net as a param it seems that chars that have special meaning in the URI ie + or / are replaced with " " spaces. 如果您是从.net作为参数发送base64字符串,则似乎在URI中具有特殊含义的字符+/被替换为" "

So before you send your string in .net you should probably do something like this 因此,在将字符串发送到.net之前,您可能应该执行以下操作

base64img.Replace("+", "-").Replace("/", "_"))

Then in python decode the string (also add '=' until the length is divisible by 4) 然后在python中解码字符串(还添加'='直到长度被4整除)

def decode_base64(data):
    data += '=' * (len(data) % 4)
    return base64.urlsafe_b64decode(data)

Further if you want to use the image in openCV 此外,如果要在openCV中使用图像

def get_cv2_img_from_base64(base_64_string):
    data = decode_base64(base_64_string)
    np_data = np.frombuffer(data, dtype=np.uint8)
    return cv2.imdecode(np_data, cv2.IMREAD_UNCHANGED)

My solution was to translate old c# code to python.我的解决方案是将旧的 c# 代码转换为 python。

import base64

def base64_encode_url(value):
    encoded = str(base64.b64encode(bytes(value, "utf-8")), 'utf-8')
    return encoded.replace('=', '').replace('+', '-').replace('/', '_')

def base64_decode_url(data):
    value = data.replace('-', '+').replace('_', '/')
    value += '=' * (len(value) % 4)
    return str(base64.urlsafe_b64decode(value), 'utf-8')

just只是

base64.urlsafe_b64decode(s)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM