新增验证码生成校验测试接口
This commit is contained in:
Binary file not shown.
@@ -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 {
|
||||
//创建用户信息表记录
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
@@ -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
|
||||
}
|
||||
|
@@ -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)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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 ""
|
||||
}
|
||||
|
@@ -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/") //验证码校验
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user