1.0
This commit is contained in:
@@ -0,0 +1,372 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"awesomeProject/internal/common"
|
||||
"awesomeProject/internal/models"
|
||||
"awesomeProject/internal/services"
|
||||
jwtutil "awesomeProject/pkg/utils"
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"github.com/google/uuid"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// AuthHandler 认证处理器
|
||||
type AuthHandler struct{}
|
||||
|
||||
// LoginRequest 登录请求结构
|
||||
type LoginRequest struct {
|
||||
Phone string `json:"phone" binding:"required"`
|
||||
Password string `json:"password" binding:"required"`
|
||||
}
|
||||
|
||||
// LoginResponse 登录响应结构
|
||||
type LoginResponse struct {
|
||||
Token string `json:"token"`
|
||||
User models.User `json:"user"`
|
||||
}
|
||||
type TokenGen struct {
|
||||
UserID uint `json:"user_id"`
|
||||
Phone string `json:"phone"`
|
||||
SystemRole int8 `json:"system_role"`
|
||||
}
|
||||
|
||||
// Login 用户登录
|
||||
func (h *AuthHandler) Login(c *gin.Context) {
|
||||
var req LoginRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusOK, common.Error(400, "参数错误: "+err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询用户
|
||||
var user models.User
|
||||
err := common.GetDB().Where("phone = ?", req.Phone).First(&user).Error
|
||||
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
c.JSON(http.StatusOK, common.Error(401, "手机号或密码错误"))
|
||||
} else {
|
||||
c.JSON(http.StatusOK, common.Error(500, "登录失败"))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 验证密码(这里简单使用MD5,实际应该使用bcrypt)
|
||||
hashedPassword := fmt.Sprintf("%x", md5.Sum([]byte(req.Password)))
|
||||
fmt.Println(hashedPassword)
|
||||
if user.Password != hashedPassword {
|
||||
c.JSON(http.StatusOK, common.Error(404, "手机号或密码错误"))
|
||||
return
|
||||
}
|
||||
|
||||
// 检查用户状态
|
||||
if user.Status != 1 {
|
||||
c.JSON(http.StatusOK, common.Error(404, "用户已被禁用,请联系管理员"))
|
||||
return
|
||||
}
|
||||
|
||||
// 生成JWT token
|
||||
claims := TokenGen{
|
||||
UserID: user.ID,
|
||||
Phone: user.Phone,
|
||||
SystemRole: int8(user.SystemRole),
|
||||
}
|
||||
|
||||
token, err := jwtutil.GenerateToken(claims)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, common.Error(500, "生成token失败"))
|
||||
return
|
||||
}
|
||||
|
||||
// 返回登录结果
|
||||
response := LoginResponse{
|
||||
Token: token,
|
||||
User: user,
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, common.Success(response))
|
||||
}
|
||||
|
||||
// RegisterRequest 注册请求结构体
|
||||
type RegisterRequest struct {
|
||||
models.User
|
||||
SMSCode string `json:"sms_code"` // 短信验证码
|
||||
}
|
||||
|
||||
// Register 用户注册
|
||||
func (h *AuthHandler) Register(c *gin.Context) {
|
||||
var req RegisterRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusOK, common.Error(400, "参数错误: "+err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 验证短信验证码(必填)
|
||||
if req.SMSCode == "" {
|
||||
c.JSON(http.StatusOK, common.Error(400, "请输入短信验证码"))
|
||||
return
|
||||
}
|
||||
|
||||
// 验证短信验证码
|
||||
smsService := services.GetSMSService()
|
||||
if !smsService.VerifyCode(req.Phone, req.SMSCode) {
|
||||
c.JSON(http.StatusOK, common.Error(400, "短信验证码错误或已过期"))
|
||||
return
|
||||
}
|
||||
|
||||
// 检查手机号是否已存在
|
||||
var existUser models.User
|
||||
if err := common.GetDB().Where("phone = ?", req.Phone).First(&existUser).Error; err == nil {
|
||||
c.JSON(http.StatusOK, common.Error(400, "手机号已被注册"))
|
||||
return
|
||||
}
|
||||
|
||||
user := req.User
|
||||
|
||||
// 生成身份码(简单实现,实际应该使用更复杂的算法)
|
||||
user.IdentityCode = fmt.Sprintf("U%v", uuid.New().String()[:8])
|
||||
|
||||
// 密码加密(这里简单使用MD5,实际应该使用bcrypt)
|
||||
hashedPassword := fmt.Sprintf("%x", md5.Sum([]byte(user.Password)))
|
||||
user.Password = hashedPassword
|
||||
|
||||
// 默认为普通用户
|
||||
if user.SystemRole == 0 {
|
||||
user.SystemRole = 2
|
||||
|
||||
}
|
||||
user.Status = 0
|
||||
// 保存用户
|
||||
if err := common.GetDB().Create(&user).Error; err != nil {
|
||||
c.JSON(http.StatusOK, common.Error(500, "注册失败"))
|
||||
return
|
||||
}
|
||||
|
||||
common.GetDB().Model(&user).Update("status", 0)
|
||||
|
||||
c.JSON(http.StatusOK, common.Success(user))
|
||||
}
|
||||
|
||||
// GetCurrentUser 获取当前用户信息
|
||||
func (h *AuthHandler) GetCurrentUser(c *gin.Context) {
|
||||
// 从token中获取用户信息
|
||||
tokenMap, exists := c.Get("tokenMap")
|
||||
if !exists {
|
||||
c.JSON(http.StatusOK, common.Error(401, "未授权访问"))
|
||||
return
|
||||
}
|
||||
|
||||
claims := tokenMap.(map[string]interface{})
|
||||
userIDFloat, ok := claims["user_id"].(float64)
|
||||
if !ok {
|
||||
c.JSON(http.StatusOK, common.Error(401, "用户信息无效"))
|
||||
return
|
||||
}
|
||||
|
||||
userID := uint(userIDFloat)
|
||||
|
||||
// 查询用户信息
|
||||
var user models.User
|
||||
if err := common.GetDB().First(&user, userID).Error; err != nil {
|
||||
c.JSON(http.StatusOK, common.Error(404, "用户不存在"))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, common.Success(user))
|
||||
}
|
||||
|
||||
// UpdateProfileRequest 更新个人信息请求结构体
|
||||
type UpdateProfileRequest struct {
|
||||
CustomerName string `json:"customer_name" binding:"required"`
|
||||
RealName string `json:"real_name" binding:"required"`
|
||||
Avatar string `json:"avatar"`
|
||||
CompanyName string `json:"company_name"`
|
||||
PersonalIntro string `json:"personal_intro"`
|
||||
BusinessLicense string `json:"business_license"`
|
||||
IDCardFront string `json:"id_card_front"`
|
||||
IDCardBack string `json:"id_card_back"`
|
||||
MainPaymentCode string `json:"main_payment_code"`
|
||||
BackupPaymentCode string `json:"backup_payment_code"`
|
||||
Phone string `json:"phone"`
|
||||
}
|
||||
|
||||
// UpdateProfile 更新个人信息
|
||||
func (h *AuthHandler) UpdateProfile(c *gin.Context) {
|
||||
// 从token中获取用户信息
|
||||
tokenMap, exists := c.Get("tokenMap")
|
||||
if !exists {
|
||||
c.JSON(http.StatusOK, common.Error(401, "未授权访问"))
|
||||
return
|
||||
}
|
||||
|
||||
claims := tokenMap.(map[string]interface{})
|
||||
userIDFloat, ok := claims["user_id"].(float64)
|
||||
if !ok {
|
||||
c.JSON(http.StatusOK, common.Error(401, "用户信息无效"))
|
||||
return
|
||||
}
|
||||
|
||||
userID := uint(userIDFloat)
|
||||
|
||||
var req UpdateProfileRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusOK, common.Error(400, "参数错误: "+err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询当前用户
|
||||
var user models.User
|
||||
if err := common.GetDB().First(&user, userID).Error; err != nil {
|
||||
c.JSON(http.StatusOK, common.Error(404, "用户不存在"))
|
||||
return
|
||||
}
|
||||
|
||||
// 更新用户信息
|
||||
updateData := models.User{
|
||||
CustomerName: req.CustomerName,
|
||||
RealName: req.RealName,
|
||||
Avatar: req.Avatar,
|
||||
CompanyName: req.CompanyName,
|
||||
PersonalIntro: req.PersonalIntro,
|
||||
BusinessLicenseImage: req.BusinessLicense,
|
||||
IdCardFrontImage: req.IDCardFront,
|
||||
IdCardBackImage: req.IDCardBack,
|
||||
MainPaymentQrImage: &req.MainPaymentCode,
|
||||
SubPaymentQrImage: &req.BackupPaymentCode,
|
||||
Phone: req.Phone,
|
||||
}
|
||||
|
||||
updateData.ID = userID
|
||||
if err := common.GetDB().Model(&user).Updates(&updateData).Error; err != nil {
|
||||
c.JSON(http.StatusOK, common.Error(500, "更新个人信息失败"))
|
||||
return
|
||||
}
|
||||
|
||||
// 返回更新后的用户信息
|
||||
var updatedUser models.User
|
||||
common.GetDB().First(&updatedUser, userID)
|
||||
|
||||
c.JSON(http.StatusOK, common.Success(updatedUser))
|
||||
}
|
||||
|
||||
// ChangePasswordRequest 修改密码请求结构体
|
||||
type ChangePasswordRequest struct {
|
||||
CurrentPassword string `json:"current_password" binding:"required"`
|
||||
NewPassword string `json:"new_password" binding:"required"`
|
||||
}
|
||||
|
||||
// ChangePassword 修改密码
|
||||
func (h *AuthHandler) ChangePassword(c *gin.Context) {
|
||||
// 从token中获取用户信息
|
||||
tokenMap, exists := c.Get("tokenMap")
|
||||
if !exists {
|
||||
c.JSON(http.StatusOK, common.Error(401, "未授权访问"))
|
||||
return
|
||||
}
|
||||
|
||||
claims := tokenMap.(map[string]interface{})
|
||||
userIDFloat, ok := claims["user_id"].(float64)
|
||||
if !ok {
|
||||
c.JSON(http.StatusOK, common.Error(401, "用户信息无效"))
|
||||
return
|
||||
}
|
||||
|
||||
userID := uint(userIDFloat)
|
||||
|
||||
var req ChangePasswordRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusOK, common.Error(400, "参数错误: "+err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询当前用户
|
||||
var user models.User
|
||||
if err := common.GetDB().First(&user, userID).Error; err != nil {
|
||||
c.JSON(http.StatusOK, common.Error(404, "用户不存在"))
|
||||
return
|
||||
}
|
||||
|
||||
// 验证当前密码
|
||||
hashedCurrentPassword := fmt.Sprintf("%x", md5.Sum([]byte(req.CurrentPassword)))
|
||||
if hashedCurrentPassword != user.Password {
|
||||
c.JSON(http.StatusOK, common.Error(400, "当前密码错误"))
|
||||
return
|
||||
}
|
||||
|
||||
// 加密新密码
|
||||
hashedNewPassword := fmt.Sprintf("%x", md5.Sum([]byte(req.NewPassword)))
|
||||
|
||||
// 更新密码
|
||||
if err := common.GetDB().Model(&user).Update("password", hashedNewPassword).Error; err != nil {
|
||||
c.JSON(http.StatusOK, common.Error(500, "修改密码失败"))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, common.Success(nil))
|
||||
}
|
||||
|
||||
// SendSMSRequest 发送短信验证码请求结构体
|
||||
type SendSMSRequest struct {
|
||||
Phone string `json:"phone" binding:"required"`
|
||||
}
|
||||
|
||||
// SendSMS 发送短信验证码
|
||||
func (h *AuthHandler) SendSMS(c *gin.Context) {
|
||||
var req SendSMSRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusOK, common.Error(400, "参数错误: "+err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 获取客户端IP地址
|
||||
clientIP := getClientIP(c)
|
||||
|
||||
// 调用短信服务发送验证码
|
||||
smsService := services.GetSMSService()
|
||||
code, err := smsService.SendSMS(req.Phone, clientIP)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, common.Error(400, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 根据环境决定是否返回验证码(开发环境返回,生产环境不返回)
|
||||
config := common.MineConfig
|
||||
response := map[string]interface{}{
|
||||
"message": "验证码已发送",
|
||||
}
|
||||
|
||||
// 仅在开发环境返回验证码,方便测试
|
||||
if config != nil && config.App.Env == "development" {
|
||||
response["code"] = code
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, common.Success(response))
|
||||
}
|
||||
|
||||
// getClientIP 获取客户端真实IP地址
|
||||
func getClientIP(c *gin.Context) string {
|
||||
// 优先从 X-Forwarded-For 获取(经过代理时)
|
||||
ip := c.GetHeader("X-Forwarded-For")
|
||||
if ip != "" {
|
||||
// X-Forwarded-For 可能包含多个IP,取第一个
|
||||
ips := strings.Split(ip, ",")
|
||||
if len(ips) > 0 {
|
||||
return strings.TrimSpace(ips[0])
|
||||
}
|
||||
}
|
||||
|
||||
// 从 X-Real-IP 获取
|
||||
ip = c.GetHeader("X-Real-IP")
|
||||
if ip != "" {
|
||||
return strings.TrimSpace(ip)
|
||||
}
|
||||
|
||||
// 最后从 RemoteAddr 获取
|
||||
ip = c.ClientIP()
|
||||
return ip
|
||||
}
|
||||
Reference in New Issue
Block a user