【问题标题】:How to use lists or dicts as command line arguments in pyJWT如何在 pyJWT 中使用列表或字典作为命令行参数
【发布时间】:2019-04-03 11:41:10
【问题描述】:

以下 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 :(

这没有用。是根本不支持吗?

【问题讨论】:

  • 也许您可以向后尝试 - 解码不需要的令牌并查看 json 对象返回的内容以恢复您的工作。乍一看,存在一些可能性,包括 id=1 可能被解释为 int 而不是您预期的 str
  • 好电话,我还没试过。但是它不起作用,它以json格式打印并且不会收回。
  • 这是它返回的对象:{'nested': '[{name=me,', 'id': '1}]'},它会出现紧跟在nested=... 之后的任何内容都被逐字作为一个字符串作为嵌套的值。 pyjwt encode 上的扩展 CLI 帮助也不是很有帮助。最坏的情况是,CLI 可能不支持嵌套对象。
  • 在我看来并非如此。我和他们一起打开了an issue

标签: python jwt pyjwt


【解决方案1】:

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

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

快速了解jwt 包中的__main__.py 给出了这个小sn-p:

... 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 中嵌套dicts

不过,好消息是,有一些方法可以解决这些问题:

  1. 像这样直接在 Python 的 CLI 上运行即兴语句:

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

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

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

    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 进行实施并且它已暴露,我强烈建议您投入精力更仔细地清理和解析 argvs。

  1. 最人为的方法:您可以尝试修改Lib\site-packages\jwt\__main__.py 函数(后果自负)以满足您的需要,直到添加官方支持。我提醒您,在考虑弄乱主代码之前,您应该对编写自己的解析感到相当自在。在我意识到您将遇到的限制之前,我试了几次:

    一个。主要的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 对,我需要进一步处理另一个分隔符,如 , 以及处理 @ 987654343@s,它可能会变得更加混乱。这绝对是可行的,而且效果立竿见影,即 CLI 直接从这个 __main__.py 运行,但它的工作量比我目前想投资的要多,所以我把它交给你有能力的人。

克服这些问题以实现您的需求可能超出必要,这取决于您的技能和舒适程度。所以选择你的战斗......如果 CLI 不是绝对必要的,我建议只使用 .py 方法。

【讨论】:

  • 不错!我想我会选择选项 #1,因为它将在 CI/CD 管道中运行的代码。我认为,动态创建脚本或在每次运行时不断更改重新安装的软件包会更糟。话虽如此,您可以将您的代码作为 PR 发布到我打开的问题中。
  • 我并没有真正使用 github(令人震惊),因为我更像是一个业余爱好者,但请随时添加我对您的问题/PR 的回答的全部/任何部分以帮助社区。
  • 好吧,我可能会这样做。不过,您将因遇到的麻烦而获得适当的学分,再次感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2016-10-10
  • 2018-08-10
  • 2021-10-10
  • 1970-01-01
  • 2011-08-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多