【问题标题】:How to decode base64 url in python?如何在python中解码base64 url​​?
【发布时间】:2011-03-19 04:37:12
【问题描述】:

对于 Facebook fbml 应用,Facebook 正在发送此处解释的 signed_request 参数:

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

他们已经给出了解码这个签名请求的 php 版本:

http://pastie.org/1054154

如何在 python 中做同样的事情?

我尝试了 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

【问题讨论】:

  • 感谢我尝试了 base64 ,但我收到了这个错误:pastie.org/1054201
  • 请实际发布显示错误的最小代码和实际错误。我们中的大多数人都没有耐心跟踪所有地方的链接。
  • 注意:如果您偶然使用从搜索返回的 Azure blob URL,则需要从编码的 URL stackoverflow.com/questions/44338134/… 中去除尾随的“0”

标签: python facebook base64 decode


【解决方案1】:

只是

base64.urlsafe_b64decode(s)

【讨论】:

  • 请编辑您的答案添加一些解释/文档。
  • 即使使用 URL-safe 变体,您仍然需要在操作生效之前调整输入的填充。
【解决方案2】:

如果您从.net 发送base64 字符串作为参数,则似乎在URI 中具有特殊含义的字符,即+/ 将替换为" " 空格。

所以在你在 .net 中发送你的字符串之前,你可能应该做这样的事情

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

然后在 python 中对字符串进行解码(同时添加 '=' 直到长度可以被 4 整除)

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

如果你想在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)

【讨论】:

    【解决方案3】:

    这是正确的解决方案。在 python 中有 base64.b64encode 但只有 base64 编码,它与 base64 url​​ 编码不同。以下是将 base64encoded 格式转换为 base64urlencoded 字符串的正确步骤:
    1. 从结果字符串中,将“/”替换为“_”,将“+”替换为“-”
    2. 去掉尾随的“==”。

    瞧!这将使它成为 base64 url​​ 解码的有效字符串。顺便说一句,上面@dae.eklen 答案中的链接现在已损坏。

    【讨论】:

      【解决方案4】:

      令人惊讶,但目前接受的答案并不完全正确。 就像其他一些答案一样,它是一种称为 base64url 编码的东西,它是 RFC7515 的一部分。

      基本上,他们分别用 '-' 和 '_' 替换了 '+' 和 '/' 字符;并另外删除了所有尾随的“=”字符,因为您总是可以通过查看编码字符串长度来判断您缺少多少字符。

      这是来自 RFC7515 的 C# 示例:

       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
       }
      

      【讨论】:

      【解决方案5】:

      我在http://sunilarora.org/parsing-signedrequest-parameter-in-python-bas 分享了一个代码 sn-p,用于在基于 python 的 Facebook 画布应用程序中解析 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
      

      【讨论】:

      • dae.eklen 的解决方案也是如此,而且更加优雅。 (base64.urlsafe_b64decode(s + '=' * (4 - len(s) % 4)))
      • 谢谢。这是一个非常短的代码 sn-p- 很高兴看到它包含在这个答案中。
      【解决方案6】:

      替代@dae.eklen 的解决方案,您可以将=== 附加到它:

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

      这是可行的,因为 Python 只抱怨缺少填充,而不是额外的填充。

      【讨论】:

      • 好的,这很有意义并且适用于您的示例。不过我很困惑,我有一个长度为 4 的倍数的字符串,没有填充返回不正确的填充错误,当我有一个 = 时,我仍然遇到同样的问题,但如果我至少有 == 它作品。那是怎么回事?
      【解决方案7】:

      试试

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

      正如它所写的那样here

      【讨论】:

      • 确保您使用的字符串 s 是 str 的实例 - unicode 会因错误而失败。如果是这种情况,请使用 str(s) 函数进行转换。
      【解决方案8】:
      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
      

      【讨论】:

        【解决方案9】:

        显然您在复制原始 base64 编码字符串时遗漏了最后两个字符。在输入字符串后缀两个等号 (=) 即可正确解码。

        【讨论】:

        • 吉尔特,谢谢。但这正是我从 facebook 获得的代码,最后没有 =。这是预期的吗?
        • 这不是我想说的。但是,您可以通过检查 base64 输入的长度来验证它的长度:长度必须始终是 4 字节的倍数(这实际上是解码器抛出错误的原因)。如果不是,您可以添加等号直到它是,然后字符串将被正确解码。
        • 似乎 = 在所有变体中都不需要填充:en.wikipedia.org/wiki/Base64
        • RFC 3548 和 RFC 4648 都声明“......实现必须在编码数据的末尾包含适当的填充字符,除非引用本文档的规范另有明确说明。”这可能就是 Python 的 base64 不接受未正确填充的字符串的原因。
        • 警告这个答案是错误的;它忘记了替换 + 和 / 字符的 - 和 _ 字符。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-08-15
        • 2020-04-18
        • 2017-06-01
        • 2016-05-28
        • 1970-01-01
        • 2015-03-21
        • 2020-07-20
        相关资源
        最近更新 更多