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 条评论
推荐阅读
一文搞懂秒杀系统,欢迎参与开源,提交PR,提高竞争力。早日上岸,升职加薪。
前言秒杀和高并发是面试的高频考点,也是我们做电商项目必知必会的场景。欢迎大家参与我们的开源项目,提交PR,提高竞争力。早日上岸,升职加薪。知识点详解秒杀系统架构图秒杀流程图秒杀系统设计这篇文章一万多...

王中阳Go35阅读 2.6k评论 1

封面图
Golang 中 []byte 与 string 转换
string 类型和 []byte 类型是我们编程时最常使用到的数据结构。本文将探讨两者之间的转换方式,通过分析它们之间的内在联系来拨开迷雾。

机器铃砍菜刀24阅读 58.4k评论 2

万字详解,吃透 MongoDB!
MongoDB 是一个基于 分布式文件存储 的开源 NoSQL 数据库系统,由 C++ 编写的。MongoDB 提供了 面向文档 的存储方式,操作起来比较简单和容易,支持“无模式”的数据建模,可以存储比较复杂的数据类型,是一款非常...

JavaGuide8阅读 1.7k

封面图
数据结构与算法:二分查找
一、常见数据结构简单数据结构(必须理解和掌握)有序数据结构:栈、队列、链表。有序数据结构省空间(储存空间小)无序数据结构:集合、字典、散列表,无序数据结构省时间(读取时间快)复杂数据结构树、 堆图二...

白鲸鱼9阅读 5.4k

PHP转Go实践:xjson解析神器「开源工具集」
我和劲仔都是PHP转Go,身边越来越多做PHP的朋友也逐渐在用Go进行重构,重构过程中,会发现php的json解析操作(系列化与反序列化)是真的香,弱类型语言的各种隐式类型转换,很大程度的减低了程序的复杂度。

王中阳Go11阅读 2.7k评论 4

封面图
Git操作不规范,战友提刀来相见!
年终奖都没了,还要扣我绩效,门都没有,哈哈。这波骚Git操作我也是第一次用,担心闪了腰,所以不仅做了备份,也做了笔记,分享给大家。问题描述小A和我在同时开发一个功能模块,他在优化之前的代码逻辑,我在开...

王中阳Go6阅读 2.9k评论 4

封面图
妙啊,空结构体还能这么用?Go语言的结构体看这篇就够了
本文详解了Go语言结构体的各个知识点,最后介绍了空结构体的3种妙用。希望对你有帮助。定义结构体,是一种自定义的数据类型,由多个数据类型组合而成。用于描述一类事物相关属性。定义方式: {代码...} 实例化结...

王中阳Go6阅读 1.2k

封面图
1 声望
1 粉丝
宣传栏