fix: finalize oauth identity bindings

This commit is contained in:
IanShaw027
2026-04-20 21:24:33 +08:00
parent bdcd3d87e5
commit 5adefb466b
4 changed files with 376 additions and 7 deletions

View File

@@ -242,7 +242,18 @@ func (h *AuthHandler) WeChatOAuthCallback(c *gin.Context) {
redirectOAuthError(c, frontendCallback, "session_error", infraerrors.Reason(err), infraerrors.Message(err))
return
}
if existingIdentityUser == nil {
existingIdentityUser, err = h.findWeChatUserByLegacyOpenID(c.Request.Context(), identityRef, cfg, openid)
if err != nil {
redirectOAuthError(c, frontendCallback, "session_error", infraerrors.Reason(err), infraerrors.Message(err))
return
}
}
if existingIdentityUser != nil {
if err := h.ensureWeChatRuntimeIdentityBinding(c.Request.Context(), existingIdentityUser.ID, identityRef, upstreamClaims); err != nil {
redirectOAuthError(c, frontendCallback, "session_error", infraerrors.Reason(err), infraerrors.Message(err))
return
}
tokenPair, user, err := h.authService.LoginOrRegisterOAuthWithTokenPair(c.Request.Context(), existingIdentityUser.Email, username, "")
if err != nil {
redirectOAuthError(c, frontendCallback, "login_failed", infraerrors.Reason(err), infraerrors.Message(err))
@@ -511,6 +522,91 @@ func (h *AuthHandler) ensureWeChatBindOwnership(
return nil
}
func (h *AuthHandler) findWeChatUserByLegacyOpenID(
ctx context.Context,
identity service.PendingAuthIdentityKey,
cfg wechatOAuthConfig,
openid string,
) (*dbent.User, error) {
client := h.entClient()
if client == nil {
return nil, infraerrors.ServiceUnavailable("PENDING_AUTH_NOT_READY", "pending auth service is not ready")
}
openid = strings.TrimSpace(openid)
channel := strings.TrimSpace(cfg.mode)
channelAppID := strings.TrimSpace(cfg.appID)
if openid != "" && channel != "" && channelAppID != "" {
record, err := client.AuthIdentityChannel.Query().
Where(
authidentitychannel.ProviderTypeEQ(strings.TrimSpace(identity.ProviderType)),
authidentitychannel.ProviderKeyEQ(strings.TrimSpace(identity.ProviderKey)),
authidentitychannel.ChannelEQ(channel),
authidentitychannel.ChannelAppIDEQ(channelAppID),
authidentitychannel.ChannelSubjectEQ(openid),
).
WithIdentity(func(q *dbent.AuthIdentityQuery) {
q.WithUser()
}).
Only(ctx)
if err != nil && !dbent.IsNotFound(err) {
return nil, infraerrors.InternalServer("AUTH_IDENTITY_CHANNEL_LOOKUP_FAILED", "failed to inspect auth identity channel ownership").WithCause(err)
}
if record != nil && record.Edges.Identity != nil && record.Edges.Identity.Edges.User != nil {
return record.Edges.Identity.Edges.User, nil
}
}
if openid == "" {
return nil, nil
}
record, err := client.AuthIdentity.Query().
Where(
authidentity.ProviderTypeEQ(strings.TrimSpace(identity.ProviderType)),
authidentity.ProviderKeyEQ(strings.TrimSpace(identity.ProviderKey)),
authidentity.ProviderSubjectEQ(openid),
).
WithUser().
Only(ctx)
if err != nil {
if dbent.IsNotFound(err) {
return nil, nil
}
return nil, infraerrors.InternalServer("AUTH_IDENTITY_LOOKUP_FAILED", "failed to inspect auth identity ownership").WithCause(err)
}
return record.Edges.User, nil
}
func (h *AuthHandler) ensureWeChatRuntimeIdentityBinding(
ctx context.Context,
userID int64,
identity service.PendingAuthIdentityKey,
upstreamClaims map[string]any,
) error {
client := h.entClient()
if client == nil {
return infraerrors.ServiceUnavailable("PENDING_AUTH_NOT_READY", "pending auth service is not ready")
}
tx, err := client.Tx(ctx)
if err != nil {
return infraerrors.InternalServer("AUTH_IDENTITY_BIND_FAILED", "failed to begin wechat identity repair transaction").WithCause(err)
}
defer func() { _ = tx.Rollback() }()
_, err = ensurePendingOAuthIdentityForUser(dbent.NewTxContext(ctx, tx), tx, &dbent.PendingAuthSession{
ProviderType: strings.TrimSpace(identity.ProviderType),
ProviderKey: strings.TrimSpace(identity.ProviderKey),
ProviderSubject: strings.TrimSpace(identity.ProviderSubject),
UpstreamIdentityClaims: cloneOAuthMetadata(upstreamClaims),
}, userID)
if err != nil {
return err
}
return tx.Commit()
}
func (h *AuthHandler) getWeChatOAuthConfig(ctx context.Context, rawMode string, c *gin.Context) (wechatOAuthConfig, error) {
mode, err := resolveWeChatOAuthMode(rawMode, c)
if err != nil {