fix: 支持系统域名完整邮箱标识直接解析有效账号与协议认证
Some checks are pending
Security Checks / security (push) Waiting to run

This commit is contained in:
smail 2026-09-12 10:49:45 +08:00
parent 875b83fa2a
commit 343d038ee3
2 changed files with 85 additions and 15 deletions

View File

@ -72,24 +72,44 @@ func ResolveIdentifier(identifier string) (ResolvedIdentity, error) {
Find(&bindings); err != nil {
return ResolvedIdentity{}, fmt.Errorf("load login email binding: %w", err)
}
if len(bindings) != 1 || bindings[0].UserID <= 0 {
return ResolvedIdentity{}, errors.New("invalid identifier")
if len(bindings) == 1 && bindings[0].UserID > 0 {
var user models.User
has, err := db.Instance.ID(bindings[0].UserID).Get(&user)
if err != nil {
return ResolvedIdentity{}, fmt.Errorf("load login user: %w", err)
}
if has && user.ID > 0 && user.Account != "" && user.Disabled == 0 {
return ResolvedIdentity{
UserID: user.ID,
Account: user.Account,
LoginAddress: normalized,
Kind: IdentifierEmail,
}, nil
}
}
var user models.User
has, err := db.Instance.ID(bindings[0].UserID).Get(&user)
if err != nil {
return ResolvedIdentity{}, fmt.Errorf("load login user: %w", err)
// 回退机制:若未绑定独立外部邮箱,但属于系统配置的域名,则按账号匹配有效系统用户
parts := strings.SplitN(normalized, "@", 2)
if len(parts) == 2 && isConfiguredLoginDomain(parts[1]) {
account, err := validation.NormalizeAccount(parts[0])
if err == nil {
var user models.User
has, err := db.Instance.Where("account = ? AND disabled = 0", account).Get(&user)
if err != nil {
return ResolvedIdentity{}, fmt.Errorf("load domain user: %w", err)
}
if has && user.ID > 0 && user.Account != "" {
return ResolvedIdentity{
UserID: user.ID,
Account: user.Account,
LoginAddress: normalized,
Kind: IdentifierEmail,
}, nil
}
}
}
if !has || user.ID <= 0 || user.Account == "" {
return ResolvedIdentity{}, errors.New("invalid identifier")
}
return ResolvedIdentity{
UserID: user.ID,
Account: user.Account,
LoginAddress: normalized,
Kind: IdentifierEmail,
}, nil
return ResolvedIdentity{}, errors.New("invalid identifier")
}
func parseLoginIdentifier(identifier string) (string, IdentifierKind, error) {

View File

@ -92,3 +92,53 @@ func TestNormalizeIdentifierKeepsLegacyAccountCompatibility(t *testing.T) {
t.Fatalf("normalized email key = %q, err = %v", got, err)
}
}
func TestResolveIdentifierFallbackToConfiguredDomainUser(t *testing.T) {
oldConfig := config.Instance
oldDB := db.Instance
config.Instance = &config.Config{
DbType: config.DBTypeSQLite,
DbDSN: filepath.Join(t.TempDir(), "domain_fallback.db"),
Domain: "solit.cn",
Domains: []string{"solit.cn"},
}
if err := db.Init(""); err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
if db.Instance != nil && db.Instance != oldDB {
_ = db.Instance.Close()
}
db.Instance = oldDB
config.Instance = oldConfig
})
user := models.User{Account: "bob", Name: "Bob", Disabled: 0}
if err := SetPassword(&user, "CorrectP12"); err != nil {
t.Fatal(err)
}
if _, err := db.Instance.Insert(&user); err != nil {
t.Fatal(err)
}
identity, err := ResolveIdentifier(" Bob@Solit.cn ")
if err != nil {
t.Fatalf("resolve configured domain user failed: %v", err)
}
if identity.Kind != IdentifierEmail || identity.UserID != user.ID || identity.Account != "bob" || identity.LoginAddress != "bob@solit.cn" {
t.Fatalf("unexpected resolved identity: %+v", identity)
}
disabledUser := models.User{Account: "charlie", Name: "Charlie", Disabled: 1}
if _, err := db.Instance.Insert(&disabledUser); err != nil {
t.Fatal(err)
}
if _, err := ResolveIdentifier("charlie@solit.cn"); err == nil {
t.Fatal("disabled domain user must not be resolved")
}
if _, err := ResolveIdentifier("bob@other.com"); err == nil {
t.Fatal("unconfigured domain must not be resolved")
}
}