使用Golang服务器阻止对文件夹中文件的访问。

huangapple go评论88阅读模式
英文:

prevent access to files in folder with a golang server

问题

我有一个使用golang编写的服务器,处理文件夹路径的方式如下:

fs := http.FileServer(http.Dir("./assets"))
http.Handle("/Images/", fs)
http.ListenAndServe(":8000", nil)

但是在这个文件夹中有私有图片,不应该允许访问这些文件。那么我该如何保护图片的访问,并防止任何人访问文件夹中的内容呢?

例如,像这样:

使用Golang服务器阻止对文件夹中文件的访问。

英文:

I've a server in golang who handle folder path like that :

fs := http.FileServer(http.Dir("./assets"))
http.Handle("/Images/", fs)
http.ListenAndServe(":8000", nil)

But in this folder there are privates images, and it shouldn't be possible to access files. So how can i secure image access and prevent anybody to access content of folder.

like that for example :

使用Golang服务器阻止对文件夹中文件的访问。

答案1

得分: 2

如果你想使用http包来阻止一个目录,也许这个代码对你有用:

package main

import (
	"net/http"
	"os"
)

type justFilesFilesystem struct {
	fs http.FileSystem
}

func (fs justFilesFilesystem) Open(name string) (http.File, error) {
	f, err := fs.fs.Open(name)
	if err != nil {
		return nil, err
	}
	return neuteredReaddirFile{f}, nil
}

type neuteredReaddirFile struct {
	http.File
}

func (f neuteredReaddirFile) Readdir(count int) ([]os.FileInfo, error) {
	return nil, nil
}

func main() {
	fs := justFilesFilesystem{http.Dir("/tmp/")}
	http.ListenAndServe(":8080", http.FileServer(fs))
}

这段代码可以用来阻止指定目录的访问。你可以将要阻止的目录路径替换为"/tmp/",然后运行该代码,它将在本地的8080端口上启动一个HTTP服务器,该服务器将只提供指定目录下的文件,而不会提供目录的列表。

英文:

If you want to block a directory using http package, maybe this will be useful to you :

> https://groups.google.com/forum/#!topic/golang-nuts/bStLPdIVM6w
>
>
> package main
>
> import (
> "net/http"
> "os"
> )
>
> type justFilesFilesystem struct {
> fs http.FileSystem
> }
>
> func (fs justFilesFilesystem) Open(name string) (http.File, error) {
> f, err := fs.fs.Open(name)
> if err != nil {
> return nil, err
> }
> return neuteredReaddirFile{f}, nil
> }
>
> type neuteredReaddirFile struct {
> http.File
> }
>
> func (f neuteredReaddirFile) Readdir(count int) ([]os.FileInfo, error) {
> return nil, nil
> }
>
> func main() {
> fs := justFilesFilesystem{http.Dir("/tmp/")}
> http.ListenAndServe(":8080", http.FileServer(fs))
> }

答案2

得分: 1

一个简单的FileServer()包装器可以解决你的问题,现在你需要添加一些逻辑来进行授权。看起来你有唯一的名称,这很好,所以我为你创建了一个名称映射,现在你可以添加一些更动态的东西,比如一个键/存储(如memcached、redis等)。希望你能理解这些注释。

package main

import (
	"log"
	"net/http"
	"strings"
)

// 在这里放置允许的哈希或键
// 你可以考虑将它们放在一个键/值存储中
//
var allowedImages = map[string]bool{
	"key-abc.jpg": true,
	"key-123.jpg": true,
}

func main() {

	http.Handle("/Images/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

		// 在这里我们可以进行任何类型的检查,在这种情况下,我们将只是拆分URL并
		// 检查图像名称是否在allowedImages映射中,我们可以在数据库或其他地方进行检查
		//
		parts := strings.Split(r.URL.Path, "/")
		imgName := parts[len(parts)-1]

		if _, contains := allowedImages[imgName]; !contains { // 如果映射包含图像名称
		
			log.Printf("未找到图像:%q 路径:%s\n", imgName, r.URL.Path)

			// 如果找不到图像,我们写入一个404
			//
			// 奖励:我们不列出目录,所以没有人能知道里面有什么 :)
			//
			http.NotFound(w, r)
			return
		}

		log.Printf("提供允许的图像:%q\n", imgName)

		fileServer := http.StripPrefix("/Images/", http.FileServer(http.Dir("./assets")))

		fileServer.ServeHTTP(w, r) // StripPrefix()和FileServer()返回一个实现ServerHTTP()的处理程序
	}))

	http.ListenAndServe(":8000", nil)
}

你可以在这里查看代码:https://play.golang.org/p/ehrd_AWXim

英文:

A little wrapper over FileServer() solves your problem, now you have to add some sort of logic to do Authorization, it looks like you have unique names, that's good, so I just filter the image name for you creating a map of names, now you can add something more dynamic like a key/store(memcached, redis. etc.) Hope you can follow the comments

package main

import (
	"log"
	"net/http"
	"strings"
)

// put the allowed hashs or keys here
// you may consider put them in a key/value store
//
var allowedImages = map[string]bool{
	"key-abc.jpg": true,
	"key-123.jpg": true,
}

func main() {

	http.Handle("/Images/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

		// here we can do any kind of checking, in this case we'll just split the url and
		// check if the image name is in the allowedImages map, we can check in a DB or something
		//
		parts := strings.Split(r.URL.Path, "/")
		imgName := parts[len(parts)-1]

		if _, contains := allowedImages[imgName]; !contains { // if the map contains the image name
		
			log.Printf("Not found image: %q path: %s\n", imgName, r.URL.Path)

			// if the image is not found we write a 404
			//
			// Bonus: we don't list the directory, so nobody can know what's inside :)
			//
			http.NotFound(w, r)
			return
		}

		log.Printf("Serving allowed image: %q\n", imgName)

		fileServer := http.StripPrefix("/Images/", http.FileServer(http.Dir("./assets")))

		fileServer.ServeHTTP(w, r) // StripPrefix() and FileServer() return a Handler that implements ServerHTTP()
	}))

	http.ListenAndServe(":8000", nil)
}

https://play.golang.org/p/ehrd_AWXim

huangapple
  • 本文由 发表于 2016年11月21日 17:34:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/40716869.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定