engineercms分享文件提取碼-參考藍眼雲盤
- 2020 年 3 月 6 日
- 筆記
因為藍眼雲盤也是採用go語言+gorm編寫的,所以參考起來稍微輕鬆一點。主要還是了解如何通過一段提取碼就能取到文件的訪問權。
生成一個分享文件uuid和提取碼code。服務端接受選擇的文件或文件夾id,隨機生成一個share uuid和提取碼code,返回給頁面:服務端寫入數據表share和bridge,前者存share uuid和分享者id,及過期時間expiretime,還有是否永久有效。後者存儲share uuid和對應的文件id,一對多。

用戶通過這個鏈接地址,瀏覽器請求服務端,服務端判斷用戶有無登錄——如果登錄,再判斷這個分享是不是這個登錄用戶創建。如果沒登錄,則需要提取碼code。
當輸入code後,服務根據share uuid,和code,通過讀取share數據表,如果符合,則根據share uuid取出bridge里的文件列表
當用戶全部打包下載,或下載其中一個,怎麼處理邏輯呢?再通過share uuid和code做一次判斷么?
// check whether shareUuid and shareCode matches. check whether user can access. func (this *ShareService) CheckShare(request *http.Request, shareUuid string, code string, user *User) *Share { share := this.shareDao.CheckByUuid(shareUuid) //if self, not need shareCode if user == nil || user.Uuid != share.UserUuid { //if not login or not self's share, shareCode is required. if code == "" { panic(result.CustomWebResultI18n(request, result.NEED_SHARE_CODE, i18n.ShareCodeRequired)) } else if share.Code != code { panic(result.CustomWebResultI18n(request, result.SHARE_CODE_ERROR, i18n.ShareCodeError)) } else { if !share.ExpireInfinity { if share.ExpireTime.Before(time.Now()) { panic(result.BadRequest("share expired")) } } } } return share }如果是自己,就不需要提取碼,不是自己的,或者沒有登錄,就判斷提取碼,如果有提取碼,就和資料庫中存的對比,如果正確,再判斷有效期,如果是永遠的,則不需要判斷過期時間。如果不是永遠有效的,則看看資料庫里的過期時間跟當前時間對比。
上面的邏輯相當於通過認證後,提供給頁面的文件或文件列表。
那麼下載也差不多是這個邏輯,也是要判斷code。
func (this *ShareController) Zip(writer http.ResponseWriter, request *http.Request) *result.WebResult { shareUuid := request.FormValue("shareUuid") code := request.FormValue("code") puuid := request.FormValue("puuid") rootUuid := request.FormValue("rootUuid") user := this.findUser(request) if puuid == MATTER_ROOT { //download all things. share := this.shareService.CheckShare(request, shareUuid, code, user) bridges := this.bridgeDao.FindByShareUuid(share.Uuid) var matterUuids []string for _, bridge := range bridges { matterUuids = append(matterUuids, bridge.MatterUuid) } matters := this.matterDao.FindByUuids(matterUuids, nil) this.matterService.DownloadZip(writer, request, matters) } else { //download a folder. matter := this.matterDao.CheckByUuid(puuid) this.shareService.ValidateMatter(request, shareUuid, code, user, rootUuid, matter) this.matterService.DownloadZip(writer, request, []*Matter{matter}) } return nil }也是先要checkshare,然後再去bridge數據表裡取出文件或文件的id……如果是文件夾,則用validatematter判斷,也是一樣的:
//check whether a user can access a matter. shareRootUuid is matter's parent(or parent's parent and so on) func (this *ShareService) ValidateMatter(request *http.Request, shareUuid string, code string, user *User, shareRootUuid string, matter *Matter) { if matter == nil { panic(result.Unauthorized("matter cannot be nil")) } //if self's matter, ok. if user != nil && matter.UserUuid == user.Uuid { return } if shareUuid == "" || code == "" || shareRootUuid == "" { panic(result.Unauthorized("shareUuid,code,shareRootUuid cannot be null")) } share := this.CheckShare(request, shareUuid, code, user) //if shareRootUuid is root. Bridge must has record. if shareRootUuid == MATTER_ROOT { this.bridgeDao.CheckByShareUuidAndMatterUuid(share.Uuid, matter.Uuid) } else { //check whether shareRootMatter is being sharing shareRootMatter := this.matterDao.CheckByUuid(shareRootUuid) this.bridgeDao.CheckByShareUuidAndMatterUuid(share.Uuid, shareRootMatter.Uuid) // shareRootMatter is ancestor of matter. child := strings.HasPrefix(matter.Path, shareRootMatter.Path) if !child { panic(result.BadRequest("%s is not %s's children", matter.Uuid, shareRootUuid)) } } }也是要checkshare一下的。
