我正在尝试使用 GO 实现访问令牌验证。但我在网上看到的例子似乎只是用 TOKEN_SECRET 来验证它。但是我习惯了在Java spring中编程,并且不需要使用TOKEN_SECRET。我只是提供 jwk-set-uri 并检查有效性(自动 - 安全过滤器等)我知道它与 oauth 服务器通信并进行此验证。
Go 中是否没有库可以检查向 oauth 服务器发出请求时令牌是否有效?
我知道我可以通过向 oauth 服务器的用户信息端点发出请求来手动进行操作:
http://localhost:8080/auth/realms/<your_realm>/protocol/openid-connect/userinfo
(在具有密钥授权的标头中包含令牌)
但我不知道这是否完全符合标准。
正确的做法是什么?
简短回答:使用 go-oidc
长答案: 首先,让我们了解 Spring Security 如何自动验证 JWT 访问令牌。按照惯例,如果您在
application.yaml
配置文件中定义 OAuth 2.0 或 OIDC 客户端属性,Spring 将自动在安全过滤器链中连接一个过滤器,从 Keycloak 中获取 jwk-set
,这是一组与私钥对应的公钥Keycloak 使用它来签署令牌。该过滤器将应用于所有受保护的路由,并且 spring 将使用公钥来检查令牌的签名是否有效,并在适用时进行额外的检查(受众、超时等...)
那么我们如何在 Go 中做到这一点呢?我们可以编写一个简单的中间件来接受
jwk-set
并使用它来验证令牌。您需要解码令牌,确认 iss
和 sub
声明,以确保它来自受信任的发行者并且针对目标受众,检查它是否尚未过期,然后检查 alg
声明以了解哪个使用了签名算法,从jwk-set
中选择相应的公钥并检查签名是否有效。
func JWTMiddleware(jwkSet map[string]*rsa.PublicKey) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
http.Error(w, "Authorization header is required", http.StatusUnauthorized)
return
}
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
alg := token.Method.Alg()
publicKey, ok := jwkSet[alg]
if !ok {
return nil, fmt.Errorf("no key found for signing method: %v", alg)
}
return publicKey, nil
})
// Other checks, ISS, Aud, Expirey etc ...
if err != nil || !token.Valid {
http.Error(w, "Invalid token", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
})
}
}