Go 转到语言并验证JWT

Go 转到语言并验证JWT,go,jwt,jwt-go,Go,Jwt,Jwt Go,我一直在寻找一个我能理解的例子,如何用GO语言验证JWT的签名 这可能特别棘手,因为我使用的是Okta,它使用的是JWKs,所以它不是特别直接 当我收到JWT,我可以解码它没有问题,只是停留在如何验证签名 下面我介绍了JWT和JWK的详细信息。如果有人对此感到满意,并能用一个例子完成签名验证,那将是令人惊讶的。:) 您可以在此处获得所有这些信息:,此站点将从Okta生成JWT,并且可以在此处获得密钥: 以下是JWT: eyJhbGciOiJSUzI1NiIsImtpZCI6Ind5TXdLNEE

我一直在寻找一个我能理解的例子,如何用GO语言验证JWT的签名

这可能特别棘手,因为我使用的是Okta,它使用的是JWKs,所以它不是特别直接

当我收到JWT,我可以解码它没有问题,只是停留在如何验证签名

下面我介绍了JWT和JWK的详细信息。如果有人对此感到满意,并能用一个例子完成签名验证,那将是令人惊讶的。:)

您可以在此处获得所有这些信息:,此站点将从Okta生成JWT,并且可以在此处获得密钥:

以下是JWT:

eyJhbGciOiJSUzI1NiIsImtpZCI6Ind5TXdLNEE2Q0w5UXcxMXVvZlZleVExMTlYeVgteHlreW1ra1h5Z1o1T00ifQ.eyJzdWIiOiIwMHUxOGVlaHUzNDlhUzJ5WDFkOCIsIm5hbWUiOiJva3RhcHJveHkgb2t0YXByb3h5IiwidmVyIjoxLCJpc3MiOiJodHRwczovL2NvbXBhbnl4Lm9rdGEuY29tIiwiYXVkIjoidlpWNkNwOHJuNWx4ck45YVo2ODgiLCJpYXQiOjE0ODEzODg0NTMsImV4cCI6MTQ4MTM5MjA1MywianRpIjoiSUQuWm9QdVdIR3IxNkR6a3RUbEdXMFI4b1lRaUhnVWg0aUotTHo3Z3BGcGItUSIsImFtciI6WyJwd2QiXSwiaWRwIjoiMDBveTc0YzBnd0hOWE1SSkJGUkkiLCJub25jZSI6Im4tMFM2X1d6QTJNaiIsInByZWZlcnJlZF91c2VybmFtZSI6Im9rdGFwcm94eUBva3RhLmNvbSIsImF1dGhfdGltZSI6MTQ4MTM4ODQ0MywiYXRfaGFzaCI6Im1YWlQtZjJJczhOQklIcV9CeE1ISFEifQ.OtVyCK0sE6Cuclg9VMD2AwLhqEyq2nv3a1bfxlzeS-bdu9KtYxcPSxJ6vxMcSSbMIIq9eEz9JFMU80zqgDPHBCjlOsC5SIPz7mm1Z3gCwq4zsFJ-2NIzYxA3p161ZRsPv_3bUyg9B_DPFyBoihgwWm6yrvrb4rmHXrDkjxpxCLPp3OeIpc_kb2t8r5HEQ5UBZPrsiScvuoVW13YwWpze59qBl_84n9xdmQ5pS7DklzkAVgqJT_NWBlb5uo6eW26HtJwHzss7xOIdQtcOtC1Gj3O82a55VJSQnsEEBeqG1ESb5Haq_hJgxYQnBssKydPCIxdZiye-0Ll9L8wWwpzwig
以下是关键:

