Golang实现OIDC资源服务器完整教程
概述
OIDC(OpenID Connect)资源服务器负责保护API资源,验证访问令牌并授权客户端访问。
核心组件
1. 依赖包
import (
"context"
"fmt"
"net/http"
"github.com/coreos/go-oidc/v3/oidc"
"golang.org/x/oauth2"
)
2. 配置OIDC提供者
func setupOIDCProvider(issuerURL string) (*oidc.Provider, error) {
ctx := context.Background()
provider, err := oidc.NewProvider(ctx, issuerURL)
if err != nil {
return nil, fmt.Errorf("failed to create provider: %v", err)
}
return provider, nil
}
3. 中间件验证令牌
func authMiddleware(verifier *oidc.IDTokenVerifier) 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 required", http.StatusUnauthorized)
return
}
// 提取Bearer令牌
token := strings.TrimPrefix(authHeader, "Bearer ")
if token == authHeader {
http.Error(w, "Bearer token required", http.StatusUnauthorized)
return
}
// 验证令牌
idToken, err := verifier.Verify(r.Context(), token)
if err != nil {
http.Error(w, "Invalid token", http.StatusUnauthorized)
return
}
// 将令牌信息存入上下文
ctx := context.WithValue(r.Context(), "idToken", idToken)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
4. 资源服务器主程序
func main() {
// 配置OIDC提供者
provider, err := setupOIDCProvider("https://your-oidc-provider.com")
if err != nil {
panic(err)
}
// 创建令牌验证器
verifier := provider.Verifier(&oidc.Config{
ClientID: "your-client-id",
})
// 创建路由
mux := http.NewServeMux()
// 受保护的路由
mux.Handle("/api/protected", authMiddleware(verifier)(
http.HandlerFunc(protectedHandler),
))
// 启动服务器
fmt.Println("Server starting on :8080")
http.ListenAndServe(":8080", mux)
}
func protectedHandler(w http.ResponseWriter, r *http.Request) {
// 从上下文中获取令牌信息
idToken := r.Context().Value("idToken").(*oidc.IDToken)
var claims struct {
Email string `json:"email"`
Name string `json:"name"`
}
if err := idToken.Claims(&claims); err != nil {
http.Error(w, "Failed to parse claims", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, `{"message": "Hello %s!", "email": "%s"}`, claims.Name, claims.Email)
}
5. 完整配置示例
// config.go
type Config struct {
OIDCIssuer string
ClientID string
ClientSecret string
RedirectURL string
}
func LoadConfig() *Config {
return &Config{
OIDCIssuer: "https://your-oidc-provider.com",
ClientID: "your-client-id",
ClientSecret: "your-client-secret",
RedirectURL: "http://localhost:8080/callback",
}
}
部署步骤
- 安装依赖:
go mod init oidc-resource-server
go get github.com/coreos/go-oidc/v3/oidc
go get golang.org/x/oauth2
- 配置OIDC提供者信息
- 运行服务器:
go run main.go
测试
使用有效的访问令牌访问受保护端点:
curl -H "Authorization: Bearer <your-access-token>" http://localhost:8080/api/protected
这个实现提供了基本的OIDC资源服务器功能,包括令牌验证和声明提取。根据具体需求,可以扩展添加角色验证、范围检查等高级功能。