我有这个功能:
func GetSigningKey() *rsa.PublicKey {
set, _ := jwk.ParseString(GetWellKnown())
publicKey, _ := set.Keys[0].Materialize()
return publicKey.(*rsa.PublicKey)
}
.Materialize()
返回interface{}
,所以我使用此函数将其强制转换为(我认为是)期望的类型。
然后我可以将该令牌用于:
publicKey := GetSigningKey()
token, _ := jwt.Parse(tokenString, func(*jwt.Token) (interface{}, error) {
return publicKey, nil
})
fmt.Println(token.Valid)
几个问题:
GetSigningKey
函数的目的是从众所周知的文件中获取签名密钥,并将结果密钥转换为正确的类型。
1)这需要一个位于GetWellKnown()
中的http请求。在该函数中,我执行http请求,并将响应缓存在一个变量中,以便后续请求将从该变量中提取。这是一个好习惯吗? (跟进,我应该对GetSigningKey()
中解析的公钥执行相同的操作)
2)我是否认为这是将interface{}
转换为正确类型的最佳方法,对吗?
3)如果尝试使用fmt.Println(GetSigningKey())
,我会得到一长串无法识别的数字
&{2568409364095596940117712027335... %!s(int=65537)}635 <nil>
我在这里看到什么?
答案 0 :(得分:0)
在您的代码中没有错误检查。尤其是如果JWKS为空或包含非RSA密钥的东西,则您的程序将崩溃,而这往往不是Go中鼓励的行为。我将对整个事情进行一些检查;例如,
func GetSigningKey() *rsa.PublicKey, error {
...
if rsaKey, ok := publicKey.(*rsa.PublicKey); ok {
return rsaKey, nil
}
return nil, errors.New("not an RSA key")
}
请记住,other signing methods存在,原则上您可以获取ECDSA密钥或(理论上)用于对称签名的原始密钥,因此在此处进行检查很有价值。
您应该尝试的另一种高级方法是获取原始JSON Web令牌并对其进行解码; https://jwt.io/有一个我使用的调试器。如果标头包含名为"kid"
的声明,它是一个密钥ID,那么您应该能够将该密钥ID作为输入传递给JWKS库。这应该比盲目使用JWKS中的第一个密钥更强大。
联机JWKS文档可以更改,但是通常很少更改(以几个月为单位)。 (如果它们确实发生了变化,那么JWKS可能会同时包含旧密钥和新密钥。)在过程中对其进行高速缓存是非常合理的。如果您看到"kid"
,则表示您无法尝试重新获取文档。
您的fmt.Printf
输出看起来可能是原始的RSA公钥。公钥本身由两个数字组成,一个是两个大质数的乘积,第二个通常恰好是65537。Wikipedia description of RSA中对此有更多讨论。