{
   "keys":[
      {
         "alg":"RS256",
         "e":"AQAB",
         "n":"ok6rvXu95337IxsDXrKzlIqw_I_zPDG8JyEw2CTOtNMoDi1QzpXQVMGj2snNEmvNYaCTmFf51I-EDgeFLLexr40jzBXlg72quV4aw4yiNuxkigW0gMA92OmaT2jMRIdDZM8mVokoxyPfLub2YnXHFq0XuUUgkX_TlutVhgGbyPN0M12teYZtMYo2AUzIRggONhHvnibHP0CPWDjCwSfp3On1Recn4DPxbn3DuGslF2myalmCtkujNcrhHLhwYPP-yZFb8e0XSNTcQvXaQxAqmnWH6NXcOtaeWMQe43PNTAyNinhndgI8ozG3Hz-1NzHssDH_yk6UYFSszhDbWAzyqw",
         "kid":"wyMwK4A6CL9Qw11uofVeyQ119XyX-xykymkkXygZ5OM",
         "kty":"RSA",
         "use":"sig"
      },
      {
         "alg":"RS256",
         "e":"AQAB",
         "n":"nXv6FSAcMjuanQ2hIIUb8Vkqe94t98kPh2T8-0j6-Jq8pOclgKdtVeIZcBE9F_XiuJvg4b6WVs-uvA-pS8mmMvQ21xU5Q_37Cojv8v_QlHWETHwEJdXXiY2Xq5LgXDSwEhhdDZHSMQYDuvhp_P6nl2LNqqUvJkjoFWcnn2btgSIUQROIaDdxtx7_2h4oUi5u11BGSF2SZZiEpDAKT08Htv3uwXdwDA6ll99fbi8X8RmH5oY_tIZTeIzu50qHxElPewoYO8QrJYsO9oFcCPMHGxYWjXQEa-QZYgo0wS9zRIkeJc5kshc4-9Uhv2DVIjk_-ofGlML9ieggGyillBKptw",
         "kid":"GRF55Lbzgg4sANCmER-sm55eX_qUOpY8UTptDmDG_6U",
         "kty":"RSA",
         "use":"sig"
      }
   ]
}

下面是JWT解码和验证的示例。它同时使用和包:

package main

import (
    "errors"
    "fmt"

    "github.com/dgrijalva/jwt-go"
    "github.com/lestrrat-go/jwx/jwk"
)

const token = `eyJhbGciOiJSUzI1NiIsImtpZCI6Ind5TXdLNEE2Q0w5UXcxMXVvZlZleVExMTlYeVgteHlreW1ra1h5Z1o1T00ifQ.eyJzdWIiOiIwMHUxOGVlaHUzNDlhUzJ5WDFkOCIsIm5hbWUiOiJva3RhcHJveHkgb2t0YXByb3h5IiwidmVyIjoxLCJpc3MiOiJodHRwczovL2NvbXBhbnl4Lm9rdGEuY29tIiwiYXVkIjoidlpWNkNwOHJuNWx4ck45YVo2ODgiLCJpYXQiOjE0ODEzODg0NTMsImV4cCI6MTQ4MTM5MjA1MywianRpIjoiSUQuWm9QdVdIR3IxNkR6a3RUbEdXMFI4b1lRaUhnVWg0aUotTHo3Z3BGcGItUSIsImFtciI6WyJwd2QiXSwiaWRwIjoiMDBveTc0YzBnd0hOWE1SSkJGUkkiLCJub25jZSI6Im4tMFM2X1d6QTJNaiIsInByZWZlcnJlZF91c2VybmFtZSI6Im9rdGFwcm94eUBva3RhLmNvbSIsImF1dGhfdGltZSI6MTQ4MTM4ODQ0MywiYXRfaGFzaCI6Im1YWlQtZjJJczhOQklIcV9CeE1ISFEifQ.OtVyCK0sE6Cuclg9VMD2AwLhqEyq2nv3a1bfxlzeS-bdu9KtYxcPSxJ6vxMcSSbMIIq9eEz9JFMU80zqgDPHBCjlOsC5SIPz7mm1Z3gCwq4zsFJ-2NIzYxA3p161ZRsPv_3bUyg9B_DPFyBoihgwWm6yrvrb4rmHXrDkjxpxCLPp3OeIpc_kb2t8r5HEQ5UBZPrsiScvuoVW13YwWpze59qBl_84n9xdmQ5pS7DklzkAVgqJT_NWBlb5uo6eW26HtJwHzss7xOIdQtcOtC1Gj3O82a55VJSQnsEEBeqG1ESb5Haq_hJgxYQnBssKydPCIxdZiye-0Ll9L8wWwpzwig`

