gin源码阅读(一)- auth.go

详细介绍

auth.go

基本信息验证功能,具体介绍可参考https://zhuanlan.zhihu.com/p/...
auth.go对外提供了接口BasicAuthBasicAuthForRealm, 这两个接口以中间件的方式提供默认的账号供使用。

func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc {
    if realm == "" {
        realm = "Authorization Required"
    }
    realm = "Basic realm=" + strconv.Quote(realm) 
    pairs := processAccounts(accounts) //处理账号信息
    return func(c *Context) {
        // Search user in the slice of allowed credentials
        user, found := pairs.searchCredential(c.requestHeader("Authorization")) 
        if !found {
            // Credentials doesn't match, we return 401 and abort handlers chain.
            c.Header("WWW-Authenticate", realm)
            c.AbortWithStatus(http.StatusUnauthorized)
            return
        }

        // The user credentials was found, set user's id to key AuthUserKey in this context, the user's id can be read later using
        // c.MustGet(gin.AuthUserKey).
        c.Set(AuthUserKey, user)
    }
}

strconv.Quote() 这个方法的主要作用是把字符串转成带双引号的字符串,该功能在转结构体字符串时比较实用,例如:

   a := A{
        A: "test",
        B: 18,
    }
    by, err := json.Marshal(a)
    if err != nil {
        return
    }
    str := string(by)
    fmt.Println(str)
    fmt.Println(strconv.Quote(str))

结果是:

{"A":"test","B":18}
"{\"A\":\"test\",\"B\":18}"

processAccounts:把密码和用户名组合通过base64加密作为value,user作为user构造成新的authPair结构体存入slice切片中。

func processAccounts(accounts Accounts) authPairs {
    length := len(accounts)
    assert1(length > 0, "Empty list of authorized credentials")
    pairs := make(authPairs, 0, length)
    for user, password := range accounts {
        assert1(user != "", "User can not be empty")
        value := authorizationHeader(user, password)
        pairs = append(pairs, authPair{
            value: value,
            user:  user,
        })
    }
    return pairs
}

func authorizationHeader(user, password string) string {
    base := user + ":" + password
    return "Basic " + base64.StdEncoding.EncodeToString(bytesconv.StringToBytes(base))
}

searchCredential:把http请求头中的Authorization值 和存储的base64编码的value做对比。没找到就返回401,找到就设置context的user 为authPair的key。

func (a authPairs) searchCredential(authValue string) (string, bool) {
    if authValue == "" {
        return "", false
    }
    for _, pair := range a {
        if subtle.ConstantTimeCompare(bytesconv.StringToBytes(pair.value), bytesconv.StringToBytes(authValue)) == 1 {
            return pair.user, true
        }
    }
    return "", false
}

这里有两个地方可以学习:

  1. 如果要比较用于验证用户数据密钥信息的字节切片时,使用reflact.DeepEqual()bytes.Equal()bytes.Compare()会使应用程序遭受计时攻击(Timing Attack),可使用crypto/subtle.ConstantTimeCompare()避免泄漏时间信息。
    这块可参考: http://blog.codeg.cn/2015/01/...
  2. string和[]byte转换,这个转换是zero-copy,性能比较高,推荐使用。

string和[]byte转换:

func StringToBytes(s string) []byte {
    return *(*[]byte)(unsafe.Pointer(
        &struct {
            string
            Cap int
        }{s, len(s)},
    ))
}

// BytesToString converts byte slice to string without a memory allocation.
func BytesToString(b []byte) string {
    return *(*string)(unsafe.Pointer(&b))
}

总结:
该模块功能虽然比较少,但是可以学的内容还是比较多:

  1. strconv.Quote()
  2. subtle.ContantTImeCompare
  3. string和[]byte比较
  4. 基本身份认证功能。
1 声望
1 粉丝
0 条评论
推荐阅读
golang学习之旅——解开心中的go mod疑惑
在go1.16版本发布后,go module由原来的默认值 auto 变为 on 了,这意味着后续开发中,go更推荐用go module 模式开发,而不是gopath模式开发了。

Keson11阅读 14.8k

「刷起来」Go必看的进阶面试题详解
逃逸分析是Go语言中的一项重要优化技术,可以帮助程序减少内存分配和垃圾回收的开销,从而提高程序的性能。下面是一道涉及逃逸分析的面试题及其详解。

王中阳Go4阅读 1.9k评论 1

封面图
初学后端,如何做好表结构设计?
这篇文章介绍了设计数据库表结构应该考虑的4个方面,还有优雅设计的6个原则,举了一个例子分享了我的设计思路,为了提高性能我们也要从多方面考虑缓存问题。

王中阳Go4阅读 1.7k评论 2

封面图
又一款眼前一亮的Linux终端工具!
今天给大家介绍一款最近发现的功能十分强大,颜值非常高的一款终端工具。这个神器我是在其他公众号文章上看到的,但他们都没把它的强大之处介绍明白,所以我自己体验一波后,再向大家分享自己的体验。

良许5阅读 1.8k

一分钟搞明白!快速掌握 Go WebAssembly
最近因为各种奇怪的原因,更多的接触到了 WebAssembly。虽然之前很多博客也翻过写过各种文章,但总感觉欠些味道。于是今天梳理了一版,和大家一起展开学习。

煎鱼4阅读 2.2k

面试官:请说一下如何优化结构体的性能?
使用内存对齐机制优化结构体性能,妙啊!前言之前分享过2篇结构体文章:10秒改struct性能直接提升15%,产品姐姐都夸我好棒 和 Go语言空结构体这3种妙用,你知道吗? 得到了大家的好评。这篇继续分享进阶内容:结...

王中阳Go4阅读 3.8k评论 2

封面图
go 协程操作map导致的数据竞争及解决方法
有个查询结果集的操作,无可避免的需要在循环获取数据,然后将结果集放到 map 中,这个操作在压测的时候,没出现问题,发布到生产环境之后,开始偶现 fatal error: concurrent map read and map write 错误,导致...

hxd_5阅读 839评论 4

1 声望
1 粉丝
宣传栏