226 lines
4.7 KiB
Go
226 lines
4.7 KiB
Go
|
|
/**
|
|||
|
|
* package api
|
|||
|
|
* 作用:认证相关API处理器
|
|||
|
|
*/
|
|||
|
|
package api
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"xk-websocket-v2/internal/model"
|
|||
|
|
"xk-websocket-v2/internal/service"
|
|||
|
|
"xk-websocket-v2/internal/utils"
|
|||
|
|
|
|||
|
|
"github.com/gin-gonic/gin"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* LoginHandler
|
|||
|
|
* 功能:用户登录
|
|||
|
|
* 路径:POST /api/login
|
|||
|
|
*/
|
|||
|
|
func LoginHandler(c *gin.Context) {
|
|||
|
|
var req model.LoginReq
|
|||
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|||
|
|
utils.BadRequest(c, "参数错误: "+err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取客户端IP
|
|||
|
|
ip := getClientIP(c)
|
|||
|
|
|
|||
|
|
// 调用认证服务登录
|
|||
|
|
user, err := service.AuthSvc.Login(req.Account, req.Password)
|
|||
|
|
if err != nil {
|
|||
|
|
// 记录登录失败日志
|
|||
|
|
service.LoginLogSvc.LogLogin(req.Account, "0", ip, false)
|
|||
|
|
utils.Unauthorized(c, err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 生成Token
|
|||
|
|
token, err := utils.GenerateToken(user.ID)
|
|||
|
|
if err != nil {
|
|||
|
|
// 记录登录失败日志
|
|||
|
|
service.LoginLogSvc.LogLogin(req.Account, "0", ip, false)
|
|||
|
|
utils.InternalError(c, "生成Token失败")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 清除密码字段
|
|||
|
|
user.Password = ""
|
|||
|
|
|
|||
|
|
// 记录登录成功日志
|
|||
|
|
service.LoginLogSvc.LogLogin(req.Account, user.ID, ip, true)
|
|||
|
|
|
|||
|
|
utils.SuccessWithData(c, model.LoginResponse{
|
|||
|
|
Token: token,
|
|||
|
|
User: *user,
|
|||
|
|
}, "登录成功")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// getClientIP 获取客户端IP
|
|||
|
|
func getClientIP(c *gin.Context) string {
|
|||
|
|
// 优先从X-Forwarded-For获取
|
|||
|
|
ip := c.GetHeader("X-Forwarded-For")
|
|||
|
|
if ip != "" {
|
|||
|
|
return ip
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 从X-Real-IP获取
|
|||
|
|
ip = c.GetHeader("X-Real-IP")
|
|||
|
|
if ip != "" {
|
|||
|
|
return ip
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 从RemoteAddr获取
|
|||
|
|
return c.ClientIP()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* RegisterHandler
|
|||
|
|
* 功能:用户注册
|
|||
|
|
* 路径:POST /api/register
|
|||
|
|
*/
|
|||
|
|
func RegisterHandler(c *gin.Context) {
|
|||
|
|
var req model.RegisterReq
|
|||
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|||
|
|
utils.BadRequest(c, "参数错误: "+err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果提供了验证码,验证验证码
|
|||
|
|
if req.Code != "" {
|
|||
|
|
// 根据邮箱或手机号确定类型
|
|||
|
|
codeType := "email"
|
|||
|
|
if len(req.Phone) > 0 {
|
|||
|
|
codeType = "sms"
|
|||
|
|
}
|
|||
|
|
target := req.Email
|
|||
|
|
if codeType == "sms" {
|
|||
|
|
target = req.Phone
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
valid, err := service.AuthSvc.VerifyCode(target, req.Code, codeType)
|
|||
|
|
if err != nil || !valid {
|
|||
|
|
utils.BadRequest(c, "验证码无效或已过期")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 调用认证服务注册
|
|||
|
|
user, err := service.AuthSvc.Register(&req)
|
|||
|
|
if err != nil {
|
|||
|
|
utils.BadRequest(c, err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 生成Token
|
|||
|
|
token, err := utils.GenerateToken(user.ID)
|
|||
|
|
if err != nil {
|
|||
|
|
utils.InternalError(c, "生成Token失败")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
utils.SuccessWithData(c, model.RegisterResponse{
|
|||
|
|
Token: token,
|
|||
|
|
User: *user,
|
|||
|
|
}, "注册成功")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* LogoutHandler
|
|||
|
|
* 功能:用户登出(可选,前端清除token)
|
|||
|
|
* 路径:POST /api/logout
|
|||
|
|
*/
|
|||
|
|
func LogoutHandler(c *gin.Context) {
|
|||
|
|
// 登出主要是前端清除token,后端可以记录日志或清除session
|
|||
|
|
utils.Success(c, "登出成功")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* CheckTokenHandler
|
|||
|
|
* 功能:检查Token有效性
|
|||
|
|
* 路径:GET /api/check-token
|
|||
|
|
*/
|
|||
|
|
func CheckTokenHandler(c *gin.Context) {
|
|||
|
|
token := c.GetHeader("Authorization")
|
|||
|
|
if token == "" {
|
|||
|
|
utils.Unauthorized(c, "缺少Token")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 移除 "Bearer " 前缀(如果存在)
|
|||
|
|
if len(token) > 7 && token[:7] == "Bearer " {
|
|||
|
|
token = token[7:]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
userID, err := utils.ValidateToken(token)
|
|||
|
|
if err != nil {
|
|||
|
|
utils.Unauthorized(c, "Token无效或已过期")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
utils.SuccessWithData(c, gin.H{
|
|||
|
|
"status": "valid",
|
|||
|
|
"user_id": userID,
|
|||
|
|
}, "Token有效")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* SendEmailCodeHandler
|
|||
|
|
* 功能:发送邮箱验证码
|
|||
|
|
* 路径:POST /api/send-email-code
|
|||
|
|
*/
|
|||
|
|
func SendEmailCodeHandler(c *gin.Context) {
|
|||
|
|
var req model.SendCodeReq
|
|||
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|||
|
|
utils.BadRequest(c, "参数错误: "+err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if req.Type != "email" {
|
|||
|
|
utils.BadRequest(c, "类型必须是email")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
code, err := service.AuthSvc.SendEmailCode(req.Target)
|
|||
|
|
if err != nil {
|
|||
|
|
utils.InternalError(c, err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 开发环境返回验证码,生产环境不应返回
|
|||
|
|
utils.SuccessWithData(c, gin.H{
|
|||
|
|
"code": code, // 仅开发环境,生产环境应移除
|
|||
|
|
}, "验证码已发送")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* SendSmsCodeHandler
|
|||
|
|
* 功能:发送短信验证码
|
|||
|
|
* 路径:POST /api/send-sms-code
|
|||
|
|
*/
|
|||
|
|
func SendSmsCodeHandler(c *gin.Context) {
|
|||
|
|
var req model.SendCodeReq
|
|||
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|||
|
|
utils.BadRequest(c, "参数错误: "+err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if req.Type != "sms" {
|
|||
|
|
utils.BadRequest(c, "类型必须是sms")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
code, err := service.AuthSvc.SendSmsCode(req.Target)
|
|||
|
|
if err != nil {
|
|||
|
|
utils.InternalError(c, err.Error())
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 开发环境返回验证码,生产环境不应返回
|
|||
|
|
utils.SuccessWithData(c, gin.H{
|
|||
|
|
"code": code, // 仅开发环境,生产环境应移除
|
|||
|
|
}, "验证码已发送")
|
|||
|
|
}
|
|||
|
|
|