latchset / jwcrypto

Implements JWK,JWS,JWE specifications using python-cryptography
GNU Lesser General Public License v3.0
432 stars 119 forks source link

user data becomes an "unorganized dictionary" #357

Closed nblog closed 3 months ago

nblog commented 3 months ago
    class UserBindings(BaseModel):
        时区: str = "UTC"
        测试1: Optional[OrderedDict[str, Union[str, int, float]]] = {
            "测试键1": "测试值1",
            "测试键2": "测试值2",
        }
        测试2: OrderedDict[str, Union[int, float]] = {
            "测试键1": "测试值1",
            "测试键2": "测试值2",
        }

    bindings = UserBindings()

    @staticmethod
    def dumps_bindings(bindings: 'UserBindings'):
        jwtBindings = \
            jwt.JWT(
                header=dict(alg="HS256"),
                claims=dict(
                    user_data=bindings.model_dump(),
                    iat=int(datetime.now(timezone("UTC")).timestamp())))
        jwtBindings.make_signed_token(jwk.JWK.from_password(SECRET_KEY))
        return jwtBindings.serialize()

order of 'user_data' messed up after serialize

eirnym commented 3 months ago

BTW: After Python 3.7 regular dict keys are ordered

eirnym commented 3 months ago

Here keys are sorted during serialization. It's debatable if library should or should not sort keys during serialization. I see advantages of sorting in this particular library.

I don't know if keys provided in an example are sorted or not (as I don't speak Chinese (this is my guess for the language used). If these keys are sorted and they become unsorted in the target, I'd check if collation set correctly first and ask for a change second.

nblog commented 3 months ago

Here keys are sorted during serialization. It's debatable if library should or should not sort keys during serialization. I see advantages of sorting in this particular library.

I don't know if keys provided in an example are sorted or not (as I don't speak Chinese (this is my guess for the language used). If these keys are sorted and they become unsorted in the target, I'd check if collation set correctly first and ask for a change second.

Thanks for the reply, it gave me an idea why it was misplaced. I'm using python 3.10 and my 'user_data' is explicitly OrderedDict, after serialize, and then being deserialized again, the order of the dictionaries in the user_data has been misplaced, so I had to store it as a string.

eirnym commented 3 months ago

I'd like to understand what does it mean misplaced.

JSON data structure itself doesn't specify any order, json serializers and deserializers doesn't respect any order if not specified explicitly including Python from json package.

nblog commented 3 months ago

from pydantic import BaseModel
from typing import Optional, Union, OrderedDict
from jwcrypto import jwt, jwk
from json import loads, dumps

class UserBindings(BaseModel):
    test: OrderedDict[str, str] = {
        "b": "test1",
        "a": "test2",
    }

bindings = UserBindings()

jwtBindings = \
    jwt.JWT(
        header=dict(alg="HS256"),
        claims=dict(
            user_data=bindings.model_dump()))
jwtBindings.make_signed_token(jwk.JWK.from_password("TEST"))
base64Value = jwtBindings.serialize()

print(
    loads(jwt.JWT(jwt=base64Value, key=jwk.JWK.from_password("TEST")).claims)['user_data']
)

output: {'test': {'a': 'test2', 'b': 'test1'}}

my expected output: {'test': {'b': 'test2', 'a': 'test1'}}

eirnym commented 3 months ago

Out of curiosity: why do you expect this?

N.b. two dicts are equal despite the key order

nblog commented 3 months ago

For example, in a ListView, I test may be the list that the user adds to be displayed, so I'd prefer to display it in the order specified by the user

simo5 commented 3 months ago

Sorry but there is no ordering guarantee in dictionaries, the only thing that matters for jwcrypto is a serialized token anyway. And in serialization we always ask json_encode for sort_keys=True

@nblog it is on your software to sort keys for display if that's what you want, jwcrypto will not do that for you, it is beyond its scope. The order in the dictionary simply does not matter for jwcrypto uses.