Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
43f104bd
Commit
43f104bd
authored
Jan 09, 2026
by
shaw
Browse files
fix(auth): 注册接口安全加固 - 默认关闭注册
parent
0a9c17b9
Changes
4
Hide whitespace changes
Inline
Side-by-side
backend/internal/service/auth_service.go
View file @
43f104bd
...
...
@@ -75,8 +75,8 @@ func (s *AuthService) Register(ctx context.Context, email, password string) (str
// RegisterWithVerification 用户注册(支持邮件验证),返回token和用户
func
(
s
*
AuthService
)
RegisterWithVerification
(
ctx
context
.
Context
,
email
,
password
,
verifyCode
string
)
(
string
,
*
User
,
error
)
{
// 检查是否开放注册
if
s
.
settingService
!
=
nil
&&
!
s
.
settingService
.
IsRegistrationEnabled
(
ctx
)
{
// 检查是否开放注册
(默认关闭:settingService 未配置时不允许注册)
if
s
.
settingService
=
=
nil
||
!
s
.
settingService
.
IsRegistrationEnabled
(
ctx
)
{
return
""
,
nil
,
ErrRegDisabled
}
...
...
@@ -132,6 +132,10 @@ func (s *AuthService) RegisterWithVerification(ctx context.Context, email, passw
}
if
err
:=
s
.
userRepo
.
Create
(
ctx
,
user
);
err
!=
nil
{
// 优先检查邮箱冲突错误(竞态条件下可能发生)
if
errors
.
Is
(
err
,
ErrEmailExists
)
{
return
""
,
nil
,
ErrEmailExists
}
log
.
Printf
(
"[Auth] Database error creating user: %v"
,
err
)
return
""
,
nil
,
ErrServiceUnavailable
}
...
...
@@ -152,8 +156,8 @@ type SendVerifyCodeResult struct {
// SendVerifyCode 发送邮箱验证码(同步方式)
func
(
s
*
AuthService
)
SendVerifyCode
(
ctx
context
.
Context
,
email
string
)
error
{
// 检查是否开放注册
if
s
.
settingService
!
=
nil
&&
!
s
.
settingService
.
IsRegistrationEnabled
(
ctx
)
{
// 检查是否开放注册
(默认关闭)
if
s
.
settingService
=
=
nil
||
!
s
.
settingService
.
IsRegistrationEnabled
(
ctx
)
{
return
ErrRegDisabled
}
...
...
@@ -185,8 +189,8 @@ func (s *AuthService) SendVerifyCode(ctx context.Context, email string) error {
func
(
s
*
AuthService
)
SendVerifyCodeAsync
(
ctx
context
.
Context
,
email
string
)
(
*
SendVerifyCodeResult
,
error
)
{
log
.
Printf
(
"[Auth] SendVerifyCodeAsync called for email: %s"
,
email
)
// 检查是否开放注册
if
s
.
settingService
!
=
nil
&&
!
s
.
settingService
.
IsRegistrationEnabled
(
ctx
)
{
// 检查是否开放注册
(默认关闭)
if
s
.
settingService
=
=
nil
||
!
s
.
settingService
.
IsRegistrationEnabled
(
ctx
)
{
log
.
Println
(
"[Auth] Registration is disabled"
)
return
nil
,
ErrRegDisabled
}
...
...
@@ -270,7 +274,7 @@ func (s *AuthService) IsTurnstileEnabled(ctx context.Context) bool {
// IsRegistrationEnabled 检查是否开放注册
func
(
s
*
AuthService
)
IsRegistrationEnabled
(
ctx
context
.
Context
)
bool
{
if
s
.
settingService
==
nil
{
return
true
return
false
// 安全默认:settingService 未配置时关闭注册
}
return
s
.
settingService
.
IsRegistrationEnabled
(
ctx
)
}
...
...
backend/internal/service/auth_service_register_test.go
View file @
43f104bd
...
...
@@ -113,6 +113,15 @@ func TestAuthService_Register_Disabled(t *testing.T) {
require
.
ErrorIs
(
t
,
err
,
ErrRegDisabled
)
}
func
TestAuthService_Register_DisabledByDefault
(
t
*
testing
.
T
)
{
// 当 settings 为 nil(设置项不存在)时,注册应该默认关闭
repo
:=
&
userRepoStub
{}
service
:=
newAuthService
(
repo
,
nil
,
nil
)
_
,
_
,
err
:=
service
.
Register
(
context
.
Background
(),
"user@test.com"
,
"password"
)
require
.
ErrorIs
(
t
,
err
,
ErrRegDisabled
)
}
func
TestAuthService_Register_EmailVerifyEnabledButServiceNotConfigured
(
t
*
testing
.
T
)
{
repo
:=
&
userRepoStub
{}
// 邮件验证开启但 emailCache 为 nil(emailService 未配置)
...
...
@@ -155,7 +164,9 @@ func TestAuthService_Register_EmailVerifyInvalid(t *testing.T) {
func
TestAuthService_Register_EmailExists
(
t
*
testing
.
T
)
{
repo
:=
&
userRepoStub
{
exists
:
true
}
service
:=
newAuthService
(
repo
,
nil
,
nil
)
service
:=
newAuthService
(
repo
,
map
[
string
]
string
{
SettingKeyRegistrationEnabled
:
"true"
,
},
nil
)
_
,
_
,
err
:=
service
.
Register
(
context
.
Background
(),
"user@test.com"
,
"password"
)
require
.
ErrorIs
(
t
,
err
,
ErrEmailExists
)
...
...
@@ -163,7 +174,9 @@ func TestAuthService_Register_EmailExists(t *testing.T) {
func
TestAuthService_Register_CheckEmailError
(
t
*
testing
.
T
)
{
repo
:=
&
userRepoStub
{
existsErr
:
errors
.
New
(
"db down"
)}
service
:=
newAuthService
(
repo
,
nil
,
nil
)
service
:=
newAuthService
(
repo
,
map
[
string
]
string
{
SettingKeyRegistrationEnabled
:
"true"
,
},
nil
)
_
,
_
,
err
:=
service
.
Register
(
context
.
Background
(),
"user@test.com"
,
"password"
)
require
.
ErrorIs
(
t
,
err
,
ErrServiceUnavailable
)
...
...
@@ -171,15 +184,30 @@ func TestAuthService_Register_CheckEmailError(t *testing.T) {
func
TestAuthService_Register_CreateError
(
t
*
testing
.
T
)
{
repo
:=
&
userRepoStub
{
createErr
:
errors
.
New
(
"create failed"
)}
service
:=
newAuthService
(
repo
,
nil
,
nil
)
service
:=
newAuthService
(
repo
,
map
[
string
]
string
{
SettingKeyRegistrationEnabled
:
"true"
,
},
nil
)
_
,
_
,
err
:=
service
.
Register
(
context
.
Background
(),
"user@test.com"
,
"password"
)
require
.
ErrorIs
(
t
,
err
,
ErrServiceUnavailable
)
}
func
TestAuthService_Register_CreateEmailExistsRace
(
t
*
testing
.
T
)
{
// 模拟竞态条件:ExistsByEmail 返回 false,但 Create 时因唯一约束失败
repo
:=
&
userRepoStub
{
createErr
:
ErrEmailExists
}
service
:=
newAuthService
(
repo
,
map
[
string
]
string
{
SettingKeyRegistrationEnabled
:
"true"
,
},
nil
)
_
,
_
,
err
:=
service
.
Register
(
context
.
Background
(),
"user@test.com"
,
"password"
)
require
.
ErrorIs
(
t
,
err
,
ErrEmailExists
)
}
func
TestAuthService_Register_Success
(
t
*
testing
.
T
)
{
repo
:=
&
userRepoStub
{
nextID
:
5
}
service
:=
newAuthService
(
repo
,
nil
,
nil
)
service
:=
newAuthService
(
repo
,
map
[
string
]
string
{
SettingKeyRegistrationEnabled
:
"true"
,
},
nil
)
token
,
user
,
err
:=
service
.
Register
(
context
.
Background
(),
"user@test.com"
,
"password"
)
require
.
NoError
(
t
,
err
)
...
...
backend/internal/service/email_service.go
View file @
43f104bd
...
...
@@ -5,6 +5,7 @@ import (
"crypto/rand"
"crypto/tls"
"fmt"
"log"
"math/big"
"net/smtp"
"strconv"
...
...
@@ -256,7 +257,9 @@ func (s *EmailService) VerifyCode(ctx context.Context, email, code string) error
// 验证码不匹配
if
data
.
Code
!=
code
{
data
.
Attempts
++
_
=
s
.
cache
.
SetVerificationCode
(
ctx
,
email
,
data
,
verifyCodeTTL
)
if
err
:=
s
.
cache
.
SetVerificationCode
(
ctx
,
email
,
data
,
verifyCodeTTL
);
err
!=
nil
{
log
.
Printf
(
"[Email] Failed to update verification attempt count: %v"
,
err
)
}
if
data
.
Attempts
>=
maxVerifyCodeAttempts
{
return
ErrVerifyCodeMaxAttempts
}
...
...
@@ -264,7 +267,9 @@ func (s *EmailService) VerifyCode(ctx context.Context, email, code string) error
}
// 验证成功,删除验证码
_
=
s
.
cache
.
DeleteVerificationCode
(
ctx
,
email
)
if
err
:=
s
.
cache
.
DeleteVerificationCode
(
ctx
,
email
);
err
!=
nil
{
log
.
Printf
(
"[Email] Failed to delete verification code after success: %v"
,
err
)
}
return
nil
}
...
...
backend/internal/service/setting_service.go
View file @
43f104bd
...
...
@@ -141,8 +141,8 @@ func (s *SettingService) UpdateSettings(ctx context.Context, settings *SystemSet
func
(
s
*
SettingService
)
IsRegistrationEnabled
(
ctx
context
.
Context
)
bool
{
value
,
err
:=
s
.
settingRepo
.
GetValue
(
ctx
,
SettingKeyRegistrationEnabled
)
if
err
!=
nil
{
//
默认开放
注册
return
tru
e
//
安全默认:如果设置不存在或查询出错,默认关闭
注册
return
fals
e
}
return
value
==
"true"
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment