繁体   English   中英

在 python 中生成使用 RSA 密钥签名的 JWT 令牌

[英]Generate JWT token signed with RSA key in python

我正在尝试转换此 java 代码以在 python 中生成 JWT 令牌。

String privateKeyContent = privateKey
    .replaceAll(Definitions.ApiGeneral.LINE_BREAKER, "")
    .replace(Definitions.AuthProperty.PRIVATE_KEY_START, "")
    .replace(Definitions.AuthProperty.PRIVATE_KEY_END, "");

PKCS8EncodedKeySpec keySpecPKCS8 = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyContent));

KeyFactory kf = KeyFactory.getInstance(Definitions.AuthProperty.RSA_KEY_FACTORY);
PrivateKey privKey = kf.generatePrivate(keySpecPKCS8);

String jwtAudUrl = System.getenv(Definitions.IamProperty.IAM_URL_KEY) + System.getenv(Definitions.IamProperty.JWT_AUD_URI_KEY);
String jwtToken = Jwts.builder()
    .setAudience(jwtAudUrl)
    .setSubject(serviceId)
    .setIssuer(serviceId)
    .setExpiration(new Date(new Date().getTime() + TimeUnit.MINUTES.toMillis(Definitions.AuthProperty.JWT_TOKEN_EXPIRY_IN_MINUTES)))
    .signWith(privKey)
    .compact();

Python:

import jwt

serviceID = "abc"
secret = '-----BEGIN RSA PRIVATE KEY-----MIIEogIBAAKCAQEAhstYtRbkgQkFwlVr8QjSCQqqRTDMKWHdIGRYBpXcQmvKfagId9nBA2Ygh7cOrT9g8MhxYo8U1jYmPQpv6gf3LgO/J0qspLdaAhZP6LusA/HHJBR7kjTXBsLcsEDyd8S0UioBYP3DLvtWhGIR2f4o7SH1TlE96tldV6FZKGO2NHsJrJwTd+ym0AeZe0b7QZLe43LBCTLdqk05U34jrknJliSAEbGqYg4h6nrJsKBC/0pmiQ9ptD1N/Kl4bqffMWIbZq2bPP6jFrmBLe+7yTeVMKltVbJZys4nHhyYngBtbAxynXeB2tpE8If7cK75fj42MlFgquEiEZZVSzNNmrmPOwIDAQABAoH/B18Xes/Fr0jPB9GkFYpl8hijNyV0BM9VSHA0YCfR49ABQt3tmKBP7d+n58QbCV5t7r0Hdlxcx1ouvSfU9vd4jQunaH6s8lUUlwihVhjtT0npmg+EsnoxSC1f5EOo/uPC+LtTV/qIsgkMsjCqyUEc+9rfj2jh+fXpJOGt/od1b2k2xs84MsXmSF/As7GYRdw+FLbkN64R/SGmv3NLtQdg5uvBKLuKvtQWIJBuPqgKOsJWaCVO0XaoUDQeav/nTfP0ntmF0QH9JtXYzBldhGq2FPVQRUaCuJ4YPEpXlD3FptQBlX/Wu7wXbdwDz3qyXbGqSkiaR3gN+QR+IgjG3oQxAoGBAML5M4Dg0S/yobHuCRcvpngraXGBWnCTaD0mMh/cosV0HBNdZbglwVpG8Agz9BEYIrDM777HFuB+lWUvGNMR45rObPcDqn7Qj8Uwnj775Bg0Sx09MCBds6IGce/92uPUsHPx4pj8dzCj1s3cfUKO+EaUE33bnFXcMCGh/0x0sIVXAoGBALD8H4Aph2OPQK9OOHb3ULDvrmMPrpe3xv5iSzfLt7xBIP2G0Wl+q0hzEtdEOUZGQemOtyuV5t9Jwwfh9uH9jAhk9OEvoNg3F3mQl6hjmHPd1xUNvRTqwnV+VvQnw7Aeq2TZMcAKwbXf3+p430wMsxR6m0Y7rGi0FIxWbILp0RK9AoGBAIfiPBXnGYOsOysRtb42FHQN9WgI+eoZof10IFz6XWr12Bda8Wicz5vGcsWUx9YeFxdXTQOOJ5CASEiDwW5hOlqK4YBqSqolWv3YO4Gz9i00TOFs4py8EVSr3z6ekq5UbkHwY7exxLPei/dfYuE/WSN/UfJWWyev1M+r4oz7iobzAoGAKe8S56LvWT+P6/l0l3txuvqPLxmAHKKGm69ecxHprskfr/JJm91PaBMb27VmfKgY5eXSsJkL4svvUebQQCt7CmIhQ1mtmo0zGrKPvG4cqRde5rYintogyQXuRFtHmmsp4PM1PnNOAnHQ9BU/kx1PMQL712A8MXK5i6bOfxY3W2ECgYEAp9cw3NeMSy/WcXyZoyNFUdEQiHTJGPBtELjHWRnjMU1454EkWYYPiYXUnElfxP6InxHgMNbGVsd1BUEhXOdSUS5bO/WBOOPqSh6MIGfKFuMN/9SI/Y/UZKltCD1CboTvDfmkD+opkLM6YZpW9CRT7Szn7ivdFr5KqGQZUZOwn3k=-----END RSA PRIVATE KEY-----'

