Go是比較容易基於net/http來實現中間件的,比如現在要加一個http訪問的攔截器,可以對那些需要授權才能訪問的接口進行驗證。
比如:
func HTTPInterceptor(h http.HandlerFunc) http.HandlerFunc { return http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { r.ParseForm() // TODO: 進行身份驗證,比如校驗cookie或token
h(w, r) }) } // 然后在創建路由時類似這么調用: // http.HandleFunc("/test", HTTPInterceptor(YourCustomHandler))
而基於Gin框架來實現這個功能的話,也是非常簡單,只要注冊一個中間件函數即可。
只有注冊中間件之后的路由會被修飾,而注冊中間件之前的路由不會受影響;
具體示例如下:
package main import ( "github.com/gin-gonic/gin" "net/http" "crypto/md5" "encoding/hex" "strings" ) const ( // 可自定義鹽值 TokenSalt = "default_salt" ) func MD5(data []byte) string { _md5 := md5.New() _md5.Write(data) return hex.EncodeToString(_md5.Sum([]byte(""))) } func Authorize() gin.HandlerFunc{ return func(c *gin.Context){ username := c.Query("username") // 用戶名 ts := c.Query("ts") // 時間戳 token := c.Query("token") // 訪問令牌 if strings.ToLower(MD5([]byte(username+ts+TokenSalt))) == strings.ToLower(token) { // 驗證通過,會繼續訪問下一個中間件 c.Next() } else { // 驗證不通過,不再調用后續的函數處理 c.Abort() c.JSON(http.StatusUnauthorized,gin.H{"message":"訪問未授權"}) // return可省略, 只要前面執行Abort()就可以讓后面的handler函數不再執行 return } } } func ServiceWithoutAuth(c *gin.Context){ c.JSON(http.StatusOK, gin.H{"message":"這是一個不用經過認證就能訪問的接口"}) } func ServiceWithAuth(c *gin.Context){ c.JSON(http.StatusOK, gin.H{"message":"這是一個需要經過認證才能訪問的接口,看到此信息說明驗證已通過"}) } func main(){ router:=gin.Default() // Use(Authorize())之前的接口,都不用經過身份驗證 router.GET("/service_without_auth", ServiceWithoutAuth) //以下的接口,都使用Authorize()中間件身份驗證 router.Use(Authorize()) router.GET("/service_with_auth", ServiceWithAuth) router.Run(":9999") }
curl測試用例:
$ curl 'http://localhost:9999/service_with_auth?username=admin' {"message":"訪問未授權"} $ curl 'http://localhost:9999/service_without_auth?username=admin' {"message":"這是一個不用經過認證就能訪問的接口"} $ curl 'http://localhost:9999/service_with_auth?username=admin&ts=1552440940&token=142f0bee2b4a088fc93b5aee341b7c56' {"message":"這是一個需要經過認證才能訪問的接口,看到此信息說明驗證已通過"}