DownloadAIUploadFile 下载 AI 上传文件 @Summary 下载 AI 上传文件 @Description 下载指定的 AI 上传文件内容 @Tags Message @Accept json @Produce octet-stream @Param id path int true "文件ID" @Success 200 {file} binary @Router /api/upload-files/{id}/download [get] @Security BearerAuth
(c *gin.Context)
| 843 | // @Router /api/upload-files/{id}/download [get] |
| 844 | // @Security BearerAuth |
| 845 | func DownloadAIUploadFile(c *gin.Context) { |
| 846 | // 支持 HashID 和整数ID |
| 847 | idStr := c.Param("id") |
| 848 | fileID, err := hashids.TryParseID(idStr) |
| 849 | if err != nil { |
| 850 | c.JSON(http.StatusBadRequest, model.ParamError.ToResponse(errors.New("无效的文件ID"))) |
| 851 | return |
| 852 | } |
| 853 | |
| 854 | // 获取文件记录 |
| 855 | file, err := model.GetAIUploadFileByID(fileID) |
| 856 | if err != nil { |
| 857 | c.JSON(http.StatusNotFound, model.NotFound.ToResponse(err)) |
| 858 | return |
| 859 | } |
| 860 | |
| 861 | // 签名下载(支持无登录态访问或用户 token) |
| 862 | downloadToken := strings.TrimSpace(c.Query("token")) |
| 863 | if downloadToken != "" { |
| 864 | requestedFileName := strings.TrimSpace(c.Param("filename")) |
| 865 | expectedFileName := path.Base(strings.TrimSpace(file.FileName)) |
| 866 | if requestedFileName == "" { |
| 867 | requestedFileName = expectedFileName |
| 868 | } |
| 869 | if path.Base(requestedFileName) != expectedFileName { |
| 870 | c.JSON(http.StatusForbidden, model.ForbiddenError.ToResponse(errors.New("文件名不匹配"))) |
| 871 | return |
| 872 | } |
| 873 | |
| 874 | // 尝试解析为用户 access token |
| 875 | userID, userEid, jwtErr := jwt.UserParseJWT(downloadToken) |
| 876 | if jwtErr == nil && userID > 0 && userEid > 0 { |
| 877 | user := model.ValidateAccessToken(downloadToken) |
| 878 | if user != nil && user.UserID == userID && user.Eid == file.Eid { |
| 879 | serveUploadFile(c, file) |
| 880 | return |
| 881 | } |
| 882 | // 用户存在但企业不匹配,直接拒绝 |
| 883 | if user != nil && user.Eid != file.Eid { |
| 884 | c.JSON(http.StatusForbidden, model.ForbiddenError.ToResponse(errors.New("无权访问该文件"))) |
| 885 | return |
| 886 | } |
| 887 | // user == nil: token 已失效,继续尝试 sandbox token |
| 888 | } |
| 889 | |
| 890 | // 尝试解析为临时下载 token |
| 891 | if err := sandboxdl.ValidateDownloadToken(downloadToken, file.ID, expectedFileName); err != nil { |
| 892 | c.JSON(http.StatusUnauthorized, model.UnauthorizedError.ToResponse(err)) |
| 893 | return |
| 894 | } |
| 895 | serveUploadFile(c, file) |
| 896 | return |
| 897 | } |
| 898 | |
| 899 | // Bearer 鉴权下载(兼容旧逻辑) |
| 900 | token := strings.TrimSpace(c.GetHeader("Authorization")) |
| 901 | token = strings.TrimSpace(strings.TrimPrefix(token, "Bearer ")) |
| 902 | if token == "" { |
nothing calls this directly
no test coverage detected