package authapi import ( "strings" "videoweb/app/service/authser" "videoweb/app/service/wordsfilterser" "videoweb/pub/common" "videoweb/pub/common/ipaddr" "videoweb/pub/common/srvdef" "videoweb/pub/common/useragent" "videoweb/pub/pubdef" "github.com/gin-gonic/gin" ) func requestUA(ctx *gin.Context) useragent.UA { ua, _ := common.GetUA(ctx) return ua } func applyRequestDevID(ua useragent.UA, devID string) useragent.UA { if v := strings.TrimSpace(devID); v != "" { ua.DevID = v } return ua } type registerReq struct { AccountNo string `json:"accountNo" binding:"required"` // 账号 Email string `json:"email" binding:"required"` // 邮箱 Password string `json:"password" binding:"required"` // 明文密码 AgentInviteCode string `json:"agentInviteCode"` // 邀请人的邀请码(可选) DevID string `json:"devID"` // 设备唯一标示(可选) Channel string `json:"channel"` // 渠道码(可选,用户无商区码时写入) } type loginReq struct { Account string `json:"account" binding:"required"` // 账号或邮箱 Password string `json:"password" binding:"required"` // 明文密码 DevID string `json:"devID"` // 设备唯一标示(可选) Channel string `json:"channel"` // 渠道码(可选,用户无商区码时写入) } type resetPasswordReq struct { AccountNo string `json:"accountNo" binding:"required"` // 账号 Email string `json:"email" binding:"required"` // 邮箱 NewPassword string `json:"newPassword" binding:"required"` // 新密码 } type updateProfileReq struct { NickName *string `json:"nickName"` // 新昵称(可选) Avatar *string `json:"avatar"` // 新头像 URL(可选) Introduction *string `json:"introduction"` // 简介(可选) PrivacyMode *bool `json:"privacyMode"` // 隐私模式:true-开启,false-关闭(可选) OldPassword *string `json:"oldPassword"` // 旧密码明文(已设置密码时修改必填) NewPassword *string `json:"newPassword"` // 新密码明文(设置或修改密码时必填) } // GuestLogin 游客登录 // @Tags 用户认证 // @Summary 游客登录 // @Description 按设备ID创建或找回游客账号;请求头可带 Authorization 复用已有游客会话。需传 X-User-Agent // @Accept json // @Produce json // @Param param body authser.GuestLoginReq true "游客登录参数" // @Success 200 {object} authser.LoginResp "成功" // @Failure 400 {string} string "失败" // @Router /api/app/auth/guest [POST] func GuestLogin(ctx *gin.Context) { var req authser.GuestLoginReq if err := ctx.ShouldBind(&req); err != nil { common.ServerJSON(ctx, srvdef.ErrParamError, nil) return } ua, err := common.GetUA(ctx) if err != nil { common.ServerJSON(ctx, srvdef.NoUA, nil) return } if req.DevID == "" { common.ServerJSON(ctx, srvdef.ErrParamError, "devID不能为空") return } ua.DevID = req.DevID resp, serr := authser.GuestLogin(ctx, common.GetUserId(ctx), ipaddr.ResolveClientIP(ctx), &req, ua) if serr != nil { common.ServerJSON(ctx, serr.Code, serr.Tips) return } common.ServerJSON(ctx, srvdef.Success, resp) } // Register 用户注册 // @Tags 用户认证 // @Summary 注册 // @Description 传入账号、邮箱、明文密码。请求头带游客 Authorization 时升级该游客为普通用户,否则新建用户 // @Accept json // @Produce json // @Param param body registerReq true "注册参数" // @Success 200 {object} authser.LoginResp "注册成功,返回 token 及用户基本信息" // @Failure 400 {string} string "失败" // @Router /api/app/auth/register [POST] func Register(ctx *gin.Context) { var req registerReq if err := ctx.ShouldBind(&req); err != nil { common.ServerJSON(ctx, srvdef.ErrParamError, nil) return } ua := applyRequestDevID(requestUA(ctx), req.DevID) resp, serr := authser.Register(ctx, common.GetUserId(ctx), req.AccountNo, req.Email, req.Password, req.AgentInviteCode, ua, ipaddr.ResolveClientIP(ctx), req.Channel) if serr != nil { common.ServerJSON(ctx, serr.Code, serr.Tips) return } common.ServerJSON(ctx, srvdef.Success, resp) } // Login 用户登录 // @Tags 用户认证 // @Summary 登录 // @Description 账号或邮箱均可作为登录凭证 // @Accept json // @Produce json // @Param param body loginReq true "登录参数" // @Success 200 {object} authser.LoginResp "登录成功,返回 token 及用户基本信息" // @Failure 400 {string} string "失败" // @Router /api/app/auth/login [POST] func Login(ctx *gin.Context) { var req loginReq if err := ctx.ShouldBind(&req); err != nil { common.ServerJSON(ctx, srvdef.ErrParamError, nil) return } ua := applyRequestDevID(requestUA(ctx), req.DevID) resp, serr := authser.Login(ctx, req.Account, req.Password, ua, ipaddr.ResolveClientIP(ctx), req.Channel) if serr != nil { common.ServerJSON(ctx, serr.Code, serr.Tips) return } common.ServerJSON(ctx, srvdef.Success, resp) } // UpdateProfile 修改用户资料 // @Tags 用户认证 // @Summary 修改用户资料(头像 / 简介 / 密码,可任意组合) // @Description 用户信息通过 token 获取,无需传账号;nickName、avatar、introduction、oldPassword+newPassword 均为可选,至少提供一项。未设置密码时传 newPassword 可设置密码,已设置密码时修改需传 oldPassword+newPassword // @Accept json // @Produce json // @Param param body updateProfileReq true "修改资料参数" // @Success 200 {string} string "成功" // @Failure 400 {string} string "失败" // @Router /api/app/auth/profile [POST] func UpdateProfile(ctx *gin.Context) { userId := common.GetUserId(ctx) if userId <= 0 { common.ServerJSON(ctx, srvdef.InvalidToken, nil) return } var req updateProfileReq if err := ctx.ShouldBind(&req); err != nil { common.ServerJSON(ctx, srvdef.ErrParamError, nil) return } if req.NickName != nil && !wordsfilterser.Validate(*req.NickName) { common.ServerJSON(ctx, srvdef.ErrContainIllegalWord, "包含非法字符") return } serr := authser.UpdateProfile(ctx, &authser.UpdateProfileReq{ UserId: userId, NickName: req.NickName, Avatar: req.Avatar, Introduction: req.Introduction, PrivacyMode: req.PrivacyMode, OldPassword: req.OldPassword, NewPassword: req.NewPassword, }) if serr != nil { common.ServerJSON(ctx, serr.Code, serr.Tips) return } common.ServerJSON(ctx, srvdef.Success, "") } // GetInfo 获取当前用户信息 // @Tags 用户认证 // @Summary 获取当前用户信息 // @Description 通过 token 获取最新用户信息,包含金币余额、VIP状态等 // @Produce json // @Success 200 {object} authser.LoginResp "用户信息" // @Failure 400 {string} string "失败" // @Router /api/app/auth/getInfo [GET] func GetInfo(ctx *gin.Context) { userId := common.GetUserId(ctx) if pubdef.IsCrawlerUser(userId) { common.ServerJSON(ctx, srvdef.Success, authser.CrawlerLoginResp("")) return } if userId <= 0 { common.ServerJSON(ctx, srvdef.InvalidToken, nil) return } resp, serr := authser.GetInfo(ctx, userId, requestUA(ctx)) if serr != nil { common.ServerJSON(ctx, serr.Code, serr.Tips) return } common.ServerJSON(ctx, srvdef.Success, resp) } // ResetPassword 找回密码 // @Tags 用户认证 // @Summary 找回密码 // @Description 通过账号和邮箱双重校验后重置密码,两者必须同时匹配同一用户 // @Accept json // @Produce json // @Param param body resetPasswordReq true "找回密码参数" // @Success 200 {string} string "成功" // @Failure 400 {string} string "失败" // @Router /api/app/auth/resetPassword [POST] func ResetPassword(ctx *gin.Context) { var req resetPasswordReq if err := ctx.ShouldBind(&req); err != nil { common.ServerJSON(ctx, srvdef.ErrParamError, nil) return } serr := authser.ResetPassword(ctx, req.AccountNo, req.Email, req.NewPassword) if serr != nil { common.ServerJSON(ctx, serr.Code, serr.Tips) return } common.ServerJSON(ctx, srvdef.Success, "") }