SpringSecurity+JWT配置的坑以及源碼分析

拋出問題:

之前在QQ上有位朋友問jwt的問題闲询,開始的時候只給了他一個自己寫的參考案例久免,以為整個過程就可以順利配置并且可以愉快的使用,但是后面遇到了一個小坑扭弧,可能平時配置自定義AuthorizationServerConfigurerAdapter的自定義父類的時候阎姥,一下子就入坑了,好現(xiàn)在先拋出代碼然后分析鸽捻,以下為部分核心配置代碼:

@Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore())
            .authenticationManager(authenticationManager);
        //通過TokenEnhancerChain增強器鏈將jwtAccessTokenConverter(轉(zhuǎn)換成jwt)和jwtTokenEnhancer(往里面加內(nèi)容加信息)連起來
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        List<TokenEnhancer> enhancerList = Lists.newArrayList();
        enhancerList.add(tokenEnhancer());
        enhancerList.add(accessTokenConverter());
        enhancerChain.setTokenEnhancers(enhancerList);
        endpoints
            .tokenEnhancer(enhancerChain)
            .tokenServices(tokenServices())
            .accessTokenConverter(accessTokenConverter());

    }

    @Primary
    @Bean
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices=new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        //維持刷新token
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }

   @Bean
    public TokenStore tokenStore() {
        TokenStore tokenStore = new JwtTokenStore(accessTokenConverter());
        return tokenStore;
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
        accessTokenConverter.setSigningKey(jwtSigningKey);
        return accessTokenConverter;
    }

    @Bean
    public TokenEnhancer tokenEnhancer() {
        return new CustomTokenEnhancer();
    }

可是啟動執(zhí)行獲取token接口返回值為:

{
    "access_token": "35cdbd07-9b5e-40ab-b69f-8eacaa2c1fc7",
    "token_type": "bearer",
    "refresh_token": "db5aa1e5-512b-45a4-9d55-aa137d710f67",
    "expires_in": 43199,
    "scope": "read,write"
}

乍一看這個沒啥問題抡爹,我明明配置的是jwt的accessTokenConvertertokenStore可是啟動程序生成的token怎么不是jwt呢兔魂,而是uuid的一串字符串,自己也沒發(fā)現(xiàn)有啥問題,找呀找呀调缨,時間就這么過去了......

源碼分析:

通過跟蹤源碼分析TokenEndpoint的接口方法postAccessToken可以發(fā)現(xiàn)生成token的執(zhí)行的方法為:

    OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);

其中其核心生成token的類為DefaultTokenServices執(zhí)行的方法為createAccessToken可以看到源碼中生成token的方法為createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken)的私有方法,源碼為:

private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) {
        DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(UUID.randomUUID().toString());
        int validitySeconds = getAccessTokenValiditySeconds(authentication.getOAuth2Request());
        if (validitySeconds > 0) {
            token.setExpiration(new Date(System.currentTimeMillis() + (validitySeconds * 1000L)));
        }
        token.setRefreshToken(refreshToken);
        token.setScope(authentication.getOAuth2Request().getScope());
        //這個才是自定義token生成策略的關(guān)鍵
        return accessTokenEnhancer != null ? accessTokenEnhancer.enhance(token, authentication) : token;
    }

可以發(fā)現(xiàn)這邊在createToken的時候首先是使用UUID來生成的栋盹,然后在最后一行
accessTokenEnhancer != null采用的是accessTokenEnhancer配置的token生成策略夺谁,若為null則直接返回生成的uuidtoken.

失效原因分析:

源碼的token生成策略我們已經(jīng)分析完成托猩,現(xiàn)在讓我們回過頭來看看我們之前的配置代碼TokenEnhancerChain已經(jīng)設(shè)置了我們的tokenStoreaccessTokenConverter但是為啥沒生效呢......?
可以看到我們在重寫configure(AuthorizationServerEndpointsConfigurer endpoints)這個方法的時候執(zhí)行了一個命令endpoints. .tokenServices(tokenServices())tokenService()方法我們配置的是什么呢碘箍?

