如何手动生成JWT的RS256签名?已完成Header与Payload编码
问题:手动生成JWT签名失败,求正确步骤及错误原因
我有以下JWT:
eyJhbGciOiJSUzI1NiIsImtpZCI6IjVkMzQwZGRiYzNjNWJhY2M0Y2VlMWZiOWQxNmU5ODM3ZWM2MTYzZWIiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiemFnYWxvIiwiaXNzIjoiaHR0cHM6Ly9zZWN1cmV0b2tlbi5nb29nbGUuY29tL3Byb2ZlcHQtM2M0NzkiLCJhdWQiOiJwcm9mZXB0LTNjNDc5IiwiYXV0aF90aW1lIjoxNjY2MjkxNDAzLCJ1c2VyX2lkIjoiZ1JtdnFYb0tySE85T0RLUURCYTBWNnRaNTBLMiIsInN1YiI6ImdSbXZxWG9LckhPOU9ES1FEQmEwVjZ0WjUwSzIiLCJpYXQiOjE2NjYyOTE0MDMsImV4cCI6MTY2NjI5NTAwMywiZW1haWwiOiJyc2p1bGlhb0BnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsicnNqdWxpYW9AZ21haWwuY29tIl19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifX0.ZkBqE8GCSGt9FX_LxoaLNgHcPx19EDMq3ARmZaJ_R1_FiBcQAp8T_AEmleVu68lqw7SdcM2aAjZ1kZbfkZ48hgfhW0LI03VC_6Dc4sq9pgCHWarteCeUz4fE1B6nl4nIbKI3nPQorKYTu82SXEzaRiEwHQCVayiMmnkjzj4d-2YVp4WA8If_h3jNHBe8giskjwkB2t6hB39vYLqvcM5sEeSBRpVT8zA-hmp2AeImcXagCK4Av7JIt_iBNuwT9dwMLtA6addoXcDYTJuRZ3GhVrbL8x_is9u2XDDLWDWdrj1yAjkq7pTPwC7KPft8Md2PKxqYR5bid_VRSjPIeb_k8A
对应的公钥:
-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3CTs4UeO1cS3FJAWDTcO HHcAeEfZOCFmxju1xC+kSAw9RVQTykKzgNAREUQyGFvp1WwC51r1QHMwNyk+wsDG /h4mbDIgECMeEEGh2qnHgFIVWJ12H5oP/WHVvho/GgVuOkJzCuHTTVYGSaKi43IR VZqO7784VfzHsHl/caUqv/pOu8MjsynD8QVzac0XrdXHTqYUMWm0rFCrEm+UWFHK KQK2skzQxFTUTcI2NtG+TjNFiHGs3ZzAfd+N6PuW3FpX3TsNN0fWmFbqgUH0oduV 9Qd2XhZ2TtnAK4+FVCLJDuqk8XkAe9Ibmgelz+aKtwFGN1bx8TilswsvepGjDpMj AwIDAQAB -----END PUBLIC KEY-----
用验证工具可以成功验证该JWT的签名,但手动生成签名时失败,步骤如下:
- 对Header JSON:
{"alg":"RS256","kid":"5d340ddbc3c5bacc4cee1fb9d16e9837ec6163eb","typ":"JWT"}
执行base64UrlEncode,得到正确结果:
eyJhbGciOiJSUzI1NiIsImtpZCI6IjVkMzQwZGRiYzNjNWJhY2M0Y2VlMWZiOWQxNmU5ODM3ZWM2MTYzZWIiLCJ0eXAiOiJKV1QifQ
- 对Payload JSON:
{"name":"zagalo","iss":"https://securetoken.google.com/profept-3c479","aud":"profept-3c479","auth_time":1666291403,"user_id":"gRmvqXoKrHO9ODKQDBa0V6tZ50K2","sub":"gRmvqXoKrHO9ODKQDBa0V6tZ50K2","iat":1666291403,"exp":1666295003,"email":"rsjuliao@gmail.com","email_verified":false,"firebase":{"identities":{"email":["rsjuliao@gmail.com"]},"sign_in_provider":"password"}}
执行base64UrlEncode,也得到正确结果:
eyJuYW1lIjoiemFnYWxvIiwiaXNzIjoiaHR0cHM6Ly9zZWN1cmV0b2tlbi5nb29nbGUuY29tL3Byb2ZlcHQtM2M0NzkiLCJhdWQiOiJwcm9mZXB0LTNjNDc5IiwiYXV0aF90aW1lIjoxNjY2MjkxNDAzLCJ1c2VyX2lkIjoiZ1JtdnFYb0tySE85T0RLUURCYTBWNnRaNTBLMiIsInN1YiI6ImdSbXZxWG9LckhPOU9ES1FEQmEwVjZ0WjUwSzIiLCJpYXQiOjE2NjYyOTE0MDMsImV4cCI6MTY2NjI5NTAwMywiZW1haWwiOiJyc2p1bGlhb0BnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsicnNqdWxpYW9AZ21haWwuY29tIl19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifX0
按照说明,签名应为RSASHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload)),我尝试将SHA256结果传入RSA操作(用上述公钥),但无法得到正确签名。请问正确的生成步骤是什么?我哪里出错了?需要学习哪些知识来解决该问题?
解答
核心错误点
RS256的签名逻辑是用私钥对哈希结果做签名,公钥仅用于验证签名合法性,你手里只有公钥,根本不可能生成出正确的签名——公钥无法反向替代私钥完成签名操作。
RS256签名的正确步骤
- 拼接Header和Payload的base64Url编码结果,中间用
.分隔,得到待签名字符串H.P - 对
H.P做SHA-256哈希,得到哈希值 - 用对应的RSA私钥对这个哈希值做PKCS#1 v1.5格式的签名(这就是RSASHA256的核心操作)
- 把签名结果做base64Url编码,就是JWT的第三段内容
为什么公钥无法生成签名
RSA是非对称加密算法,私钥负责签名/加密,公钥负责验证/解密。私钥是签名方(这里是Google的Secure Token服务)持有的保密密钥,你拿到的公钥只能用来确认签名是否由对应私钥生成,无法反向生成签名。
需要补充的知识
- 非对称加密(RSA)基础:私钥与公钥的分工、签名/验证的完整流程
- JWT签名规范:不同算法(RS256/HS256等)的具体实现逻辑差异
- 密码学基础:哈希函数的单向性、签名与哈希的关联区别
内容的提问来源于stack exchange,提问作者aguiadouro
相关产品推荐
相关产品推荐

