從goauth2的一個bug提及

goauth2因爲做者使用詭計,致使若是goauth2啓用redis緩存token與code後,致使android客戶端不能在獲取token了,這裏就分享一下查這個bug的過程。android

首先,bug的表現爲獲取token失敗,具體的緣由是由於當goauth2產生了token與code後,可是隻能存儲code而不能存儲token,這樣驗證的時候因爲沒法從redis服務器獲取token,因此就失敗了,客戶端就沒法訪問受保護的資源了。redis

func (ac *RedisAuthCache) RegisterAccessToken(clientID, scope, token string) (ttype string, expiry int64, err error) {
    
    vars := map[string]string{
        "clientID": clientID,
        "scope":    scope,
    }
    val, err := json.Marshal(vars)
    if err != nil {
        log.Println("Error Marshalling variables for Redis Set", err)
        return "", 0, err
    }

    key := tokenKey(token)

    err = ac.db.Set(key, val)
    if err != nil {
        log.Println("Error performing Redis-Set", err)
        return "", 0, err
    }

    valid, err := ac.db.Expire(key, int64(ac.TokenExpiry))
    if err != nil {
        log.Println("Error performing Redis-Expire", err)
        return "", 0, err
    } else if !valid {
        err = errors.New("Invalid return from setting code expiration.")
        log.Println("Error performing Redis-Expire", err)
        return "", 0, err
    }

    return "bearer", ac.TokenExpiry, nil
}

我最早懷疑的是究竟是key不能設置仍是token不能設置,所以作了幾種嘗試,ac.db.Set("token:257fc9823289eaabc4a28aff190b59b468bffb53", val)拿上一次產生的token三硬編碼,發現能夠設置;但若是函數調用時用一樣的key就不能設置;因而當取回tokenKey後,我就破壞key,發現這個key就能設置,這完全讓我迷惑了,因而懷疑是goauth使用的redis有問題,又換了一種redis,但是問題依舊。無語了,靈感一現,注意到set了token後,就設置了Expire,會不會是這行代碼致使沒法設置token,果斷註釋代碼,發現token就保存住了,一會兒就猜想bug緣由,會不會是設置了Expire,這個是負責token的超時,若是超時設置成了0,那麼剛設置完token,又立刻告訴redis token的超時爲0,因此就消失了,再看源碼json

func NewRedisAuthCacheWithClient(addr string, dbnum int, pass string) *RedisAuthCache {
    return &RedisAuthCache{
        db:          redis.New(addr, dbnum, pass),
        CodeExpiry:  260,
        TokenExpiry: 0,
    }
}

果真,TokenExpiry默認爲0。緩存

我爲何要特別說明這個問題呢,由於嚴格來講做者並無寫錯任何一行代碼,TokenExpiry給予一個保守的默認值,做者也沒有錯,但是這些沒有錯加在一塊兒就成全了這個bug。這個bug很是有趣的地方在於,比如redis是個箱子,程序邏輯一半是往箱子裏放蘋果,而另外一個邏輯就是吃掉這個蘋果,但是咱們卻疑問蘋果去那了?最後redis躺槍,咱們怪redis這個怪物偷吃了蘋果。服務器

相關文章
相關標籤/搜索