73 lines
3.0 KiB
Go
73 lines
3.0 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
|
|
"hyapp/pkg/appcode"
|
|
"hyapp/pkg/xerr"
|
|
authdomain "hyapp/services/user-service/internal/domain/auth"
|
|
invitedomain "hyapp/services/user-service/internal/domain/invite"
|
|
userdomain "hyapp/services/user-service/internal/domain/user"
|
|
invitestorage "hyapp/services/user-service/internal/storage/mysql/invite"
|
|
"hyapp/services/user-service/internal/storage/mysql/shared"
|
|
userstorage "hyapp/services/user-service/internal/storage/mysql/user"
|
|
)
|
|
|
|
func (r *Repository) FindThirdPartyIdentity(ctx context.Context, provider string, providerSubject string) (authdomain.ThirdPartyIdentity, error) {
|
|
var identity authdomain.ThirdPartyIdentity
|
|
err := r.db.QueryRowContext(ctx, `
|
|
SELECT app_code, user_id, provider, provider_subject, COALESCE(provider_union_id, ''), created_at_ms, updated_at_ms
|
|
FROM third_party_identities
|
|
WHERE app_code = ? AND provider = ? AND provider_subject = ?
|
|
`, appcode.FromContext(ctx), provider, providerSubject).Scan(&identity.AppCode, &identity.UserID, &identity.Provider, &identity.ProviderSubject, &identity.ProviderUnionID, &identity.CreatedAtMs, &identity.UpdatedAtMs)
|
|
if err == sql.ErrNoRows {
|
|
// 未绑定三方身份时由 service 转入注册路径。
|
|
return authdomain.ThirdPartyIdentity{}, xerr.New(xerr.NotFound, "third-party identity not found")
|
|
}
|
|
if err != nil {
|
|
return authdomain.ThirdPartyIdentity{}, err
|
|
}
|
|
|
|
return identity, nil
|
|
}
|
|
|
|
// CreateThirdPartyUser 原子创建用户、默认短号、三方身份和首个 session。
|
|
|
|
func (r *Repository) CreateThirdPartyUser(ctx context.Context, user userdomain.User, identity userdomain.Identity, thirdParty authdomain.ThirdPartyIdentity, session authdomain.Session, inviteBind invitedomain.BindCommand) error {
|
|
// 三方首次登录注册必须同时写用户、默认短号、三方绑定和首个 session。
|
|
tx, err := r.db.BeginTx(ctx, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer tx.Rollback()
|
|
|
|
if err := userstorage.InsertUserIdentity(ctx, tx, user, identity); err != nil {
|
|
// 默认短号冲突由 service 重试。
|
|
return mapAuthDuplicateError(err)
|
|
}
|
|
if _, err := invitestorage.EnsurePrimaryCodeForUser(ctx, tx, user.AppCode, user.UserID, user.CreatedAtMs); err != nil {
|
|
return err
|
|
}
|
|
if _, err := invitestorage.BindRelation(ctx, tx, inviteBind); err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = tx.ExecContext(ctx, `
|
|
INSERT INTO third_party_identities (app_code, user_id, provider, provider_subject, provider_union_id, created_at_ms, updated_at_ms)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
`, appcode.Normalize(thirdParty.AppCode), thirdParty.UserID, thirdParty.Provider, thirdParty.ProviderSubject, shared.NullableString(thirdParty.ProviderUnionID), thirdParty.CreatedAtMs, thirdParty.UpdatedAtMs)
|
|
if err != nil {
|
|
return mapAuthDuplicateError(err)
|
|
}
|
|
|
|
if err := insertSession(ctx, tx, session); err != nil {
|
|
// session 插入失败会回滚用户和三方绑定。
|
|
return err
|
|
}
|
|
|
|
return tx.Commit()
|
|
}
|
|
|
|
// RecordLoginAudit 写登录审计;调用方不会让审计失败影响主链路。
|