一句话总结就是:增加一个装饰器函数 BasicAuth 装饰需要被保护的函数。
package main
import (
"bytes"
"encoding/base64"
"io"
"log"
"net/http"
"strings"
)
type ViewFunc func(http.ResponseWriter, *http.Request)
func BasicAuth(f ViewFunc, user, passwd []byte) ViewFunc {
return func(w http.ResponseWriter, r *http.Request) {
basicAuthPrefix := "Basic "
// 获取 request header
auth := r.Header.Get("Authorization")
// 如果是 http basic auth
if strings.HasPrefix(auth, basicAuthPrefix) {
// 解码认证信息
payload, err := base64.StdEncoding.DecodeString(
auth[len(basicAuthPrefix):],
)
if err == nil {
pair := bytes.SplitN(payload, []byte(":"), 2)
if len(pair) == 2 && bytes.Equal(pair[0], user) &&
bytes.Equal(pair[1], passwd) {
// 执行被装饰的函数
f(w, r)
return
}
}
}
// 认证失败,提示 401 Unauthorized
// Restricted 可以改成其他的值
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
// 401 状态码
w.WriteHeader(http.StatusUnauthorized)
}
}
// 需要被保护的内容
func HelloServer(w http.ResponseWriter, req *http.Request) {
io.WriteString(w, "hello, world!\n")
}
func main() {
user := []byte("foo")
passwd := []byte("bar")
// 装饰需要保护的 handler
http.HandleFunc("/hello", BasicAuth(HelloServer, user, passwd))
log.Println("Listen :8000")
err := http.ListenAndServe(":8000", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
效果¶
未输入用户名和密码的情况下,提示未认证:
~$ curl -i http://127.0.0.1:8000/hello
HTTP/1.1 401 Unauthorized
Www-Authenticate: Basic realm="Restricted"
Date: Mon, 06 Apr 2015 11:56:10 GMT
Content-Length: 0
Content-Type: text/plain; charset=utf-8
输入用户名和密码,显示被保护的内容:
~$ curl -i --user "foo:bar" http://127.0.0.1:8000/hello
HTTP/1.1 200 OK
Date: Mon, 06 Apr 2015 11:56:23 GMT
Content-Length: 14
Content-Type: text/plain; charset=utf-8
hello, world!
Comments