python 3打印bytestring并说string是str类型?

时间:2017-01-10 06:41:37

标签: python python-3.x

我的代码来自单点登录功能

from urllib.parse import unquote
import base64

payload = unquote(payload)
print(payload)
print(type(payload))
decoded = base64.decodestring(payload)

decodestring抱怨我给它一个字符串而不是字节......

  File "/Users/Jeff/Development/langalang/proj/discourse/views.py", line 38, in sso
    decoded = base64.decodestring(payload)
  File "/Users/Jeff/.virtualenvs/proj/lib/python3.6/base64.py", line 559, in decodestring
    return decodebytes(s)
  File "/Users/Jeff/.virtualenvs/proj/lib/python3.6/base64.py", line 551, in decodebytes
    _input_type_check(s)
  File "/Users/Jeff/.virtualenvs/proj/lib/python3.6/base64.py", line 520, in _input_type_check
    raise TypeError(msg) from err
TypeError: expected bytes-like object, not str

这很好但是当我看到打印到终端的打印语句时,我看到了......

b'bm9uY2U9NDI5NDg5OTU0NjU4MjAzODkyNTI=\n'
<class 'str'>

似乎是说它是一串字节,但后来它说它是一个字符串。

这里发生了什么?

如果我在有效负载声明的末尾添加encode(),我会看到这个......

payload = unquote(payload).encode()

b"b'bm9uY2U9NDQxMTQ4MzIyNDMwNjU3MjcyMDM=\\n'"
<class 'bytes'>

编辑:添加制作有效载荷的方法

@patch("discourse.views.HttpResponseRedirect")
def test_sso_success(self, mock_redirect):
    """Test for the sso view"""

    # Generating a random number, encoding for url, signing it with a hash
    nonce = "".join([str(random.randint(0, 9)) for i in range(20)])
    # The sso payload needs to be a dict of params
    params = {"nonce": nonce}
    payload = base64.encodestring(urlencode(params).encode())
    print(payload.decode() + " tests")

    key = settings.SSO_SECRET
    h = hmac.new(key.encode(), payload, digestmod=hashlib.sha256)
    signature = h.hexdigest()

    url = reverse("discourse:sso") + "?sso=%s&sig=%s" % (payload, signature)
    req = self.rf.get(url)
    req.user = self.user
    response = sso(req)
    self.assertTrue(mock_redirect.called)

3 个答案:

答案 0 :(得分:1)

  

似乎是说它是一串字节,但后来它说它是一个字符串。

看起来你在这里的字符串看起来像:"b'bm9uY2U9NDQxMTQ4MzIyNDMwNjU3MjcyMDM=\\n'"所以前导b不是字节文字,它只是字符串值的一部分。

因此,在将符号传递给base64解码器之前,您需要先将其删除:

from urllib.parse import unquote, quote_from_bytes
import base64

payload = unquote(payload)
print(payload[2:-1])
enc = base64.decodebytes(payload[2:-1].encode())
print(enc)

答案 1 :(得分:1)

当您payload生成base64.encodestring(s)时,文档是:

  

对类似字节的对象进行编码,该对象可以包含任意二进制文件   数据,以及包含base64编码数据的返回字节   在每76个字节的输出之后插入换行符(b'\ n')并确保   根据RFC 2045(MIME),有一个尾随换行符。

然后对{ASCII}字符序列进行urllib.parse.unquote。在那一刻,你的字符串前缀为b',因为unquote在有效负载bytearray上运行str构造函数。作为一个请求,你得到一个str而不是字节,而且这是一个无效的base64编码。

答案 2 :(得分:0)

允许原始错误认为,并且编码字符串的显示确认了它:您的payload字符串 是一个unicode字符串,恰好以前缀{{1}开头并以单个"b'"结尾。

这样的字符串通常使用"'"调用构建:

repr

您可以使用>>> b = b'abc' # b is a byte string >>> r = repr(b) # by construction r is a unicode string >>> print(r) # will look like a byte string b'abc' >>> print(b) # what is printed for a true byte string abc 恢复为真正的字节字符串:

literal_eval

但是还原只是一种解决方法,您应该在代码中跟踪您构建字节字符串的表示