如何实现Kratos与Microsoft Azure的单点登出功能?
解决Azure AD前端登出同步Kratos会话的问题
核心思路
Azure AD前端登出请求携带的sid是Azure侧的会话ID,需要先在Kratos中建立该sid与Kratos用户会话的关联,再通过Kratos管理员API安全删除对应会话。
步骤1:配置Kratos捕获Azure AD的sid Claim
在Kratos的OIDC身份提供商配置中,确保获取并存储Azure AD返回的sid Claim。修改Kratos的OIDC provider配置(通常在identity.schema.json或对应OIDC配置文件中):
{ "id": "microsoft", "provider": "oidc", "config": { "issuer_url": "https://login.microsoftonline.com/[tenant-id]/v2.0", "client_id": "[your-client-id]", "client_secret": "[your-client-secret]", "scopes": ["openid", "profile", "email"], "claims": { "sid": { "mapping": "traits.microsoft.sid", "required": true } } } }
配置完成后,Kratos会将Azure的sid存储到用户的traits.microsoft.sid字段中。
步骤2:用Go后端处理Azure的前端登出请求
在你的Go服务中创建接口(比如/auth/azure/logout)接收Azure的GET请求,提取sid参数后执行会话删除操作:
import ( "context" "fmt" "net/http" "github.com/ory/kratos-client-go" ) func handleAzureFrontchannelLogout(w http.ResponseWriter, r *http.Request) { // 提取Azure传入的sid参数 sid := r.URL.Query().Get("sid") if sid == "" { w.WriteHeader(http.StatusBadRequest) return } // 初始化Kratos Admin客户端 config := kratos.NewConfiguration() config.Servers = []kratos.ServerConfiguration{{URL: "http://kratos-host:4433"}} client := kratos.NewAPIClient(config) // 携带Kratos Admin Token,绕过CSRF验证 adminCtx := context.WithValue(r.Context(), kratos.ContextAPIKey, kratos.APIKey{ Key: "[your-kratos-admin-token]", // 从Kratos配置中获取ADMIN_TOKEN }) // 查询匹配sid的Kratos用户 listParams := client.IdentityApi.ListIdentities(adminCtx) listParams = listParams.TraitsQuery(fmt.Sprintf("traits.microsoft.sid=\"%s\"", sid)) identities, _, err := client.IdentityApi.ListIdentitiesExecute(listParams) if err != nil || len(identities) == 0 { w.WriteHeader(http.StatusNotFound) return } // 删除该用户的所有Kratos会话 for _, identity := range identities { sessions, _, err := client.SessionApi.ListSessionsForIdentity(adminCtx, identity.Id).Execute() if err != nil { continue } for _, session := range sessions { _, err := client.SessionApi.DeleteSession(adminCtx, session.Id).Execute() if err != nil { // 此处可添加错误日志记录 } } } // 返回200给Azure,确认登出处理完成 w.WriteHeader(http.StatusOK) }
关键注意事项
- 必须使用Kratos的Admin API并携带管理员Token,这样可以绕过CSRF验证(管理员接口无需CSRF Token)。
- 如果用户存在多设备登录的情况,上述逻辑会删除该用户的所有Kratos会话,确保完全同步登出状态。
- 确保处理登出请求的Go接口可以被Azure的iframe请求访问(无CORS限制)。
替代方案(无需捕获sid)
如果不想配置Kratos存储sid,可以通过Azure用户的固定sub(主题ID)关联用户:
- Kratos默认会将Azure用户的
sub存储在identity.credentials.oauth2[].subject中。 - 查询用户时通过
credentials.oauth2.subject筛选,再删除该用户的所有会话。这种方式会删除用户所有Kratos会话,而非仅关联当前Azure sid的会话。
内容的提问来源于stack exchange,提问作者popstr
相关产品推荐
相关产品推荐

