仿Gin搭建自己的web框架(七)
本篇介紹HTTP Basic Auth的實(shí)現(xiàn)以及Recovery機(jī)制。
HTTP Basic Auth
Basic Auth是一種開放平臺認(rèn)證方式,簡單的說就是需要你輸入用戶名和密碼才能繼續(xù)訪問。對于Basic Auth的概念不過多的進(jìn)行介紹,直接進(jìn)入如何實(shí)現(xiàn)的過程。
Basic Auth說白了就是賬號和密碼的組合,所以定義用來存儲賬號和密碼的結(jié)構(gòu)體。
type (// BasicAuthPair .BasicAuthPair struct {Code stringUser string}// Account .Account struct {User stringPassword string}// Accounts .Accounts []Account// Pairs .Pairs []BasicAuthPair ) 復(fù)制代碼其中, Accounts 用來存放原始原始的賬號密碼組合, Pairs 用來存經(jīng)過編碼的賬號密碼組合。
Basic Auth初始化的過程,就是將 “賬號:密碼” 串經(jīng)過base64編碼之后,存放在Pairs中。
func processCredentials(accounts Accounts) (Pairs, error) {if len(accounts) == 0 {return nil, errors.New("Empty list of authorized credentials.")}pairs := make(Pairs, 0, len(accounts))for _, account := range accounts {if len(account.User) == 0 || len(account.Password) == 0 {return nil, errors.New("User or password is empty")}base := account.User + ":" + account.Passwordcode := "Basic " + base64.StdEncoding.EncodeToString([]byte(base))pairs = append(pairs, BasicAuthPair{code, account.User})}// We have to sort the credentials in order to use bsearch later.sort.Sort(pairs)return pairs, nil } 復(fù)制代碼在訪問對應(yīng)url的時候,會提取auth字段,然后將auth字段在我們保存的Pairs 中進(jìn)行比對查找,如果找到了,就會返回對應(yīng)的user
func searchCredential(pairs Pairs, auth string) string {if len(auth) == 0 {return ""}// Search user in the slice of allowed credentialsr := sort.Search(len(pairs), func(i int) bool { return pairs[i].Code >= auth })if r < len(pairs) && subtle.ConstantTimeCompare([]byte(pairs[r].Code), []byte(auth)) == 1 {// user is allowed, set UserId to key "user" in this context, the userId can be read later using// c.Get("user"return pairs[r].User}return "" } 復(fù)制代碼相應(yīng)的, 如果我們需要對一個 url 開啟Basic Auth認(rèn)證,首先定義一個路由組,調(diào)用對應(yīng)的Basic Auth的中間件函數(shù)。
accounts := gin.Accounts{{User: "admin", Password: "password"},{User: "foo", Password: "bar"},} authorized := r.Group("/auth", gin.BasicAuth(accounts)) 復(fù)制代碼然后把需要認(rèn)證的url都掛在下邊
authorized.GET("/secret", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"secret": "The secret url need to be authorized",}) }) 復(fù)制代碼這樣當(dāng)我們訪問 /auth/secret 的時候,就需要經(jīng)過Basic Auth的認(rèn)證。如果我們在瀏覽器端訪問,會彈出一個提示框,要求輸入賬號和密碼; 如果是在 postman 等工具中訪問, 需要在header中添加一個 Authorization 字段,字段的值是 “Basic 賬號:密碼的base64編碼”。 比如賬號是admin, 密碼是password, 那么“admin:password” 經(jīng)過base64編碼的結(jié)果是“YWRtaW46cGFzc3dvcmQ=”, 所以對應(yīng)的Authorization填的值應(yīng)該是 “Basic YWRtaW46cGFzc3dvcmQ=”。
Recovery
Recovery在web框架中也是一個必不可少的中間件,如果某個請求出現(xiàn)了panic,服務(wù)需要捕獲請求中的panic信息,并且把信息打印到日志中,有利于后期的維護(hù)和修復(fù)。
Recovery 其實(shí)就是定義了一個defer函數(shù)來處理請求中的panic,在defer中,會通過golang的recover() 函數(shù)catch住panic,然后將對應(yīng)的棧信息打印出來。
func Recovery() HandlerFunc {return func(c *Context) {defer func() {if len(c.Errors) > 0 {log.Println(c.Errors)}if err := recover(); err != nil {stack := stack(3)log.Printf("PANIC: %s\n%s", err, stack)c.Writer.WriteHeader(http.StatusInternalServerError)}}()c.Next()} } 復(fù)制代碼一般來說,log中間件和recovery中間件都是必須的,所以可以定義一個默認(rèn)的框架初始化函數(shù),自動把log中間件和recovery中間件加載進(jìn)去。
// Default Returns a Engine instance with the Logger and Recovery already attached. func Default() *Engine {engine := New()engine.Use(Recovery(), Logger())return engine } 復(fù)制代碼至此,一個簡易版本的gin web框架就成型了,包括最基本的日志功能、錯誤恢復(fù)、路由功能、認(rèn)證功能等。當(dāng)然也可以在這個基礎(chǔ)之上在增加ORM等模塊,當(dāng)是后續(xù)的功能擴(kuò)展了。
完整的代碼參見: github.com/harleylau/m…
總結(jié)
以上是生活随笔為你收集整理的仿Gin搭建自己的web框架(七)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Asia Yokohama Region
- 下一篇: 博鳌“‘AI+时代’来了吗”分论坛,嘉宾