due_date = datetime.now() + timedelta(minutes=10)
header = {"alg": "RS256"}
expiry = int(due_date.timestamp())
payload = {"iss": serviceID, "sub": serviceID, "exp": expiry, "aud": iam_url + "/oauth2/access_token"}

priv_rsakey = serialization.load_pem_private_key(secret.encode('utf8'), password=None, backend=default_backend())
token=jwt.encode(payload, priv_rsakey, algorithm='RS256')

但是,我不断收到此错误:

ValueError: ('Could not deserialize key data. The data may be in an incorrect format, it may be encrypted with an unsupported algorithm, or it may be an unsupported key type (e.g. EC curves with explicit parameters).', [_OpenSSLErrorWithText(code=503841036, lib=60, reason=524556, reason_text=b'error:1E08010C:DECODER routines::unsupported')])

有人可以帮我吗?

错误消息中明确指出了该问题:您的私钥格式不正确。 PEM 编码密钥由 Base64 编码主体组成,每 64 个字符后包含一个换行符,以及 header 和单独行的页脚。 您的密钥缺少换行符。

load_pem_private_key()期望至少 header 和页脚在单独的行中,但可以容忍正文中的换行符,即它们是可选的。 所以你必须像这样传递你的密钥:

secret = '-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAhstYtRbkgQkFwlVr8QjSCQqqRTDMKWHdIGRYBpXcQmvKfagId9nBA2Ygh7cOrT9g8MhxYo8U1jYmPQpv6gf3LgO/J0qspLdaAhZP6LusA/HHJBR7kjTXBsLcsEDyd8S0UioBYP3DLvtWhGIR2f4o7SH1TlE96tldV6FZKGO2NHsJrJwTd+ym0AeZe0b7QZLe43LBCTLdqk05U34jrknJliSAEbGqYg4h6nrJsKBC/0pmiQ9ptD1N/Kl4bqffMWIbZq2bPP6jFrmBLe+7yTeVMKltVbJZys4nHhyYngBtbAxynXeB2tpE8If7cK75fj42MlFgquEiEZZVSzNNmrmPOwIDAQABAoH/B18Xes/Fr0jPB9GkFYpl8hijNyV0BM9VSHA0YCfR49ABQt3tmKBP7d+n58QbCV5t7r0Hdlxcx1ouvSfU9vd4jQunaH6s8lUUlwihVhjtT0npmg+EsnoxSC1f5EOo/uPC+LtTV/qIsgkMsjCqyUEc+9rfj2jh+fXpJOGt/od1b2k2xs84MsXmSF/As7GYRdw+FLbkN64R/SGmv3NLtQdg5uvBKLuKvtQWIJBuPqgKOsJWaCVO0XaoUDQeav/nTfP0ntmF0QH9JtXYzBldhGq2FPVQRUaCuJ4YPEpXlD3FptQBlX/Wu7wXbdwDz3qyXbGqSkiaR3gN+QR+IgjG3oQxAoGBAML5M4Dg0S/yobHuCRcvpngraXGBWnCTaD0mMh/cosV0HBNdZbglwVpG8Agz9BEYIrDM777HFuB+lWUvGNMR45rObPcDqn7Qj8Uwnj775Bg0Sx09MCBds6IGce/92uPUsHPx4pj8dzCj1s3cfUKO+EaUE33bnFXcMCGh/0x0sIVXAoGBALD8H4Aph2OPQK9OOHb3ULDvrmMPrpe3xv5iSzfLt7xBIP2G0Wl+q0hzEtdEOUZGQemOtyuV5t9Jwwfh9uH9jAhk9OEvoNg3F3mQl6hjmHPd1xUNvRTqwnV+VvQnw7Aeq2TZMcAKwbXf3+p430wMsxR6m0Y7rGi0FIxWbILp0RK9AoGBAIfiPBXnGYOsOysRtb42FHQN9WgI+eoZof10IFz6XWr12Bda8Wicz5vGcsWUx9YeFxdXTQOOJ5CASEiDwW5hOlqK4YBqSqolWv3YO4Gz9i00TOFs4py8EVSr3z6ekq5UbkHwY7exxLPei/dfYuE/WSN/UfJWWyev1M+r4oz7iobzAoGAKe8S56LvWT+P6/l0l3txuvqPLxmAHKKGm69ecxHprskfr/JJm91PaBMb27VmfKgY5eXSsJkL4svvUebQQCt7CmIhQ1mtmo0zGrKPvG4cqRde5rYintogyQXuRFtHmmsp4PM1PnNOAnHQ9BU/kx1PMQL712A8MXK5i6bOfxY3W2ECgYEAp9cw3NeMSy/WcXyZoyNFUdEQiHTJGPBtELjHWRnjMU1454EkWYYPiYXUnElfxP6InxHgMNbGVsd1BUEhXOdSUS5bO/WBOOPqSh6MIGfKFuMN/9SI/Y/UZKltCD1CboTvDfmkD+opkLM6YZpW9CRT7Szn7ivdFr5KqGQZUZOwn3k=\n-----END RSA PRIVATE KEY-----'

