init
This commit is contained in:
357
serve/api/handlers/auth_handler.go
Normal file
357
serve/api/handlers/auth_handler.go
Normal file
@@ -0,0 +1,357 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Nanqipro/YunQue-Tech-Projects/ai_english_learning/serve/internal/common"
|
||||
"github.com/Nanqipro/YunQue-Tech-Projects/ai_english_learning/serve/internal/middleware"
|
||||
"github.com/Nanqipro/YunQue-Tech-Projects/ai_english_learning/serve/internal/models"
|
||||
"github.com/Nanqipro/YunQue-Tech-Projects/ai_english_learning/serve/internal/services"
|
||||
"github.com/Nanqipro/YunQue-Tech-Projects/ai_english_learning/serve/internal/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
type AuthHandler struct {
|
||||
userService *services.UserService
|
||||
validator *validator.Validate
|
||||
}
|
||||
|
||||
func NewAuthHandler(userService *services.UserService) *AuthHandler {
|
||||
return &AuthHandler{
|
||||
userService: userService,
|
||||
validator: validator.New(),
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterRequest 注册请求结构
|
||||
type RegisterRequest struct {
|
||||
Username string `json:"username" validate:"required,min=3,max=20"`
|
||||
Email string `json:"email" validate:"required,email"`
|
||||
Password string `json:"password" validate:"required,min=6"`
|
||||
Nickname string `json:"nickname" validate:"required,min=1,max=50"`
|
||||
}
|
||||
|
||||
// LoginRequest 登录请求结构
|
||||
type LoginRequest struct {
|
||||
Account string `json:"account" validate:"required"` // 用户名或邮箱
|
||||
Password string `json:"password" validate:"required"`
|
||||
}
|
||||
|
||||
// RefreshTokenRequest 刷新令牌请求结构
|
||||
type RefreshTokenRequest struct {
|
||||
RefreshToken string `json:"refresh_token" validate:"required"`
|
||||
}
|
||||
|
||||
// ChangePasswordRequest 修改密码请求结构
|
||||
type ChangePasswordRequest struct {
|
||||
OldPassword string `json:"old_password" validate:"required"`
|
||||
NewPassword string `json:"new_password" validate:"required,min=6"`
|
||||
}
|
||||
|
||||
// AuthResponse 认证响应结构
|
||||
type AuthResponse struct {
|
||||
User *UserInfo `json:"user"`
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
ExpiresIn int64 `json:"expires_in"`
|
||||
}
|
||||
|
||||
// UserInfo 用户信息结构
|
||||
type UserInfo struct {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Nickname string `json:"nickname"`
|
||||
Avatar string `json:"avatar"`
|
||||
Level string `json:"level"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// Register 用户注册
|
||||
func (h *AuthHandler) Register(c *gin.Context) {
|
||||
var req RegisterRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
common.ValidationErrorResponse(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证请求参数
|
||||
if err := h.validator.Struct(&req); err != nil {
|
||||
common.ValidationErrorResponse(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证邮箱格式
|
||||
if !utils.IsValidEmail(req.Email) {
|
||||
common.BadRequestResponse(c, "邮箱格式不正确")
|
||||
return
|
||||
}
|
||||
|
||||
// 验证密码强度
|
||||
if !utils.IsStrongPassword(req.Password) {
|
||||
common.BadRequestResponse(c, "密码强度不足,至少8位且包含大小写字母、数字和特殊字符")
|
||||
return
|
||||
}
|
||||
|
||||
// 创建用户
|
||||
user, err := h.userService.CreateUser(req.Username, req.Email, req.Password)
|
||||
if err != nil {
|
||||
if businessErr, ok := err.(*common.BusinessError); ok {
|
||||
common.ErrorResponse(c, http.StatusBadRequest, businessErr.Message)
|
||||
return
|
||||
}
|
||||
common.InternalServerErrorResponse(c, "用户创建失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 生成令牌
|
||||
accessToken, refreshToken, err := middleware.GenerateTokens(user.ID, user.Username, user.Email)
|
||||
if err != nil {
|
||||
common.InternalServerErrorResponse(c, "令牌生成失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 更新用户登录信息
|
||||
h.userService.UpdateLoginInfo(user.ID, utils.GetClientIP(c))
|
||||
|
||||
// 构造响应
|
||||
nickname := ""
|
||||
if user.Nickname != nil {
|
||||
nickname = *user.Nickname
|
||||
}
|
||||
avatar := ""
|
||||
if user.Avatar != nil {
|
||||
avatar = *user.Avatar
|
||||
}
|
||||
|
||||
userInfo := &UserInfo{
|
||||
ID: user.ID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
Nickname: nickname,
|
||||
Avatar: avatar,
|
||||
Level: "beginner",
|
||||
Status: user.Status,
|
||||
}
|
||||
|
||||
response := &AuthResponse{
|
||||
User: userInfo,
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresIn: 7200, // 2小时
|
||||
}
|
||||
|
||||
common.SuccessResponse(c, response)
|
||||
}
|
||||
|
||||
// Login 用户登录
|
||||
func (h *AuthHandler) Login(c *gin.Context) {
|
||||
var req LoginRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
common.ValidationErrorResponse(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证请求参数
|
||||
if err := h.validator.Struct(&req); err != nil {
|
||||
common.ValidationErrorResponse(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 根据账号类型获取用户
|
||||
var user *models.User
|
||||
var err error
|
||||
|
||||
if utils.IsValidEmail(req.Account) {
|
||||
user, err = h.userService.GetUserByEmail(req.Account)
|
||||
} else {
|
||||
user, err = h.userService.GetUserByUsername(req.Account)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if businessErr, ok := err.(*common.BusinessError); ok {
|
||||
common.ErrorResponse(c, http.StatusBadRequest, businessErr.Message)
|
||||
return
|
||||
}
|
||||
common.InternalServerErrorResponse(c, "用户查询失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 验证密码
|
||||
if !utils.CheckPasswordHash(req.Password, user.PasswordHash) {
|
||||
common.BadRequestResponse(c, "密码错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查用户状态
|
||||
if user.Status != "active" {
|
||||
common.BadRequestResponse(c, "用户已被禁用")
|
||||
return
|
||||
}
|
||||
|
||||
// 生成令牌
|
||||
accessToken, refreshToken, err := middleware.GenerateTokens(user.ID, user.Username, user.Email)
|
||||
if err != nil {
|
||||
common.InternalServerErrorResponse(c, "令牌生成失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 更新用户登录信息
|
||||
h.userService.UpdateLoginInfo(user.ID, utils.GetClientIP(c))
|
||||
|
||||
// 构造响应
|
||||
nickname := ""
|
||||
if user.Nickname != nil {
|
||||
nickname = *user.Nickname
|
||||
}
|
||||
avatar := ""
|
||||
if user.Avatar != nil {
|
||||
avatar = *user.Avatar
|
||||
}
|
||||
|
||||
userInfo := &UserInfo{
|
||||
ID: user.ID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
Nickname: nickname,
|
||||
Avatar: avatar,
|
||||
Level: "beginner",
|
||||
Status: user.Status,
|
||||
}
|
||||
|
||||
response := &AuthResponse{
|
||||
User: userInfo,
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresIn: 7200, // 2小时
|
||||
}
|
||||
|
||||
common.SuccessResponse(c, response)
|
||||
}
|
||||
|
||||
// RefreshToken 刷新访问令牌
|
||||
func (h *AuthHandler) RefreshToken(c *gin.Context) {
|
||||
var req RefreshTokenRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
common.ValidationErrorResponse(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证刷新令牌
|
||||
claims, err := middleware.ParseToken(req.RefreshToken)
|
||||
if err != nil {
|
||||
common.BadRequestResponse(c, "无效的刷新令牌")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查令牌类型
|
||||
if claims.Type != "refresh" {
|
||||
common.BadRequestResponse(c, "令牌类型错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 生成新的令牌
|
||||
accessToken, newRefreshToken, err := middleware.GenerateTokens(claims.UserID, claims.Username, claims.Email)
|
||||
if err != nil {
|
||||
common.InternalServerErrorResponse(c, "令牌生成失败")
|
||||
return
|
||||
}
|
||||
|
||||
response := map[string]interface{}{
|
||||
"access_token": accessToken,
|
||||
"refresh_token": newRefreshToken,
|
||||
"expires_in": 7200,
|
||||
}
|
||||
|
||||
common.SuccessResponse(c, response)
|
||||
}
|
||||
|
||||
// Logout 用户登出
|
||||
func (h *AuthHandler) Logout(c *gin.Context) {
|
||||
// 这里可以实现令牌黑名单机制
|
||||
// 目前简单返回成功
|
||||
common.SuccessResponse(c, map[string]string{"message": "登出成功"})
|
||||
}
|
||||
|
||||
// GetProfile 获取用户资料
|
||||
func (h *AuthHandler) GetProfile(c *gin.Context) {
|
||||
// 获取当前用户ID
|
||||
userID, exists := utils.GetUserIDFromContext(c)
|
||||
if !exists {
|
||||
common.BadRequestResponse(c, "请先登录")
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.userService.GetUserByID(userID)
|
||||
if err != nil {
|
||||
if businessErr, ok := err.(*common.BusinessError); ok {
|
||||
common.ErrorResponse(c, http.StatusBadRequest, businessErr.Message)
|
||||
return
|
||||
}
|
||||
common.InternalServerErrorResponse(c, "用户查询失败")
|
||||
return
|
||||
}
|
||||
|
||||
nickname := ""
|
||||
if user.Nickname != nil {
|
||||
nickname = *user.Nickname
|
||||
}
|
||||
avatar := ""
|
||||
if user.Avatar != nil {
|
||||
avatar = *user.Avatar
|
||||
}
|
||||
|
||||
userInfo := &UserInfo{
|
||||
ID: user.ID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
Nickname: nickname,
|
||||
Avatar: avatar,
|
||||
Level: "beginner",
|
||||
Status: user.Status,
|
||||
}
|
||||
|
||||
common.SuccessResponse(c, userInfo)
|
||||
}
|
||||
|
||||
// ChangePassword 修改密码
|
||||
func (h *AuthHandler) ChangePassword(c *gin.Context) {
|
||||
// 获取当前用户ID
|
||||
userID, exists := utils.GetUserIDFromContext(c)
|
||||
if !exists {
|
||||
common.BadRequestResponse(c, "请先登录")
|
||||
return
|
||||
}
|
||||
|
||||
var req ChangePasswordRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
common.ValidationErrorResponse(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证请求参数
|
||||
if err := h.validator.Struct(&req); err != nil {
|
||||
common.ValidationErrorResponse(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证新密码强度
|
||||
if !utils.IsStrongPassword(req.NewPassword) {
|
||||
common.BadRequestResponse(c, "新密码强度不够")
|
||||
return
|
||||
}
|
||||
|
||||
// 更新密码
|
||||
err := h.userService.UpdatePassword(userID, req.OldPassword, req.NewPassword)
|
||||
if err != nil {
|
||||
if businessErr, ok := err.(*common.BusinessError); ok {
|
||||
common.ErrorResponse(c, http.StatusBadRequest, businessErr.Message)
|
||||
return
|
||||
}
|
||||
common.InternalServerErrorResponse(c, "密码更新失败")
|
||||
return
|
||||
}
|
||||
|
||||
common.SuccessResponse(c, map[string]string{"message": "密码修改成功"})
|
||||
}
|
||||
Reference in New Issue
Block a user