feat: 迁移商务登录品牌和三步找回密码
This commit is contained in:
+2
-2
@@ -40,8 +40,8 @@ var (
|
||||
// Service identity reported to logs, health output, and the API documentation.
|
||||
// A plain `go run` leaves the ldflags empty, so these are the fallbacks.
|
||||
const (
|
||||
appName = "Kra Admin"
|
||||
appDescription = "Kratos 管理后台服务"
|
||||
appName = "遨游龙翔游戏平台"
|
||||
appDescription = "渠道商务管理服务"
|
||||
defaultVersion = "v0.0.0-dev"
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/glebarez/sqlite"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gorm.io/gorm"
|
||||
businessbiz "kra/internal/biz/business"
|
||||
businessdata "kra/internal/data/business"
|
||||
systemdata "kra/internal/data/system"
|
||||
"kra/internal/server/handler"
|
||||
"kra/internal/server/router"
|
||||
businessservice "kra/internal/service/business"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type resetHTTPSMS struct {
|
||||
code string
|
||||
calls int
|
||||
}
|
||||
|
||||
func (s *resetHTTPSMS) SendCode(_ context.Context, _ string, code string) error {
|
||||
s.code = code
|
||||
s.calls++
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestPasswordResetAnonymousHTTPFlow(t *testing.T) {
|
||||
db, err := gorm.Open(sqlite.Open(filepath.Join(t.TempDir(), "reset.db")), &gorm.Config{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sqlDB, err := db.DB()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = sqlDB.Close() })
|
||||
for _, step := range append(systemdata.Migrations(), businessdata.Migrations()...) {
|
||||
if err := step.Migrate(db); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
before := time.Now().Add(-time.Hour)
|
||||
if err := db.Table("sys_users").Create(map[string]any{"id": 7, "uuid": "reset-test", "username": "recover", "phone": "13800138000", "enable": 1, "business_status": 0, "password": "old-hash", "password_updated_at": before}).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sms := &resetHTTPSMS{}
|
||||
service := businessservice.NewPasswordResetService(businessbiz.NewPasswordResetUsecase(businessdata.NewPasswordResetRepo(businessHTTPData{db}), sms))
|
||||
engine := gin.New()
|
||||
router.RegisterBusinessPassword(engine.Group(""), handler.NewBusinessPassword(service))
|
||||
server := httptest.NewServer(engine)
|
||||
defer server.Close()
|
||||
call := func(action string, payload map[string]any, expected int) map[string]any {
|
||||
t.Helper()
|
||||
encoded, _ := json.Marshal(payload)
|
||||
response, err := http.Post(server.URL+"/sw/auth/forgot-password/"+action, "application/json", strings.NewReader(string(encoded)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer response.Body.Close()
|
||||
var body map[string]any
|
||||
if err := json.NewDecoder(response.Body).Decode(&body); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if response.StatusCode != 200 || body["code"] != float64(expected) {
|
||||
t.Fatalf("%s 结果不正确: %+v", action, body)
|
||||
}
|
||||
data, _ := body["data"].(map[string]any)
|
||||
return data
|
||||
}
|
||||
phone := call("check", map[string]any{"username": "recover"}, 0)
|
||||
if phone["maskedPhone"] != "138****8000" {
|
||||
t.Fatal("接口手机号未脱敏")
|
||||
}
|
||||
call("send-code", map[string]any{"username": "recover"}, 0)
|
||||
call("send-code", map[string]any{"username": "recover"}, 7)
|
||||
if sms.calls != 1 {
|
||||
t.Fatal("HTTP 发码限流无效")
|
||||
}
|
||||
wrong := "000000"
|
||||
if sms.code == wrong {
|
||||
wrong = "111111"
|
||||
}
|
||||
call("verify-code", map[string]any{"username": "recover", "smsCode": wrong}, 7)
|
||||
verified := call("verify-code", map[string]any{"username": "recover", "smsCode": sms.code}, 0)
|
||||
token, ok := verified["resetToken"].(string)
|
||||
if !ok || len(token) != 64 {
|
||||
t.Fatal("未返回一次性重置凭证")
|
||||
}
|
||||
call("verify-code", map[string]any{"username": "recover", "smsCode": sms.code}, 7)
|
||||
call("reset", map[string]any{"resetToken": token, "newPassword": "abc123", "confirmPassword": "abc123"}, 0)
|
||||
var user struct {
|
||||
Password string
|
||||
PasswordUpdatedAt time.Time
|
||||
}
|
||||
if err := db.Table("sys_users").Where("id = ?", 7).Take(&user).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if bcrypt.CompareHashAndPassword([]byte(user.Password), []byte("abc123")) != nil || !user.PasswordUpdatedAt.After(before) {
|
||||
t.Fatal("新密码或会话失效版本未保存")
|
||||
}
|
||||
call("reset", map[string]any{"resetToken": token, "newPassword": "abc124", "confirmPassword": "abc124"}, 7)
|
||||
var count int64
|
||||
if err := db.Table("sys_business_password_resets").Count(&count).Error; err != nil || count != 0 {
|
||||
t.Fatal("重置凭证未在事务中消费")
|
||||
}
|
||||
}
|
||||
Generated
+6
@@ -94,8 +94,13 @@ func wireApp(configServer *config.Server, store *config.Store, logger *slog.Logg
|
||||
bindingUsecase := business2.NewBindingUsecase(bindingRepo, accountUsecase, platformAccountRepo, platformPasswordVerifier)
|
||||
bindingService := business3.NewBindingService(bindingUsecase)
|
||||
handlerBusiness := handler.NewBusiness(userPreferenceService, accountService, bindingService)
|
||||
passwordResetRepo := business.NewPasswordResetRepo(dataData)
|
||||
runtimeconfigStore := data.NewIntegrationRuntime(dataData)
|
||||
smsSender := sms.NewSender(runtimeconfigStore)
|
||||
passwordResetSMS := gameplatform.NewPasswordSMS(smsSender)
|
||||
passwordResetUsecase := business2.NewPasswordResetUsecase(passwordResetRepo, passwordResetSMS)
|
||||
passwordResetService := business3.NewPasswordResetService(passwordResetUsecase)
|
||||
businessPassword := handler.NewBusinessPassword(passwordResetService)
|
||||
smsUsecase := integration.NewSMSUsecase(smsSender)
|
||||
smsService := integration2.NewSMSService(smsUsecase)
|
||||
handlerSMS := handler.NewSMS(smsService)
|
||||
@@ -193,6 +198,7 @@ func wireApp(configServer *config.Server, store *config.Store, logger *slog.Logg
|
||||
integrationConfig := handler.NewIntegrationConfig(integrationConfigService)
|
||||
set := &handler.Set{
|
||||
Business: handlerBusiness,
|
||||
BusinessPassword: businessPassword,
|
||||
SMS: handlerSMS,
|
||||
Authority: authority,
|
||||
Menu: menu,
|
||||
|
||||
Reference in New Issue
Block a user