package main
import (
"io"
"log"
"net/http"
)
type User string
func (u User) toString() string {
return string(u)
}
type AuthHandler func(u User, w http.ResponseWriter, r *http.Request)
func main() {
// Secured API
mux := http.NewServeMux()
mux.HandleFunc("/api/users", Secure(func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, `[{"id":"1","login":"ffghi"},{"id":"2","login":"ffghj"}]`)
}))
mux.HandleFunc("/api/profile", WithUser(func(u User, w http.ResponseWriter, r *http.Request) {
log.Println(u.toString())
io.WriteString(w, "{\"user\":\""+u.toString()+"\"}")
}))
http.ListenAndServe(":8080", mux)
}
func WithUser(h AuthHandler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user := r.Header.Get("X-User")
if len(user) == 0 {
w.WriteHeader(http.StatusUnauthorized)
return
}
h(User(user), w, r)
}
}
func Secure(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
sec := r.Header.Get("X-Auth")
if sec != "authenticated" {
w.WriteHeader(http.StatusUnauthorized)
return
}
h(w, r) // use the handler
}
}
/*
(sx3.5.3) ? ~ curl -X GET -I http://127.0.0.1:8080/api/users
HTTP/1.1 401 Unauthorized
Date: Mon, 26 Mar 2018 15:42:50 GMT
Content-Length: 0
Content-Type: text/plain; charset=utf-8
curl -X GET -w "\nStatus: %{http_code}\n" http://127.0.0.1:8080/api/users
Status: 401
curl -X GET -w "\nStatus: %{http_code}\n" http://127.0.0.1:8080/api/users -H "X-Auth: authenticated"
[{"id":"1","login":"ffghi"},{"id":"2","login":"ffghj"}]
Status: 200
(sx3.5.3) ? ~ curl -X GET -w "\nStatus: %{http_code}\n" http://127.0.0.1:8080/api/profile -H "X-User: zrd"
{"user":"zrd"}
Status: 200
*/
在前面的例子中中间件的实现利用函数为一等公民的Golang特色。原handlerfunc包装成一个handlerfunc检查x-auth头。安全功能是用来保护handlerfunc,用于servemux的handlefunc方法。
请注意,这只是一个简单的示例,但这种方式可以实现更复杂的解决方案。例如,用户的身份可以从标题标记和随后的提取,处理新类型可以定义为类AuthHandler func(U *用户,W http.responsewriter,R * HTTP请求)。功能的用户创建的servemux的handlerfunc。