engineercms分享文件提取码-参考蓝眼云盘

因为蓝眼云盘也是采用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一下的。