如何在pyJWT中将列表或字典用作命令行参数

时间:2018-10-30 12:18:55

标签: python jwt pyjwt

以下python代码使用pyjwt生成有效的JWT令牌:

>>> import jwt
>>> payload = {'nested': [{'name': 'me', 'id': '1'}]}
>>> token = jwt.encode(payload, 'secret')
>>> token.decode()
ey[...]ko0Zq_k

pyjwt还支持从命令行界面进行调用。但是the docs仅显示带有=分隔键值对而不包含嵌套有效负载的示例。

我的最佳猜测是:

$ pyjwt --key=secret encode nested=[{name=me, id=1}]
ey[...]0FRW9gyU  # not the same token as above :(

哪个没用。完全不支持吗?

1 个答案:

答案 0 :(得分:1)

如前所述,您的命令行令牌在解码时会返回以下json对象:

{'nested': '[{name=me,', 'id': '1}]'}

快速浏览__main__.py包中的jwt可以看到以下代码段:

... snipped

def encode_payload(args):
    # Try to encode
    if args.key is None:
        raise ValueError('Key is required when encoding. See --help for usage.')

    # Build payload object to encode
    payload = {}

    for arg in args.payload:
        k, v = arg.split('=', 1)

    ... some additional handling on v for time, int, float and True/False/None
    ... snipped

如您所见,有效载荷的键和值是直接根据split('=', 1)确定的,因此在命令行中,键之后的第一个=传递的所有内容都将始终确定为单一值(此后会进行一些转换)。

因此,简而言之,不支持CLI中的嵌套dict

不过,好消息是,您可以通过某些方法来解决这些问题:

  1. 直接在Python的CLI上运行即兴语句,如下所示:

    > python -c "import jwt; print(jwt.encode({'nested':[{'name':'me', 'id':'1'}]}, 'secret').decode('utf-8'))"
    
    # eyJ...Zq_k
    

并不完全理想,但是它可以满足您的需求。

  1. 将相同的脚本保存到能够接收args的.py并在Python的CLI上执行:

    import sys, jwt
    my_json = sys.argv[0]
    token = jwt.encode(eval(my_json), 'secret')
    print(token.decode('utf-8'))
    
    # run in CLI
    > python my_encode.py "{'nested':[{'name':'me', 'id':'1'}]}"
    
    # eyJ...Zq_k
    

请注意,出于安全考虑,此处eval()的使用不理想。这只是我懒惰的实现方式,因为我不想为args编写解析器。如果您绝对必须使用CLI进行实施并且已经公开了CLI,我强烈建议您花更多的精力在清理和解析argv上。

  1. 最人为的方式:您可以 尝试修改Lib\site-packages\jwt\__main__.py函数(由您自己承担风险)以适应您的需要,直到增加官方支持为止。我要提醒您,尽管在考虑与主代码混淆之前,您应该对编写自己的解析感到相当满意。在意识到您将要遇到的局限性之前,我经过了几次尝试:

    a。主要的encode()方法不会将list视为有效的JSON对象(但应该如此)。因此,马上就要使用dict这样的字符串来进行操作。

    b。如果可能,代码始终强制将数字强制转换为intfloat。您需要以某种方式对其进行转义,或者完全改变其处理数字的方式。

    我的尝试是这样的:

    def func(result, payload):
        for arg in payload:
            k, v = arg.split('=', 1)
    
            if v.startswith('{') and v.endswith('}'):
                result[k] = func({}, v[1:-1])
            else:
            ... the rest of the existing code
    

    但是我很快遇到了限制,原始参数已经用空格分隔,并且假设它是一对kv,我需要进一步处理另一个分隔符,例如,,因为以及处理list的功能,并且可能变得更混乱。这绝对是可行的,而且效果是立竿见影的,即CLI可以直接从__main__.py开始运行,但是这比我目前要投资的工作量还多,所以我将它交给您有能力的人。

克服这些问题以实现您所需的努力可能比必要的要多,这取决于您的技能和舒适度。因此,选择战斗吧……如果CLI并非绝对必要,我建议您仅使用.py方法。