或者

secret = '''-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAhstYtRbkgQkFwlVr8QjSCQqqRTDMKWHdIGRYBpXcQmvKfagId9nBA2Ygh7cOrT9g8MhxYo8U1jYmPQpv6gf3LgO/J0qspLdaAhZP6LusA/HHJBR7kjTXBsLcsEDyd8S0UioBYP3DLvtWhGIR2f4o7SH1TlE96tldV6FZKGO2NHsJrJwTd+ym0AeZe0b7QZLe43LBCTLdqk05U34jrknJliSAEbGqYg4h6nrJsKBC/0pmiQ9ptD1N/Kl4bqffMWIbZq2bPP6jFrmBLe+7yTeVMKltVbJZys4nHhyYngBtbAxynXeB2tpE8If7cK75fj42MlFgquEiEZZVSzNNmrmPOwIDAQABAoH/B18Xes/Fr0jPB9GkFYpl8hijNyV0BM9VSHA0YCfR49ABQt3tmKBP7d+n58QbCV5t7r0Hdlxcx1ouvSfU9vd4jQunaH6s8lUUlwihVhjtT0npmg+EsnoxSC1f5EOo/uPC+LtTV/qIsgkMsjCqyUEc+9rfj2jh+fXpJOGt/od1b2k2xs84MsXmSF/As7GYRdw+FLbkN64R/SGmv3NLtQdg5uvBKLuKvtQWIJBuPqgKOsJWaCVO0XaoUDQeav/nTfP0ntmF0QH9JtXYzBldhGq2FPVQRUaCuJ4YPEpXlD3FptQBlX/Wu7wXbdwDz3qyXbGqSkiaR3gN+QR+IgjG3oQxAoGBAML5M4Dg0S/yobHuCRcvpngraXGBWnCTaD0mMh/cosV0HBNdZbglwVpG8Agz9BEYIrDM777HFuB+lWUvGNMR45rObPcDqn7Qj8Uwnj775Bg0Sx09MCBds6IGce/92uPUsHPx4pj8dzCj1s3cfUKO+EaUE33bnFXcMCGh/0x0sIVXAoGBALD8H4Aph2OPQK9OOHb3ULDvrmMPrpe3xv5iSzfLt7xBIP2G0Wl+q0hzEtdEOUZGQemOtyuV5t9Jwwfh9uH9jAhk9OEvoNg3F3mQl6hjmHPd1xUNvRTqwnV+VvQnw7Aeq2TZMcAKwbXf3+p430wMsxR6m0Y7rGi0FIxWbILp0RK9AoGBAIfiPBXnGYOsOysRtb42FHQN9WgI+eoZof10IFz6XWr12Bda8Wicz5vGcsWUx9YeFxdXTQOOJ5CASEiDwW5hOlqK4YBqSqolWv3YO4Gz9i00TOFs4py8EVSr3z6ekq5UbkHwY7exxLPei/dfYuE/WSN/UfJWWyev1M+r4oz7iobzAoGAKe8S56LvWT+P6/l0l3txuvqPLxmAHKKGm69ecxHprskfr/JJm91PaBMb27VmfKgY5eXSsJkL4svvUebQQCt7CmIhQ1mtmo0zGrKPvG4cqRde5rYintogyQXuRFtHmmsp4PM1PnNOAnHQ9BU/kx1PMQL712A8MXK5i6bOfxY3W2ECgYEAp9cw3NeMSy/WcXyZoyNFUdEQiHTJGPBtELjHWRnjMU1454EkWYYPiYXUnElfxP6InxHgMNbGVsd1BUEhXOdSUS5bO/WBOOPqSh6MIGfKFuMN/9SI/Y/UZKltCD1CboTvDfmkD+opkLM6YZpW9CRT7Szn7ivdFr5KqGQZUZOwn3k=
-----END RSA PRIVATE KEY-----'''

