本文档介绍如何在 Go 应用程序中集成 OpenID Connect (OIDC) 身份验证功能。OIDC 是基于 OAuth 2.0 协议的身份验证层,提供了标准化的用户身份验证和授权流程。
我们提供的provider是oidc.ctf.icu
Note
如果您不需要限定某一应用的用户范围,请不要给应用指定Group,Group为空即是允许所有人通过
如果您的应用只允许某一特定的团体才能通过,请务必指定Group(Group可以一次性指定多个)
目前我们强制使用Totp进行用户验证,我们放弃了传统的密码验证,以此来保证用户身份的安全性
语言: Go
依赖库
github.com/coreos/go-oidc/v3/oidc
- OIDC 客户端库
golang.org/x/oauth2
- OAuth2 客户端库
协议: OpenID Connect 1.0
OIDC Provider 是身份提供方,负责用户认证和令牌颁发。
x
provider, err := oidc.NewProvider(ctx, "https://oidc.ctf.icu")
if err != nil {
log.Fatalf("Failed to create provider: %v", err)
}
配置 OAuth2 客户端参数,包括客户端凭据、重定向 URL 和请求范围。
xxxxxxxxxx
config := oauth2.Config{
ClientID: "default-test",
ClientSecret: "test",
RedirectURL: "http://localhost:8081/callback",
Endpoint: provider.Endpoint(),
Scopes: []string{oidc.ScopeOpenID, "profile", "email"},
}
创建用于验证 ID Token 的验证器实例。
xxxxxxxxxx
verifier := provider.Verifier(&oidc.Config{
ClientID: "default-client",
})
用户访问根路径时,应用程序会重定向到 OIDC Provider 的授权端点。
xxxxxxxxxx
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, config.AuthCodeURL("state-token", oauth2.AccessTypeOnline), http.StatusFound)
})
用户完成身份验证后,OIDC Provider 会重定向回应用程序的回调端点。
xxxxxxxxxx
if r.URL.Query().Get("state") != "state-token" {
http.Error(w, "Invalid state", http.StatusBadRequest)
return
}
使用授权码换取访问令牌和 ID Token。
xxxxxxxxxx
token, err := config.Exchange(ctx, r.URL.Query().Get("code"))
if err != nil {
http.Error(w, "Failed to exchange token: "+err.Error(), http.StatusInternalServerError)
return
}
xxxxxxxxxx
rawIDToken, ok := token.Extra("id_token").(string)
if !ok {
http.Error(w, "No id_token field in token response", http.StatusInternalServerError)
return
}
idToken, err := verifier.Verify(ctx, rawIDToken)
if err != nil {
http.Error(w, "Failed to verify ID token: "+err.Error(), http.StatusInternalServerError)
return
}
xxxxxxxxxx
var claims struct {
Name string `json:"name"`
Email string `json:"email"`
UserId int64 `json:"userId"`
}
if err := idToken.Claims(&claims); err != nil {
http.Error(w, "Failed to parse claims: "+err.Error(), http.StatusInternalServerError)
return
}
参数 | 描述 | 示例值 |
---|---|---|
ClientID | OIDC 客户端标识符 | default-test |
ClientSecret | OIDC 客户端密钥 | test |
RedirectURL | 授权后的重定向地址 | http://localhost:8081/callback |
Scopes | 请求的权限范围 | ["openid", "profile", "email"] |
状态参数用于防止 CSRF 攻击,必须在授权请求和回调处理中保持一致。
xxxxxxxxxx
// 发起请求时设置状态
authURL := config.AuthCodeURL("state-token", oauth2.AccessTypeOnline)
// 回调时验证状态
if r.URL.Query().Get("state") != "state-token" {
// 处理错误
}
所有 ID Token 都必须经过验证以确保其有效性和完整性。
xxxxxxxxxx
idToken, err := verifier.Verify(ctx, rawIDToken)
为 HTTP 服务器设置合理的超时时间以防止资源耗尽。
xxxxxxxxxx
srv := &http.Server{
Addr: ":8081",
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
}
上述代码示例展示了完整的 OIDC 集成流程,包括:
OIDC Provider 初始化
OAuth2 客户端配置
授权请求处理
回调处理和令牌验证
用户信息提取
确保已安装必要的依赖包
配置正确的 OIDC Provider URL 和客户端凭据
运行应用程序:go run main.go
访问 http://localhost:8081
开始身份验证流程
Provider 创建失败: 检查 OIDC Provider URL 是否正确且可访问
令牌交换失败: 验证客户端凭据和重定向 URL 配置
ID Token 验证失败: 确认客户端 ID 配置正确
Claims 解析失败: 检查声明结构体字段与实际返回数据的匹配性
启用详细日志记录
检查网络连接和防火墙设置
验证 OIDC Provider 的配置信息
使用工具如 Postman 或 curl 测试 API 端点
基于此基础实现,可以进一步扩展以下功能:
会话管理
令牌刷新
登出功能
多 Provider 支持
用户角色和权限管理