fix: normalize legacy wechat auth identity keys

This commit is contained in:
IanShaw027
2026-04-20 21:42:35 +08:00
parent f65429145e
commit 422f60a145
4 changed files with 464 additions and 48 deletions

View File

@@ -34,6 +34,7 @@ const (
wechatOAuthDefaultRedirectTo = "/dashboard"
wechatOAuthDefaultFrontendCB = "/auth/wechat/callback"
wechatOAuthProviderKey = "wechat-main"
wechatOAuthLegacyProviderKey = "wechat"
wechatOAuthIntentLogin = "login"
wechatOAuthIntentBind = "bind_current_user"
@@ -483,18 +484,20 @@ func (h *AuthHandler) ensureWeChatBindOwnership(
return infraerrors.ServiceUnavailable("PENDING_AUTH_NOT_READY", "pending auth service is not ready")
}
identity, err := client.AuthIdentity.Query().
identities, err := client.AuthIdentity.Query().
Where(
authidentity.ProviderTypeEQ("wechat"),
authidentity.ProviderKeyEQ(wechatOAuthProviderKey),
authidentity.ProviderKeyIn(wechatCompatibleProviderKeys(wechatOAuthProviderKey)...),
authidentity.ProviderSubjectEQ(strings.TrimSpace(providerSubject)),
).
Only(ctx)
if err != nil && !dbent.IsNotFound(err) {
All(ctx)
if err != nil {
return infraerrors.InternalServer("WECHAT_BIND_LOOKUP_FAILED", "failed to inspect wechat identity ownership").WithCause(err)
}
if identity != nil && identity.UserID != userID {
return infraerrors.Conflict("AUTH_IDENTITY_OWNERSHIP_CONFLICT", "auth identity already belongs to another user")
for _, identity := range identities {
if identity != nil && identity.UserID != userID {
return infraerrors.Conflict("AUTH_IDENTITY_OWNERSHIP_CONFLICT", "auth identity already belongs to another user")
}
}
channelSubject = strings.TrimSpace(channelSubject)
@@ -503,21 +506,23 @@ func (h *AuthHandler) ensureWeChatBindOwnership(
return nil
}
channel, err := client.AuthIdentityChannel.Query().
channels, err := client.AuthIdentityChannel.Query().
Where(
authidentitychannel.ProviderTypeEQ("wechat"),
authidentitychannel.ProviderKeyEQ(wechatOAuthProviderKey),
authidentitychannel.ProviderKeyIn(wechatCompatibleProviderKeys(wechatOAuthProviderKey)...),
authidentitychannel.ChannelEQ(strings.TrimSpace(cfg.mode)),
authidentitychannel.ChannelAppIDEQ(channelAppID),
authidentitychannel.ChannelSubjectEQ(channelSubject),
).
WithIdentity().
Only(ctx)
if err != nil && !dbent.IsNotFound(err) {
All(ctx)
if err != nil {
return infraerrors.InternalServer("WECHAT_BIND_CHANNEL_LOOKUP_FAILED", "failed to inspect wechat identity channel ownership").WithCause(err)
}
if channel != nil && channel.Edges.Identity != nil && channel.Edges.Identity.UserID != userID {
return infraerrors.Conflict("AUTH_IDENTITY_CHANNEL_OWNERSHIP_CONFLICT", "auth identity channel already belongs to another user")
for _, channel := range channels {
if channel != nil && channel.Edges.Identity != nil && channel.Edges.Identity.UserID != userID {
return infraerrors.Conflict("AUTH_IDENTITY_CHANNEL_OWNERSHIP_CONFLICT", "auth identity channel already belongs to another user")
}
}
return nil
}
@@ -533,14 +538,34 @@ func (h *AuthHandler) findWeChatUserByLegacyOpenID(
return nil, infraerrors.ServiceUnavailable("PENDING_AUTH_NOT_READY", "pending auth service is not ready")
}
providerType := strings.TrimSpace(identity.ProviderType)
providerSubject := strings.TrimSpace(identity.ProviderSubject)
providerKeys := wechatCompatibleProviderKeys(identity.ProviderKey)
if providerSubject != "" {
records, err := client.AuthIdentity.Query().
Where(
authidentity.ProviderTypeEQ(providerType),
authidentity.ProviderKeyIn(providerKeys...),
authidentity.ProviderSubjectEQ(providerSubject),
).
WithUser().
All(ctx)
if err != nil {
return nil, infraerrors.InternalServer("AUTH_IDENTITY_LOOKUP_FAILED", "failed to inspect auth identity ownership").WithCause(err)
}
if user, err := singleWeChatIdentityUser(records); err != nil || user != nil {
return user, err
}
}
openid = strings.TrimSpace(openid)
channel := strings.TrimSpace(cfg.mode)
channelAppID := strings.TrimSpace(cfg.appID)
if openid != "" && channel != "" && channelAppID != "" {
record, err := client.AuthIdentityChannel.Query().
records, err := client.AuthIdentityChannel.Query().
Where(
authidentitychannel.ProviderTypeEQ(strings.TrimSpace(identity.ProviderType)),
authidentitychannel.ProviderKeyEQ(strings.TrimSpace(identity.ProviderKey)),
authidentitychannel.ProviderTypeEQ(providerType),
authidentitychannel.ProviderKeyIn(providerKeys...),
authidentitychannel.ChannelEQ(channel),
authidentitychannel.ChannelAppIDEQ(channelAppID),
authidentitychannel.ChannelSubjectEQ(openid),
@@ -548,12 +573,12 @@ func (h *AuthHandler) findWeChatUserByLegacyOpenID(
WithIdentity(func(q *dbent.AuthIdentityQuery) {
q.WithUser()
}).
Only(ctx)
if err != nil && !dbent.IsNotFound(err) {
All(ctx)
if err != nil {
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 user, err := singleWeChatChannelUser(records); err != nil || user != nil {
return user, err
}
}
@@ -561,21 +586,64 @@ func (h *AuthHandler) findWeChatUserByLegacyOpenID(
return nil, nil
}
record, err := client.AuthIdentity.Query().
records, err := client.AuthIdentity.Query().
Where(
authidentity.ProviderTypeEQ(strings.TrimSpace(identity.ProviderType)),
authidentity.ProviderKeyEQ(strings.TrimSpace(identity.ProviderKey)),
authidentity.ProviderTypeEQ(providerType),
authidentity.ProviderKeyIn(providerKeys...),
authidentity.ProviderSubjectEQ(openid),
).
WithUser().
Only(ctx)
All(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
return singleWeChatIdentityUser(records)
}
func wechatCompatibleProviderKeys(providerKey string) []string {
preferred := strings.TrimSpace(providerKey)
if preferred == "" {
preferred = wechatOAuthProviderKey
}
keys := []string{preferred}
if !strings.EqualFold(preferred, wechatOAuthLegacyProviderKey) {
keys = append(keys, wechatOAuthLegacyProviderKey)
}
return keys
}
func singleWeChatIdentityUser(records []*dbent.AuthIdentity) (*dbent.User, error) {
var resolved *dbent.User
for _, record := range records {
if record == nil || record.Edges.User == nil {
continue
}
if resolved == nil {
resolved = record.Edges.User
continue
}
if resolved.ID != record.Edges.User.ID {
return nil, infraerrors.Conflict("AUTH_IDENTITY_OWNERSHIP_CONFLICT", "auth identity already belongs to another user")
}
}
return resolved, nil
}
func singleWeChatChannelUser(records []*dbent.AuthIdentityChannel) (*dbent.User, error) {
var resolved *dbent.User
for _, record := range records {
if record == nil || record.Edges.Identity == nil || record.Edges.Identity.Edges.User == nil {
continue
}
if resolved == nil {
resolved = record.Edges.Identity.Edges.User
continue
}
if resolved.ID != record.Edges.Identity.Edges.User.ID {
return nil, infraerrors.Conflict("AUTH_IDENTITY_CHANNEL_OWNERSHIP_CONFLICT", "auth identity channel already belongs to another user")
}
}
return resolved, nil
}
func (h *AuthHandler) ensureWeChatRuntimeIdentityBinding(