轉載請注明作者及出處:
作者:銀河架構師
問題
Spring Security Oauth2中,當access_token即將過期時,需要調用/oauth/token,使用refresh_token刷新access_token,此時會存在一個坑:
即如果使用Spring Security框架默認生成的AuthenticationManager時,接口調用異常。
具體報錯信息為如下:
為了解決此問題,翻閱了一些源碼及資料,發現端倪在於tokenServices。
使用默認tokenServices
首先是AuthorizationServerEndpointsConfigurer中框架創建tokenServices的邏輯。
如果沒有指定tokenServices,則創建默認的tokenServices,即DefaultTokenServices:
具體創建默認的tokenServices邏輯:
注意,默認創建的tokenServices並沒有初始化authenticationManager,這里是重點,下面會用到。
其次,DefaultTokenServices中刷新access_token的邏輯。
關於user再次認證的部分邏輯如下:
如上所述,默認的tokenServices因為沒有設置authenticationManager,所以不會走此邏輯,也就不會再次對用戶進行認證。
tokenServices自定義
自定義tokenServices邏輯如下:
@Bean public DefaultTokenServices defaultTokenServices() throws Exception { DefaultTokenServices defaultTokenServices = new DefaultTokenServices(); defaultTokenServices.setAuthenticationManager(this.authenticationManager); defaultTokenServices.setTokenStore(jdbcTokenStore()); defaultTokenServices.setClientDetailsService(jdbcClientDetailsServiceBuilder()); // access token有效期2個小時 defaultTokenServices.setAccessTokenValiditySeconds(60 * 60 * 2); // refresh token有效期30天 defaultTokenServices.setRefreshTokenValiditySeconds(60 * 60 * 24 * 30); // 支持使用refresh token刷新access token defaultTokenServices.setSupportRefreshToken(true); // 允許重復使用refresh token defaultTokenServices.setReuseRefreshToken(true); return defaultTokenServices; }
由於設置了自定義的authenticationManager,且此時身份認證模式為password,所以滿足刷新access_token令牌時,針對用戶進行的二次認證條件(文章開始處已說明),則會觸發二次用戶認證。
此時,若采用Spring Security框架默認的authenticationManager,則必然會爆出文章開頭處描述的問題。因為框架默認的authenticationManager只包含一個DaoAuthenticationProvider。
Spring Security Oauth2框架中,存在一個開發者實現好的能認證PreAuthenticatedAuthenticationToken的Provider:PreAuthenticatedAuthenticationProvider。
但是,Spring Security框架並沒有在默認authenticationManager中初始化,所以,DefaultTokenServices在執行刷新方法時,在二次認證的地方便會報錯。
知道了問題的根本,就容易解決,添加PreAuthenticatedAuthenticationProvider到authenticationManager中應該就可以完美解決了。
關於如何authenticationManager配置,方法多種多樣,如覆蓋掉Spring Security框架默認邏輯,或者完全自定義,都可以。本文不再贅述,后續也會出文章,詳細闡述Spring Security如何配置,結合Spring Security Oauth2如何配置等等。
下面附上PreAuthenticatedAuthenticationProvider定義邏輯:
不得不說,Spring Security框架確實非常復雜,設計真是巧奪天工,不得不佩服設計者和開發者,由衷的贊嘆!
正文完!
微信搜索【銀河架構師】,發現更多精彩內容。
技術資料領取方法:關注公眾號,回復微服務,領取微服務相關電子書;回復MK精講,領取MK精講系列電子書;回復JAVA 進階,領取JAVA進階知識相關電子書;回復JAVA面試,領取JAVA面試相關電子書,回復JAVA WEB領取JAVA WEB相關電子書。