新增验证码生成校验测试接口

This commit is contained in:
2025-08-05 19:39:33 +08:00
parent ca53d095b6
commit b36ca9967f
9 changed files with 1768 additions and 7 deletions

Binary file not shown.

View File

@@ -3,16 +3,39 @@ package mysql
import (
"acquaintances/biz/model"
"acquaintances/biz/model/user"
"acquaintances/biz/utils"
"encoding/base64"
"errors"
"fmt"
"golang.org/x/crypto/scrypt"
"gorm.io/gorm"
"log"
"time"
"github.com/cloudwego/hertz/pkg/common/hlog"
)
// CheckPhone 校验手机号是否已存在于系统中
// 参数phone 待检查的手机号
// 返回存在返回true不存在返回false如果发生错误则返回错误信息
func CheckPhone(phone string) (bool, error) {
// 先简单验证手机号格式,避免无效查询
if !utils.IsValidPhone(phone) {
return false, fmt.Errorf("无效的手机号格式: %s", phone)
}
var count int64
// 只查询记录数,不需要返回完整用户信息,提高性能
result := DB.Model(&model.User{}).Where("mobile = ?", phone).Count(&count)
if result.Error != nil {
// 记录错误日志,方便排查问题
log.Printf("检查手机号存在性失败: %v, 手机号: %s", result.Error, phone)
return false, fmt.Errorf("查询用户信息失败: %w", result.Error)
}
return count > 0, nil
}
func CreateUser(users []*model.User) error {
errTransaction := DB.Transaction(func(tx *gorm.DB) error {
//创建用户信息表记录

View File

@@ -8,10 +8,14 @@ import (
user "acquaintances/biz/model/user"
"acquaintances/biz/utils"
"context"
"fmt"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/common/hlog"
"github.com/cloudwego/hertz/pkg/protocol/consts"
"log"
"regexp"
"strconv"
"time"
)
// UpdateUser .
@@ -181,3 +185,178 @@ func LoginUser(ctx context.Context, c *app.RequestContext) {
resp.UserInfo = resData
c.JSON(consts.StatusOK, resp)
}
// SmsUser 处理用户短信请求(注册、登录等场景的验证码发送)
// @router /v1/user/sms/ [POST]
func SmsUser(ctx context.Context, c *app.RequestContext) {
var err error
var req user.SmsRequest
err = c.BindAndValidate(&req)
if err != nil {
c.String(consts.StatusBadRequest, err.Error())
return
}
// 验证手机号格式
if !utils.IsValidPhone(req.Phone) {
c.String(consts.StatusBadRequest, "无效的手机号格式")
return
}
// 生成6位数字验证码
code := utils.GenerateVerificationCode()
// 根据短信类型处理不同业务逻辑
var message string
switch req.Type {
case model.SmsRegister:
// 注册场景:检查手机号是否已注册
exists, err := mysql.CheckPhone(req.Phone)
if err != nil {
c.String(consts.StatusInternalServerError, "查询用户信息失败")
return
}
if exists {
c.String(consts.StatusBadRequest, "该手机号已注册")
return
}
message = fmt.Sprintf("您的注册验证码是:%s有效期5分钟。", code)
case model.SmsLongin:
// 登录场景:可以不需要检查手机号是否存在
message = fmt.Sprintf("您的登录验证码是:%s有效期5分钟。", code)
default:
c.String(consts.StatusBadRequest, "不支持的短信类型")
return
}
// 存储验证码到缓存如Redis设置5分钟过期
err = storeVerificationCode(req.Phone, req.Type, code, 5*time.Minute)
if err != nil {
c.String(consts.StatusInternalServerError, "存储验证码失败")
return
}
// 调用短信发送服务
err = utils.SendSms(req.Phone, message)
if err != nil {
// 发送失败时删除已存储的验证码
deleteVerificationCode(req.Phone, req.Type)
c.String(consts.StatusInternalServerError, "发送短信失败:"+err.Error())
return
}
resp := &user.SmsResponse{
Msg: "验证码已发送",
}
c.JSON(consts.StatusOK, resp)
}
func storeVerificationCode(phone, typ, code string, expiration time.Duration) error {
// TODO实现存储验证码到缓存的逻辑
return nil
}
func deleteVerificationCode(phone, typ string) error {
// TODO实现删除验证码的逻辑
return nil
}
// CheckOtp 校验验证码是否正确
// @router /v1/user/check_otp/ [POST]
func CheckOtp(ctx context.Context, c *app.RequestContext) {
var err error
var req user.CheckOtpRequest
err = c.BindAndValidate(&req)
if err != nil {
c.String(consts.StatusBadRequest, err.Error())
return
}
// 验证手机号格式
if !utils.IsValidPhone(req.Phone) {
c.String(consts.StatusBadRequest, "无效的手机号格式")
return
}
// 验证验证码格式通常是6位数字
//if !isValidOtp(req.Otp) {
// c.String(consts.StatusBadRequest, "验证码格式不正确")
// return
//}
// 验证验证码类型
if !isValidOtpType(req.Type) {
c.String(consts.StatusBadRequest, "不支持的验证码类型")
return
}
// 从缓存中获取存储的验证码
//storedOtp, err := getStoredVerificationCode(req.Phone, req.Type)
//if err != nil {
// c.String(consts.StatusInternalServerError, "获取验证码信息失败")
// return
//}
// 检查验证码是否存在(可能已过期或未发送)
//if storedOtp == "" {
// c.String(consts.StatusBadRequest, "验证码不存在或已过期")
// return
//}
// 验证验证码是否匹配
//if req.Otp != storedOtp {
// resp := &user.CheckOtpResponse{
// Code: consts.StatusBadRequest,
// Msg: "验证码不正确",
// }
// c.JSON(consts.StatusOK, resp)
// return
//}
// 验证码验证成功后,根据类型执行不同业务逻辑
switch req.Type {
case model.SmsRegister:
case model.SmsLongin:
}
// 验证成功后删除已使用的验证码,防止重复使用
err = deleteVerificationCode(req.Phone, req.Type)
if err != nil {
// 这里只记录警告,不影响主流程
log.Printf("删除验证码失败: %v, 手机号: %s, 类型: %s", err, req.Phone, req.Type)
}
resp := &user.CheckOtpResponse{
Msg: "验证码验证成功",
}
c.JSON(consts.StatusOK, resp)
}
// 辅助函数验证验证码格式6位数字
func isValidOtp(otp string) bool {
pattern := `^\d{6}$`
return regexp.MustCompile(pattern).MatchString(otp)
}
// 辅助函数:验证验证码类型是否合法
func isValidOtpType(typ string) bool {
switch typ {
case model.SmsRegister, model.SmsLongin:
return true
default:
return false
}
}
// 以下是需要根据实际项目实现的函数
func getStoredVerificationCode(phone, typ string) (string, error) {
// 从缓存中获取验证码的逻辑
// 例如: return redisClient.Get(ctx, getOtpCacheKey(phone, typ)).Result()
return "", nil
}

View File

@@ -9,6 +9,11 @@ import (
"time"
)
const (
SmsLongin = "sms_longin"
SmsRegister = "sms_register"
)
var UserSync *sync.Mutex
type User struct {

File diff suppressed because it is too large Load Diff

View File

@@ -315,3 +315,23 @@ func _user0Mw() []app.HandlerFunc {
// your code...
return nil
}
func _smsMw() []app.HandlerFunc {
// your code...
return nil
}
func _smsuserMw() []app.HandlerFunc {
// your code...
return nil
}
func _check_otpMw() []app.HandlerFunc {
// your code...
return nil
}
func _checkotpMw() []app.HandlerFunc {
// your code...
return nil
}

View File

@@ -81,6 +81,10 @@ func Register(r *server.Hertz) {
_user0.GET("/", append(_infouserMw(), user.InfoUser)...)
_user0.POST("/", append(_createuserMw(), user.CreateUser)...)
_user0.PUT("/", append(_updateuserMw(), user.UpdateUser)...)
{
_check_otp := _user0.Group("/check_otp", _check_otpMw()...)
_check_otp.POST("/", append(_checkotpMw(), user.CheckOtp)...)
}
{
_find := _user0.Group("/find", _findMw()...)
_find.GET("/", append(_finduserMw(), user.FindUser)...)
@@ -102,6 +106,10 @@ func Register(r *server.Hertz) {
_relation.POST("/", append(_createuserrelationsMw(), user.CreateUserRelations)...)
_relation.PUT("/", append(_updateuserrelationsMw(), user.UpdateUserRelations)...)
}
{
_sms := _user0.Group("/sms", _smsMw()...)
_sms.POST("/", append(_smsuserMw(), user.SmsUser)...)
}
}
}
}

View File

@@ -8,6 +8,7 @@ import (
"fmt"
"github.com/cloudwego/hertz/pkg/common/hlog"
"golang.org/x/crypto/scrypt"
"regexp"
"sync"
"time"
)
@@ -171,3 +172,22 @@ func trimBase64Padding(s string) string {
}
return s
}
// SendSms 短信发送
func SendSms(phone, message string) error {
// TODO
return nil
}
// IsValidPhone 辅助函数:验证手机号格式
func IsValidPhone(phone string) bool {
// 简单的手机号验证正则,可根据实际需求调整
pattern := `^\+?[1-9]\d{6,14}$`
reg := regexp.MustCompile(pattern)
return reg.MatchString(phone)
}
// GenerateVerificationCode 生成6位数字验证码
func GenerateVerificationCode() string {
return ""
}

View File

@@ -134,14 +134,35 @@ struct LoginUserRequest{
2: string password (api.path="password",api.body="password")
}
struct SmsRequest{
1: string phone (api.path="phone",api.body="phone")
2: string type (api.path="type",api.body="type")
}
struct SmsResponse{
1: Code code
2: string msg
}
struct CheckOtpRequest{
1: string phone (api.path="phone",api.body="phone")
2: string otp (api.path="otp",api.body="otp")
}
struct CheckOtpResponse{
1: Code code
2: string msg
}
service UserService {
UpdateUserResponse UpdateUser(1:UpdateUserRequest req)(api.put="/v1/user/")
DeleteUserResponse DeleteUser(1:DeleteUserRequest req)(api.delete="/v1/user/")
QueryUserResponse InfoUser(1: InfoUserRequest req)(api.get="/v1/user/")
CreateUserResponse CreateUser(1:CreateUserRequest req)(api.post="/v1/user/")
FindUserResponse FindUser(1:FindUserRequest req)(api.get="/v1/user/find/")
LoginUserResponse LoginUser(1:LoginUserRequest req)(api.post="/v1/user/login/")
UpdateUserResponse UpdateUser(1:UpdateUserRequest req)(api.put="/v1/user/") //更新用户信息
DeleteUserResponse DeleteUser(1:DeleteUserRequest req)(api.delete="/v1/user/") //删除用户
QueryUserResponse InfoUser(1: InfoUserRequest req)(api.get="/v1/user/") //查询用户信息
CreateUserResponse CreateUser(1:CreateUserRequest req)(api.post="/v1/user/") //注册用户
FindUserResponse FindUser(1:FindUserRequest req)(api.get="/v1/user/find/") //精确查询用户
LoginUserResponse LoginUser(1:LoginUserRequest req)(api.post="/v1/user/login/") //用户登录
SmsResponse SmsUser(1:SmsRequest req)(api.post="/v1/user/sms/") //用户短信
CheckOtpResponse CheckOtp(1:CheckOtpRequest req)(api.post="/v1/user/check_otp/") //验证码校验
}