fix: P0-07 complete frontend TOTP login flow

Backend changes:
- Add VerifyTOTPAfterPasswordLogin handler in auth_handler.go
- Add route /auth/login/totp-verify in router.go

Frontend changes:
- Update TokenBundle type to include requires_totp and user_id fields
- Add TOTPVerifyRequest type for TOTP verification
- Add verifyTOTPAfterPasswordLogin() API function

New login flow when user has TOTP enabled:
1. loginByPassword returns {requires_totp: true, user_id: <id>}
2. Frontend prompts user for TOTP code
3. Frontend calls verifyTOTPAfterPasswordLogin({user_id, code})
4. If TOTP valid, full TokenBundle with tokens is returned
This commit is contained in:
2026-04-18 14:50:25 +08:00
parent 4acd19f420
commit 9d7abb8a46
4 changed files with 52 additions and 0 deletions

View File

@@ -132,6 +132,41 @@ func (h *AuthHandler) Login(c *gin.Context) {
})
}
// VerifyTOTPAfterPasswordLogin 完成密码登录后的TOTP验证
// @Summary TOTP验证密码登录后
// @Description 当登录返回requires_totp=true时使用此接口完成TOTP验证
// @Tags 认证
// @Accept json
// @Produce json
// @Param request body TOTPVerifyRequest true "TOTP验证请求"
// @Success 200 {object} Response{data=service.LoginResponse} "验证成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 401 {object} Response "TOTP验证失败"
// @Router /api/v1/auth/login/totp-verify [post]
func (h *AuthHandler) VerifyTOTPAfterPasswordLogin(c *gin.Context) {
var req struct {
UserID int64 `json:"user_id" binding:"required"`
Code string `json:"code" binding:"required"`
DeviceID string `json:"device_id"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "message": err.Error()})
return
}
resp, err := h.authService.VerifyTOTPAfterPasswordLogin(c.Request.Context(), req.UserID, req.Code, req.DeviceID)
if err != nil {
handleError(c, err)
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "success",
"data": resp,
})
}
// Logout 用户登出
// @Summary 用户登出
// @Description 使当前 access_token 和 refresh_token 失效