Как использовать списки или слова в качестве аргументов командной строки в pyJWT - PullRequest
0 голосов
/ 30 октября 2018

Следующий код Python создает действительный токен JWT, используя pyjwt:

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

pyjwt также поддерживает вызовы из интерфейса командной строки. Но в документах показаны только примеры с = разделенными парами ключ-значение, а не с вложенными полезными нагрузками.

Мое лучшее предположение было таким:

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

Что не сработало. Это просто не поддерживается?

1 Ответ

0 голосов
/ 30 октября 2018

Как уже упоминалось, ваш токен командной строки при декодировании возвращает этот 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), поэтому все, что передано в первой командной строке = после ключа, всегда будет определяться как одно значение (с некоторое преобразование потом).

Короче говоря, вложенные dict s в CLI не поддерживаются .

Тем не менее, есть и хорошие новости: есть несколько способов обойти это:

  1. Запустите импровизированный оператор непосредственно из CLI Python следующим образом:

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

Не совсем идеально, но дает вам то, что вам нужно.

  1. Сохраните тот же сценарий в .py, способный принимать аргументы, и выполните его на CLI Python:

    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() здесь не идеально из-за проблем безопасности. Это просто мой ленивый способ реализации, потому что я не хочу писать парсер для аргументов. Если вам абсолютно необходимо использовать интерфейс командной строки для своей реализации, и он открыт, я настоятельно рекомендую вам вложить усилия в более тщательную очистку и анализ argv.

  1. Самый хитрый способ: вы можете попытаться изменить функцию Lib\site-packages\jwt\__main__.py (на свой страх и риск) в соответствии с вашими потребностями, пока не будет добавлена ​​официальная поддержка. Я хотел бы предостеречь, что вам должно быть довольно удобно писать свой собственный анализ, прежде чем подумать о том, чтобы возиться с основным кодом. Я сделал несколько попыток, прежде чем осознал ограничения, с которыми вы столкнетесь:

    а. Основной метод encode() не считает list допустимым объектом JSON (но он должен). Так что сразу у вас должна быть dict подобная строка для манипуляции.

    б. Код всегда заставляет числа быть приведенными как int или float, если это возможно. Вам нужно как-то избежать этого или полностью изменить способ обработки чисел.

    Моя попытка прошла примерно так:

    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
    

    Однако я быстро столкнулся с ограничением исходных аргументов, уже разделенных пробелами, и предположил, что это пара k, v, мне нужно дополнительно обработать другой разделитель, такой как ,, а также возможность обрабатывать list с, и это может стать более грязным. Это определенно выполнимо, и эффект незамедлительный, то есть CLI запускается прямо из этого __main__.py, но это больше работы, чем я хотел бы вложить в данный момент, поэтому я оставляю это вашими умелыми руками.

Усилия по преодолению этих проблем для достижения того, что вам нужно, могут быть более чем необходимыми, зависит от ваших навыков и уровня комфорта. Так что выбирайте свою битву ... если CLI не является абсолютно необходимым, я бы предложил вместо этого использовать .py методы.

...