通过此更改,代码可以正常工作(在添加缺少的iam_url和缺少的import语句之后)。


请注意,Java 代码中的PKCS8EncodedKeySpec需要 PKCS#8 格式的 DER 编码私钥,而在 Python 代码中应用 PKCS#1 格式的 PEM 编码私钥。

通过删除 header、页脚和所有换行符以及 Base64 解码 rest,从 PEM 编码密钥生成 DER 编码密钥。密码学库支持使用load_der_private_key()导入 DER 编码私钥:

import base64
secret = base64.b64decode('MIIEogIBAAKCAQEAhstYtRbkgQkFwlVr8QjSCQqqRTDMKWHdIGRYBpXcQmvKfagId9nBA2Ygh7cOrT9g8MhxYo8U1jYmPQpv6gf3LgO/J0qspLdaAhZP6LusA/HHJBR7kjTXBsLcsEDyd8S0UioBYP3DLvtWhGIR2f4o7SH1TlE96tldV6FZKGO2NHsJrJwTd+ym0AeZe0b7QZLe43LBCTLdqk05U34jrknJliSAEbGqYg4h6nrJsKBC/0pmiQ9ptD1N/Kl4bqffMWIbZq2bPP6jFrmBLe+7yTeVMKltVbJZys4nHhyYngBtbAxynXeB2tpE8If7cK75fj42MlFgquEiEZZVSzNNmrmPOwIDAQABAoH/B18Xes/Fr0jPB9GkFYpl8hijNyV0BM9VSHA0YCfR49ABQt3tmKBP7d+n58QbCV5t7r0Hdlxcx1ouvSfU9vd4jQunaH6s8lUUlwihVhjtT0npmg+EsnoxSC1f5EOo/uPC+LtTV/qIsgkMsjCqyUEc+9rfj2jh+fXpJOGt/od1b2k2xs84MsXmSF/As7GYRdw+FLbkN64R/SGmv3NLtQdg5uvBKLuKvtQWIJBuPqgKOsJWaCVO0XaoUDQeav/nTfP0ntmF0QH9JtXYzBldhGq2FPVQRUaCuJ4YPEpXlD3FptQBlX/Wu7wXbdwDz3qyXbGqSkiaR3gN+QR+IgjG3oQxAoGBAML5M4Dg0S/yobHuCRcvpngraXGBWnCTaD0mMh/cosV0HBNdZbglwVpG8Agz9BEYIrDM777HFuB+lWUvGNMR45rObPcDqn7Qj8Uwnj775Bg0Sx09MCBds6IGce/92uPUsHPx4pj8dzCj1s3cfUKO+EaUE33bnFXcMCGh/0x0sIVXAoGBALD8H4Aph2OPQK9OOHb3ULDvrmMPrpe3xv5iSzfLt7xBIP2G0Wl+q0hzEtdEOUZGQemOtyuV5t9Jwwfh9uH9jAhk9OEvoNg3F3mQl6hjmHPd1xUNvRTqwnV+VvQnw7Aeq2TZMcAKwbXf3+p430wMsxR6m0Y7rGi0FIxWbILp0RK9AoGBAIfiPBXnGYOsOysRtb42FHQN9WgI+eoZof10IFz6XWr12Bda8Wicz5vGcsWUx9YeFxdXTQOOJ5CASEiDwW5hOlqK4YBqSqolWv3YO4Gz9i00TOFs4py8EVSr3z6ekq5UbkHwY7exxLPei/dfYuE/WSN/UfJWWyev1M+r4oz7iobzAoGAKe8S56LvWT+P6/l0l3txuvqPLxmAHKKGm69ecxHprskfr/JJm91PaBMb27VmfKgY5eXSsJkL4svvUebQQCt7CmIhQ1mtmo0zGrKPvG4cqRde5rYintogyQXuRFtHmmsp4PM1PnNOAnHQ9BU/kx1PMQL712A8MXK5i6bOfxY3W2ECgYEAp9cw3NeMSy/WcXyZoyNFUdEQiHTJGPBtELjHWRnjMU1454EkWYYPiYXUnElfxP6InxHgMNbGVsd1BUEhXOdSUS5bO/WBOOPqSh6MIGfKFuMN/9SI/Y/UZKltCD1CboTvDfmkD+opkLM6YZpW9CRT7Szn7ivdFr5KqGQZUZOwn3k=') 
priv_rsakey = serialization.load_der_private_key(secret, password=None, backend=default_backend())

load_pem_private_key()load_der_private_key()支持 PKCS#8 和 PKCS#1 格式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM