You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
225 lines
6.2 KiB
225 lines
6.2 KiB
package controller |
|
|
|
import ( |
|
"net/http" |
|
"strconv" |
|
"strings" |
|
|
|
"gofaster/internal/auth/model" |
|
"gofaster/internal/auth/service" |
|
"gofaster/internal/shared/response" |
|
|
|
"github.com/gin-gonic/gin" |
|
) |
|
|
|
type AuthController struct { |
|
authService service.AuthService |
|
} |
|
|
|
func NewAuthController(authService service.AuthService) *AuthController { |
|
return &AuthController{ |
|
authService: authService, |
|
} |
|
} |
|
|
|
// Login 用户登录 |
|
// @Summary 用户登录 |
|
// @Description 用户登录接口,支持验证码验证和密码错误次数限制 |
|
// @Tags 认证 |
|
// @Accept json |
|
// @Produce json |
|
// @Param request body model.LoginRequest true "登录请求参数" |
|
// @Success 200 {object} response.Response{data=model.LoginResponse} "登录成功" |
|
// @Failure 400 {object} response.Response "请求参数错误" |
|
// @Failure 401 {object} response.Response "认证失败" |
|
// @Failure 423 {object} response.Response "账户被锁定" |
|
// @Router /auth/login [post] |
|
func (c *AuthController) Login(ctx *gin.Context) { |
|
var req model.LoginRequest |
|
if err := ctx.ShouldBindJSON(&req); err != nil { |
|
response.Error(ctx, http.StatusBadRequest, "请求参数错误", err.Error()) |
|
return |
|
} |
|
|
|
// 获取客户端IP |
|
clientIP := getClientIP(ctx.Request) |
|
|
|
// 调用服务层处理登录 |
|
resp, err := c.authService.Login(ctx, &req, clientIP) |
|
if err != nil { |
|
// 根据错误类型返回不同的状态码 |
|
if isLockedError(err) { |
|
response.Error(ctx, http.StatusLocked, "账户被锁定", err.Error()) |
|
return |
|
} |
|
if isAuthError(err) { |
|
response.Error(ctx, http.StatusUnauthorized, "认证失败", err.Error()) |
|
return |
|
} |
|
response.Error(ctx, http.StatusInternalServerError, "系统错误", err.Error()) |
|
return |
|
} |
|
|
|
response.Success(ctx, "登录成功", resp) |
|
} |
|
|
|
// Logout 用户登出 |
|
// @Summary 用户登出 |
|
// @Description 用户登出接口 |
|
// @Tags 认证 |
|
// @Accept json |
|
// @Produce json |
|
// @Param request body model.LogoutRequest true "登出请求参数" |
|
// @Success 200 {object} response.Response "登出成功" |
|
// @Router /auth/logout [post] |
|
func (c *AuthController) Logout(ctx *gin.Context) { |
|
var req model.LogoutRequest |
|
if err := ctx.ShouldBindJSON(&req); err != nil { |
|
response.Error(ctx, http.StatusBadRequest, "请求参数错误", err.Error()) |
|
return |
|
} |
|
|
|
err := c.authService.Logout(ctx, req.Token) |
|
if err != nil { |
|
response.Error(ctx, http.StatusInternalServerError, "登出失败", err.Error()) |
|
return |
|
} |
|
|
|
response.Success(ctx, "登出成功", nil) |
|
} |
|
|
|
// RefreshToken 刷新访问令牌 |
|
// @Summary 刷新访问令牌 |
|
// @Description 使用刷新令牌获取新的访问令牌 |
|
// @Tags 认证 |
|
// @Accept json |
|
// @Produce json |
|
// @Param request body model.RefreshTokenRequest true "刷新令牌请求参数" |
|
// @Success 200 {object} response.Response{data=model.LoginResponse} "刷新成功" |
|
// @Failure 400 {object} response.Response "请求参数错误" |
|
// @Failure 401 {object} response.Response "刷新令牌无效" |
|
// @Router /auth/refresh [post] |
|
func (c *AuthController) RefreshToken(ctx *gin.Context) { |
|
var req model.RefreshTokenRequest |
|
if err := ctx.ShouldBindJSON(&req); err != nil { |
|
response.Error(ctx, http.StatusBadRequest, "请求参数错误", err.Error()) |
|
return |
|
} |
|
|
|
resp, err := c.authService.RefreshToken(ctx, req.RefreshToken) |
|
if err != nil { |
|
response.Error(ctx, http.StatusUnauthorized, "刷新令牌无效", err.Error()) |
|
return |
|
} |
|
|
|
response.Success(ctx, "令牌刷新成功", resp) |
|
} |
|
|
|
// GenerateCaptcha 生成验证码 |
|
// @Summary 生成验证码 |
|
// @Description 生成图形验证码,用于登录验证 |
|
// @Tags 认证 |
|
// @Produce json |
|
// @Success 200 {object} response.Response{data=model.CaptchaResponse} "验证码生成成功" |
|
// @Router /auth/captcha [get] |
|
func (c *AuthController) GenerateCaptcha(ctx *gin.Context) { |
|
resp, err := c.authService.GenerateCaptcha(ctx) |
|
if err != nil { |
|
response.Error(ctx, http.StatusInternalServerError, "验证码生成失败", err.Error()) |
|
return |
|
} |
|
|
|
response.Success(ctx, "验证码生成成功", resp) |
|
} |
|
|
|
// GetUserInfo 获取用户信息 |
|
// @Summary 获取用户信息 |
|
// @Description 获取当前登录用户的详细信息 |
|
// @Tags 认证 |
|
// @Accept json |
|
// @Produce json |
|
// @Security BearerAuth |
|
// @Success 200 {object} response.Response{data=model.UserInfo} "获取成功" |
|
// @Failure 401 {object} response.Response "未授权" |
|
// @Router /auth/userinfo [get] |
|
func (c *AuthController) GetUserInfo(ctx *gin.Context) { |
|
// 从JWT令牌中获取用户ID |
|
userID, exists := ctx.Get("user_id") |
|
if !exists { |
|
response.Error(ctx, http.StatusUnauthorized, "未授权", "用户ID不存在") |
|
return |
|
} |
|
|
|
// 转换用户ID类型 |
|
var uid uint |
|
switch v := userID.(type) { |
|
case float64: |
|
uid = uint(v) |
|
case int: |
|
uid = uint(v) |
|
case string: |
|
if parsed, err := strconv.ParseUint(v, 10, 32); err == nil { |
|
uid = uint(parsed) |
|
} else { |
|
response.Error(ctx, http.StatusBadRequest, "用户ID格式错误", err.Error()) |
|
return |
|
} |
|
default: |
|
response.Error(ctx, http.StatusBadRequest, "用户ID类型错误", "无法识别的用户ID类型") |
|
return |
|
} |
|
|
|
// 获取用户信息 |
|
userInfo, err := c.authService.GetUserInfo(ctx, uid) |
|
if err != nil { |
|
response.Error(ctx, http.StatusInternalServerError, "获取用户信息失败", err.Error()) |
|
return |
|
} |
|
|
|
response.Success(ctx, "获取用户信息成功", userInfo) |
|
} |
|
|
|
// getClientIP 获取客户端IP地址 |
|
func getClientIP(r *http.Request) string { |
|
// 尝试从各种头部获取真实IP |
|
ip := r.Header.Get("X-Real-IP") |
|
if ip != "" { |
|
return ip |
|
} |
|
|
|
ip = r.Header.Get("X-Forwarded-For") |
|
if ip != "" { |
|
// X-Forwarded-For可能包含多个IP,取第一个 |
|
if idx := strings.Index(ip, ","); idx != -1 { |
|
ip = ip[:idx] |
|
} |
|
return strings.TrimSpace(ip) |
|
} |
|
|
|
ip = r.Header.Get("X-Forwarded") |
|
if ip != "" { |
|
return ip |
|
} |
|
|
|
// 从RemoteAddr获取 |
|
if r.RemoteAddr != "" { |
|
if idx := strings.Index(r.RemoteAddr, ":"); idx != -1 { |
|
return r.RemoteAddr[:idx] |
|
} |
|
return r.RemoteAddr |
|
} |
|
|
|
return "127.0.0.1" |
|
} |
|
|
|
// isLockedError 检查是否为锁定错误 |
|
func isLockedError(err error) bool { |
|
return strings.Contains(err.Error(), "锁定") |
|
} |
|
|
|
// isAuthError 检查是否为认证错误 |
|
func isAuthError(err error) bool { |
|
return strings.Contains(err.Error(), "密码错误") || |
|
strings.Contains(err.Error(), "用户不存在") || |
|
strings.Contains(err.Error(), "验证码错误") |
|
}
|
|
|