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這個怪物偷吃了蘋果。服務器