mirror of
https://github.com/snowykami/neo-blog.git
synced 2025-09-04 00:06:22 +00:00
⚡ implement user registration with email verification, enhance error handling, and update database configuration
This commit is contained in:
@ -20,16 +20,17 @@ type UserLoginResp struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UserRegisterReq struct {
|
type UserRegisterReq struct {
|
||||||
Username string `json:"username"` // 用户名
|
Username string `json:"username"` // 用户名
|
||||||
Nickname string `json:"nickname"` // 昵称
|
Nickname string `json:"nickname"` // 昵称
|
||||||
Password string `json:"password"` // 密码
|
Password string `json:"password"` // 密码
|
||||||
Email string `json:"email"` // 邮箱
|
Email string `json:"email"` // 邮箱
|
||||||
|
VerificationCode string `json:"verification_code"` // 邮箱验证码
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserRegisterResp struct {
|
type UserRegisterResp struct {
|
||||||
Token string `json:"token"` // 访问令牌
|
Token string `json:"token"` // 访问令牌
|
||||||
RefreshToken string `json:"refresh_token"` // 刷新令牌
|
RefreshToken string `json:"refresh_token"` // 刷新令牌
|
||||||
User UserDto `json:"user"` // 用户信息
|
User *UserDto `json:"user"` // 用户信息
|
||||||
}
|
}
|
||||||
|
|
||||||
type VerifyEmailReq struct {
|
type VerifyEmailReq struct {
|
||||||
|
@ -7,10 +7,10 @@ import (
|
|||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
Username string `gorm:"unique;index"` // 用户名,唯一
|
Username string `gorm:"uniqueIndex"` // 用户名,唯一
|
||||||
Nickname string
|
Nickname string
|
||||||
AvatarUrl string
|
AvatarUrl string
|
||||||
Email string `gorm:"unique;index"`
|
Email string `gorm:"uniqueIndex"`
|
||||||
Gender string
|
Gender string
|
||||||
Role string `gorm:"default:'user'"`
|
Role string `gorm:"default:'user'"`
|
||||||
|
|
||||||
|
@ -35,14 +35,14 @@ type DBConfig struct {
|
|||||||
// loadDBConfig 从配置文件加载数据库配置
|
// loadDBConfig 从配置文件加载数据库配置
|
||||||
func loadDBConfig() DBConfig {
|
func loadDBConfig() DBConfig {
|
||||||
return DBConfig{
|
return DBConfig{
|
||||||
Driver: utils.Env.Get("database.driver", "sqlite"),
|
Driver: utils.Env.Get("DB_DRIVER", "sqlite"),
|
||||||
Path: utils.Env.Get("database.path", "./data/data.db"),
|
Path: utils.Env.Get("DB_PATH", "./data/data.db"),
|
||||||
Host: utils.Env.Get("database.host", "postgres"),
|
Host: utils.Env.Get("DB_HOST", "postgres"),
|
||||||
Port: utils.Env.GetenvAsInt("database.port", 5432),
|
Port: utils.Env.GetenvAsInt("DB_PORT", 5432),
|
||||||
User: utils.Env.Get("database.user", "spage"),
|
User: utils.Env.Get("DB_USER", "blog"),
|
||||||
Password: utils.Env.Get("database.password", "spage"),
|
Password: utils.Env.Get("DB_PASSWORD", "blog"),
|
||||||
DBName: utils.Env.Get("database.dbname", "spage"),
|
DBName: utils.Env.Get("DB_NAME", "blog"),
|
||||||
SSLMode: utils.Env.Get("database.sslmode", "disable"),
|
SSLMode: utils.Env.Get("DB_SSLMODE", "disable"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,11 +3,13 @@ package service
|
|||||||
import (
|
import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/snowykami/neo-blog/internal/dto"
|
"github.com/snowykami/neo-blog/internal/dto"
|
||||||
|
"github.com/snowykami/neo-blog/internal/model"
|
||||||
"github.com/snowykami/neo-blog/internal/repo"
|
"github.com/snowykami/neo-blog/internal/repo"
|
||||||
"github.com/snowykami/neo-blog/internal/static"
|
"github.com/snowykami/neo-blog/internal/static"
|
||||||
"github.com/snowykami/neo-blog/pkg/constant"
|
"github.com/snowykami/neo-blog/pkg/constant"
|
||||||
"github.com/snowykami/neo-blog/pkg/errs"
|
"github.com/snowykami/neo-blog/pkg/errs"
|
||||||
"github.com/snowykami/neo-blog/pkg/utils"
|
"github.com/snowykami/neo-blog/pkg/utils"
|
||||||
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -62,7 +64,57 @@ func (s *userService) UserLogin(req *dto.UserLoginReq) (*dto.UserLoginResp, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *userService) UserRegister(req *dto.UserRegisterReq) (*dto.UserRegisterResp, error) {
|
func (s *userService) UserRegister(req *dto.UserRegisterReq) (*dto.UserRegisterResp, error) {
|
||||||
return nil, nil
|
// 验证邮箱验证码
|
||||||
|
kv := utils.KV.GetInstance()
|
||||||
|
verificationCode, ok := kv.Get(constant.KVKeyEmailVerificationCode + ":" + req.Email)
|
||||||
|
if !ok || verificationCode != req.VerificationCode {
|
||||||
|
return nil, errs.ErrInvalidCredentials
|
||||||
|
}
|
||||||
|
// 检查用户名或邮箱是否已存在
|
||||||
|
existingUser, err := repo.User.GetByUsernameOrEmail(req.Username)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errs.ErrInternalServer
|
||||||
|
}
|
||||||
|
if existingUser != nil {
|
||||||
|
return nil, errs.New(http.StatusConflict, "Username or email already exists", nil)
|
||||||
|
}
|
||||||
|
// 创建新用户
|
||||||
|
|
||||||
|
newUser := &model.User{
|
||||||
|
Username: req.Username,
|
||||||
|
Nickname: req.Nickname,
|
||||||
|
Email: req.Email,
|
||||||
|
Gender: "",
|
||||||
|
Role: "user",
|
||||||
|
Password: "",
|
||||||
|
}
|
||||||
|
err = repo.User.Create(newUser)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errs.ErrInternalServer
|
||||||
|
}
|
||||||
|
// 生成访问令牌和刷新令牌
|
||||||
|
token := utils.Jwt.NewClaims(newUser.ID, "", false, time.Duration(utils.Env.GetenvAsInt(constant.EnvKeyTokenDuration, 24)*int(time.Hour)))
|
||||||
|
tokenString, err := token.ToString()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errs.ErrInternalServer
|
||||||
|
}
|
||||||
|
refreshToken := utils.Jwt.NewClaims(newUser.ID, utils.Strings.GenerateRandomString(64), true, time.Duration(utils.Env.GetenvAsInt(constant.EnvKeyRefreshTokenDuration, 30)*int(time.Hour)))
|
||||||
|
refreshTokenString, err := refreshToken.ToString()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errs.ErrInternalServer
|
||||||
|
}
|
||||||
|
// 对refresh token进行持久化存储
|
||||||
|
err = repo.Session.SaveSession(refreshToken.SessionKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errs.ErrInternalServer
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &dto.UserRegisterResp{
|
||||||
|
Token: tokenString,
|
||||||
|
RefreshToken: refreshTokenString,
|
||||||
|
User: newUser.ToDto(),
|
||||||
|
}
|
||||||
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *userService) VerifyEmail(req *dto.VerifyEmailReq) (*dto.VerifyEmailResp, error) {
|
func (s *userService) VerifyEmail(req *dto.VerifyEmailReq) (*dto.VerifyEmailResp, error) {
|
||||||
|
@ -24,6 +24,7 @@ func (e *ServiceError) Error() string {
|
|||||||
var (
|
var (
|
||||||
ErrNotFound = &ServiceError{Code: http.StatusNotFound, Message: "not found"}
|
ErrNotFound = &ServiceError{Code: http.StatusNotFound, Message: "not found"}
|
||||||
ErrInvalidCredentials = &ServiceError{Code: http.StatusUnauthorized, Message: "invalid credentials"}
|
ErrInvalidCredentials = &ServiceError{Code: http.StatusUnauthorized, Message: "invalid credentials"}
|
||||||
|
ErrConflict = &ServiceError{Code: http.StatusConflict, Message: "resource conflict"}
|
||||||
ErrInternalServer = &ServiceError{Code: http.StatusInternalServerError, Message: "internal server error"}
|
ErrInternalServer = &ServiceError{Code: http.StatusInternalServerError, Message: "internal server error"}
|
||||||
ErrBadRequest = &ServiceError{Code: http.StatusBadRequest, Message: "invalid request parameters"}
|
ErrBadRequest = &ServiceError{Code: http.StatusBadRequest, Message: "invalid request parameters"}
|
||||||
ErrForbidden = &ServiceError{Code: http.StatusForbidden, Message: "access forbidden"}
|
ErrForbidden = &ServiceError{Code: http.StatusForbidden, Message: "access forbidden"}
|
||||||
|
Reference in New Issue
Block a user