373 lines
9.8 KiB
Go
373 lines
9.8 KiB
Go
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
|
|
}
|