简而言之:使用go-oidc
长长的答案:
首先,让我们了解一下Spring Security如何自动验证作为JWT的访问令牌.按照惯例,如果您在application.yaml
配置文件中定义OAuth 2.0或OIDC客户端属性,则Spring将自动连接安全筛选器链中的一个筛选器,该筛选器从Keyshaak获取jwk-set
,这是一组公钥,对应于Keyloak用来签署令牌的私钥.此过滤器将应用于所有受保护的路由,并且Spring将使用公钥来判断令牌的签名是否有效,并在适用的情况下进行其他判断(受众、超时等)
那么,我们如何在Go中做到这一点呢?我们可以编写一个简单的中间件,它接受jwk-set
并使用它来验证令牌.您需要解码令牌,确认iss
和sub
声明以确保它来自可信的发行者和目标受众,判断它是否尚未过期,然后判断alg
声明以查看使用了哪种签名算法,从jwk-set
中 Select 相应的公钥并判断签名是否有效.
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)
})
}
}