springboot1.5.3+redis3.4-cluster叢集+shiro1.3.2+springcloud+nginx登入後shiro的subject為null問題解決
一、 問題描述
線上環境:springboot1.5.3+redis3.4-cluster叢集+shiro1.3.2+springcloud+nginx
本地開發:springboot1.5.3+redis3.4-cluster叢集+shiro1.3.2
本地開發時,一切正常。
上線後,登入正常,之後訪問其他功能對shiro許可權認證,產生Subject().isAuthenticated() = false。debug發現根本沒有進入 doGetAuthorizationInfo()。
二、問題分析
redis
1. debug發現線上redis只寫入shiro-session,並沒有許可權cache的寫入。判斷jedis連線redis的問題。
2. 由於專案引入jedis2.9.0.jar,連線時首先採用單節點redis,Redisutils更改為jedisCluster()訪問,shiro-redis也由2.4升級為3.1.0支援redis-cluster(),本地除錯成功後,線上問題依舊。
3. 專案中產品建議採用spring直接操作redis,而不是jedis,甚至放棄本專案架構。理由是別人的專案這樣是成功的。思考良久,認為問題不在這,既然可以寫入和讀取shiro-session,連線不是問題。從解決之後來看,這種堅持是正確的。
shiro
- 百度“shiro登入後 isAuthenticated null”,發現其他人也有類似困擾,但沒有給出真正的解決之道,只說後來莫名其妙好了。只好自己動手分析shiro原始碼了,見本部落格的分析文章。
- 迫於無奈只好研讀shiro原始碼,還不能debug,因為問題在線上,復現不了。
- 網友有說HttpRequestServlet被shiro重新包裝,多執行緒導致獲取不到shiro的subject,我也驗證不了。第六感強烈告訴自己問題不在這,首先shiro專案經過許多考驗,基本的信任還是有的。
- 分析shiro原始碼,發現token是cookie讀取的,應該分析cookie是否能用。debug發現也沒問題。
nginx
為了復現問題,儘可能地模擬生產環境,本地開啟nginx,在vue前端和後臺加入nginx作為反向代理。沒問題。
問題似乎走入了死衚衕, 能試的方法都試過了
最後想起還有spring-cloud沒有模擬,麻煩的一比,為了解決問題沒辦法
springCloud
模擬springCloud,主要就是觀察zuul網關了。
問題終於復現了
問題解決
通過分析zuul閘道器日誌,發現zuul篡改了token,當然會導致shiro能登入成功,其後的功能發現沒有許可權,subject.isAuthenticated() = false。
方案一:nginx代理的時候,不再指向zuul,而是直接指向後臺服務地址,zuul的負載均衡功能可通過其他方案替代。
方案二:zuul對請求有過濾模式,在請求前面加入特定的字元,便可繞過。具體請Seach。
方案三:zuul
其實,在另外一個專案中,上傳檔案也被zuul閘道器截取了一部分位元組,導致檔案不完整報錯。網上有解決方案,不在贅述。
總結
本地除錯正常,線上問題多多,從環境入手是沒錯的。
不要輕易懷疑你專案的架構和更換其他技術,產品人員除外。