Go是比較容易基于net/http來實作中間件的,比如現在要加一個http通路的攔截器,可以對那些需要授權才能通路的接口進行驗證。基于Gin架構來實作這個功能,隻要注冊一個中間件函數即可。
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":"這是一個需要經過認證才能通路的接口,看到此資訊說明驗證已認證"}