zoukankan      html  css  js  c++  java
  • 避坑指南(一):Spring Security Oauth2中refresh_token刷新access_token异常

    转载请注明作者及出处:

    作者:银河架构师

    原文链接:https://www.cnblogs.com/luas/p/12118694.html

    ​问题

    Spring Security Oauth2中,当access_token即将过期时,需要调用/oauth/token,使用refresh_token刷新access_token,此时会存在一个坑:

    即如果使用Spring Security框架默认生成的AuthenticationManager时,接口调用异常。

    具体报错信息为如下:

    No AuthenticationProvider found for org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken

     分析

    为了解决此问题,翻阅了一些源码及资料,发现端倪在于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定义逻辑:

    private PreAuthenticatedAuthenticationProvider preAuthenticatedAuthenticationProvider() {
        PreAuthenticatedAuthenticationProvider preAuthenticatedAuthenticationProvider = new PreAuthenticatedAuthenticationProvider();
        preAuthenticatedAuthenticationProvider.setPreAuthenticatedUserDetailsService(new UserDetailsByNameServiceWrapper(userDetailsService));
        return preAuthenticatedAuthenticationProvider;
    }

     不得不说,Spring Security框架确实非常复杂,设计真是巧夺天工,不得不佩服设计者和开发者,由衷的赞叹!

    正文完!

    微信搜索【银河架构师】,发现更多精彩内容。

    技术资料领取方法:关注公众号,回复微服务,领取微服务相关电子书;回复MK精讲,领取MK精讲系列电子书;回复JAVA 进阶,领取JAVA进阶知识相关电子书;回复JAVA面试,领取JAVA面试相关电子书,回复JAVA WEB领取JAVA WEB相关电子书。

  • 相关阅读:
    const 深悟理解
    深拷贝与浅拷贝深究
    结队开发-最大子数组
    软件工程个人作业02
    四则运算关于加括号的思路
    实践出真知-所谓"java没有指针",那叫做引用!
    写代码的好习惯—先构思
    团队合作
    阿超超的四则运算 想啊想啊
    Github+阿超运算
  • 原文地址:https://www.cnblogs.com/luas/p/12118694.html
Copyright © 2011-2022 走看看