@Primary
    @Bean
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices=new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        //維持刷新token
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }

我們這邊重new DefaultTokenServices()遵馆,并且沒有配置DefaultTokenServices下的private TokenEnhancer accessTokenEnhancer;這個屬性,所以導(dǎo)致我們在DefaultTokenServices類下面執(zhí)行createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken)時最后面的accessTokenEnhancer != null ? accessTokenEnhancer.enhance(token, authentication) : token;時accessTokenEnhancer為空丰榴,導(dǎo)致直接返回生成的UUID的token返回客戶端货邓。

解決方案:

解決方式可以采用一下兩種方式:

  • configure(AuthorizationServerEndpointsConfigurer endpoints)方法中去掉endpoints.tokenServices(tokenServices())這個配置,刪除tokenService配置四濒,只保留endpoint的配置逻恐。即:
@Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore())
            .authenticationManager(authenticationManager);
        //通過TokenEnhancerChain增強器鏈將jwtAccessTokenConverter(轉(zhuǎn)換成jwt)和jwtTokenEnhancer(往里面加內(nèi)容加信息)連起來
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        List<TokenEnhancer> enhancerList = Lists.newArrayList();
        enhancerList.add(tokenEnhancer());
        enhancerList.add(accessTokenConverter());
        enhancerChain.setTokenEnhancers(enhancerList);
        endpoints
            .tokenEnhancer(enhancerChain)
            .accessTokenConverter(accessTokenConverter());

    }
  • endpoints配置 tokenEnhancer的配置代碼刪除,落到配置tokenService()方法的配置中去即:
 @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore())
            .authenticationManager(authenticationManager);
        endpoints
            .tokenServices(tokenServices())
            .accessTokenConverter(accessTokenConverter());

    }

    @Primary
    @Bean
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices=new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        //維持刷新token
        defaultTokenServices.setSupportRefreshToken(true);
        //通過TokenEnhancerChain增強器鏈將jwtAccessTokenConverter(轉(zhuǎn)換成jwt)和jwtTokenEnhancer(往里面加內(nèi)容加信息)連起來
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        List<TokenEnhancer> enhancerList = Lists.newArrayList();
        enhancerList.add(tokenEnhancer());
        enhancerList.add(accessTokenConverter());
        enhancerChain.setTokenEnhancers(enhancerList);
        defaultTokenServices.setTokenEnhancer(enhancerChain);
        return defaultTokenServices;
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末峻黍,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子拨匆,更是在濱河造成了極大的恐慌姆涩,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惭每,死亡現(xiàn)場離奇詭異骨饿,居然都是意外死亡,警方通過查閱死者的電腦和手機台腥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門宏赘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人黎侈,你說我怎么就攤上這事察署。” “怎么了峻汉?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵贴汪,是天一觀的道長脐往。 經(jīng)常有香客問我,道長扳埂,這世上最難降的妖魔是什么业簿? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮阳懂,結(jié)果婚禮上梅尤,老公的妹妹穿的比我還像新娘。我一直安慰自己岩调,他們只是感情好巷燥,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著誊辉,像睡著了一般矾湃。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上堕澄,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天邀跃,我揣著相機與錄音,去河邊找鬼蛙紫。 笑死拍屑,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的坑傅。 我是一名探鬼主播僵驰,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼唁毒!你這毒婦竟也來了蒜茴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤浆西,失蹤者是張志新(化名)和其女友劉穎粉私,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體近零,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡诺核,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了久信。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片窖杀。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖裙士,靈堂內(nèi)的尸體忽然破棺而出入客,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布痊项,位于F島的核電站锅风,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏鞍泉。R本人自食惡果不足惜皱埠,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望咖驮。 院中可真熱鬧边器,春花似錦、人聲如沸托修。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽睦刃。三九已至砚嘴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涩拙,已是汗流浹背际长。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留兴泥,地道東北人工育。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像搓彻,于是被迫代替她去往敵國和親如绸。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355