const jwksURL = `https://companyx.okta.com/oauth2/v1/keys`

func getKey(token *jwt.Token) (interface{}, error) {

    // TODO: cache response so we don't have to make a request every time
    // we want to verify a JWT
    set, err := jwk.FetchHTTP(jwksURL)
    if err != nil {
        return nil, err
    }

    keyID, ok := token.Header["kid"].(string)
    if !ok {
        return nil, errors.New("expecting JWT header to have string kid")
    }

    if key := set.LookupKeyID(keyID); len(key) == 1 {
        return key[0].Materialize()
    }

    return nil, fmt.Errorf("unable to find key %q", keyID)
}

func main() {
    token, err := jwt.Parse(token, getKey)
    if err != nil {
        panic(err)
    }
    claims := token.Claims.(jwt.MapClaims)
    for key, value := range claims {
        fmt.Printf("%s\t%v\n", key, value)
    }
}

我最近有一个非常类似的用例,所以我通读了一些RFC并编写了这个包:

它允许您使用最流行的JWT包来解析令牌。它还可以在后台goroutine中自动实时重新加载JWKS的内容

使用JWKS和JWT,这里有两个示例。第一个将通过HTTPS从远程URL加载JWKS。第二个将从静态JSON加载它

来自通过HTTPS托管的JWKS
主程序包
进口(
“日志”
“时间”
“github.com/dgrijalva/jwt go”
“github.com/MicahParks/keyfunc”
)
func main(){
//获取JWKS URL。
jwksURL:=”https://companyx.okta.com/oauth2/v1/keys"
//创建keyfunc选项。每小时刷新一次JWKS并记录错误。
刷新间隔:=时间。小时
选项:=keyfunc.options{
刷新间隔:&刷新间隔,
RefreshErrorHandler:func(错误错误){
log.Printf(“jwt.KeyFunc\n错误:%s”,err.error()
},
}
//从给定URL处的资源创建JWKS。
jwks,err:=keyfunc.Get(jwksURL,选项)
如果错误!=零{
log.Fatalf(“无法从给定URL的资源创建JWKS。\n错误:%s”,err.Error())
}
//获取要解析的JWT。
jwtB64:="EyjhbgcioizizlIfq.EyjbgciozizizizlIfq.Eyjzdwiiwwwuxvezizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizi2.本研究的目的是研究一个关于某一问题的研究的结果,或者是一个关于某一问题的研究,或者是一个关于某一问题的研究,或者是一个关于某一问题的研究,或者是一个关于某一问题的研究,或者是一个关于某一问题的研究,或者是一个关于某一问题的研究,或者是一个关于某一个非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非PHBCJLOSC5SIPz7mm1Z3gCwq4zsFJ-2NIzYxA3p161ZRsPv-3bUyg9B-DPFYBOIHWWM6YRVRB4RMHXRDKJXPXCLPP3OEIPC-KB2T8HEQ5UBZPRSISCVUOVW13YWWPZE59QBL-84n9xdmQ5pS7DklzkAVgqJT-NWBLB5UO6HTJWHZS7XOIDQTCOTCC1GJ3O825JSQ5JSQ2EB5JZQQQQ8EQQQ8WWWWW9WW9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W
//解析JWT。
令牌,err:=jwt.Parse(jwtB64,jwks.KeyFunc)
如果错误!=零{
log.Fatalf(“未能分析JWT。\n错误:%s”,err.Error())
}
//检查令牌是否有效。
if!token.Valid{
log.Fatalf(“令牌无效。”)
}
Println(“令牌有效”)
}
从JWKS到JSON
主程序包
进口(
“编码/json”
“日志”
“github.com/dgrijalva/jwt go”
“github.com/MicahParks/keyfunc”
)
func main(){
//将JWKS作为JSON获取。
var jwksJSON.RawMessage=[]字节(`{“keys”:[{“alg”:“RS256”,“e”:“AQAB”,“n”:”2.文中给出了一个关于某一方面的一个关于某一方面的文中给出了一个关于某一方面的文中给出了一个关于某一方面的文中给出了一个关于某一方面的文中给出了一个关于某一方面的文中给出了一个关于某一方面的文中给出了一个关于某一方面的文中给出了一个关于某一方面的文中的文中给出了一个关于某一方面的文中关于某一方面的边缘化边缘化边缘化边缘化边缘化边缘化边缘化边缘化的文章,或者某一ZZZZZBXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX“:“WYMWK4A6CL9QW11OFVEYQ119XYX-xykymkkXygZ5OM”,“kty:“RSA”,“use:“sig”},{“alg:“RS256”,“e:“AQAB”,“n:”2.中国的一个六六级考试的一个六级考试的一个六级考试的一个六级考试的一个六级考试的一个六级考试的一个六级考试的一个六级考试的一个六级考试的一个六级考试的一个六级考试的一个六级考试的一个六级考试的一个六级考试的一个六级考试的一个六级考试的一个六级考试的一个六级考试的一个六级考试的六级考试的六级考试的一个六级考试的六级考试,一级考试的一级考试的六级考试的一级考试的六级考试的六级考试的六级考试的六级考试的六级考试的一级考试的六级考试的一级考试的一级考试的一级考试的六级考试的一级考试的一级考试的一级考试的一级考试的一级考试的一级考试的一级考试的一级考试的一级考试的一级考试的一级考试的KSHC4-9Uhv2DVIjk_u2;-ofGlML9ieggGyillBKptw,“儿童“:“GRF55Lbzgg4sANCmER-sm55eX_qUOpY8UTptDmDG_6U”,“kty”:“RSA”,“use”:“sig”}]}`)
//从给定URL处的资源创建JWKS。
jwks,err:=keyfunc.New(jwksJSON)
如果错误!=零{
log.Fatalf(“无法从给定URL的资源创建JWKS。\n错误:%s”,err.Error())
}
//获取要解析的JWT。
jwtB64:="EyjhbgcioizizlIfq.EyjbgciozizizizlIfq.Eyjzdwiiwwwuxvezizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizizi2.本研究的目的是研究一个关于某一问题的研究的结果,或者是一个关于某一问题的研究,或者是一个关于某一问题的研究,或者是一个关于某一问题的研究,或者是一个关于某一问题的研究,或者是一个关于某一问题的研究,或者是一个关于某一问题的研究,或者是一个关于某一个非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非非PHBCJLOSC5SIPz7mm1Z3gCwq4zsFJ-2NIzYxA3p161ZRsPv-3bUyg9B-DPFYBOIHWWM6YRVRB4RMHXRDKJXPXCLPP3OEIPC-KB2T8HEQ5UBZPRSISCVUOVW13YWWPZE59QBL-84n9xdmQ5pS7DklzkAVgqJT-NWBLB5UO6HTJWHZS7XOIDQTCOTCC1GJ3O825JSQ5JSQ2EB5JZQQQQ8EQQQ8WWWWW9WW9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W9W
//解析JWT。
令牌,err:=jwt.Parse(jwtB64,jwks.KeyFunc)
如果错误!=零{
log.Fatalf(“未能分析JWT。\n错误:%s”,err.Error())
}
//检查令牌是否有效。
if!token.Valid{
日志