我正在尝试在Spring OAuth应用程序中使用刷新 token ,但没有成功。系统将在密码授予时发出刷新 token :

  { 
  "access_token": "xxxxx", 
  "token_type": "bearer", 
  "refresh_token": "xxxxxx", 
  "expires_in": 21599, 
  "scope": "read write" 
} 

但是尝试使用刷新 token 会导致以下错误:

curl -u acme -d“grant_type = refresh_token&refresh_token = xxxxxx” http://localhost:9999/uaa/oauth/token
{ 
  "error": "invalid_token", 
  "error_description": "Cannot convert access token to JSON" 
} 

我的身份验证服务器配置如下:
@Controller 
@SessionAttributes("authorizationRequest") 
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) 
@EnableResourceServer 
@ImportResource("classpath:/spring/application-context.xml") 
@Configuration 
public class ApplicationConfiguration extends WebMvcConfigurerAdapter { 
 
    @RequestMapping("/user") 
    @ResponseBody 
    public Principal user(Principal user) { 
        Authentication auth = SecurityContextHolder.getContext().getAuthentication(); 
        System.out.println(auth.toString()); 
        return user; 
    } 
 
    @Override 
    public void addViewControllers(ViewControllerRegistry registry) { 
        registry.addViewController("/login").setViewName("login"); 
        registry.addViewController("/oauth/confirm_access").setViewName("authorize"); 
    } 
 
    @Configuration 
    @Order(-20) 
    protected static class LoginConfig extends WebSecurityConfigurerAdapter { 
 
        @Autowired 
        private AuthenticationManager authenticationManager; 
 
        @Override 
        protected void configure(HttpSecurity http) throws Exception { 
 
            http.csrf().disable(); 
 
            // @formatter:off 
            http 
                .formLogin().loginPage("/login").permitAll() 
            .and() 
                .requestMatchers().antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access") 
            .and() 
                .authorizeRequests().anyRequest().authenticated(); 
            // @formatter:on 
 
        } 
 
        @Bean 
        @Override 
        public AuthenticationManager authenticationManagerBean() throws Exception { 
            return super.authenticationManagerBean(); 
        } 
    } 
 
    @Configuration 
    public static class JwtConfiguration { 
 
        @Bean 
        public JwtAccessTokenConverter jwtAccessTokenConverter() { 
            JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); 
            KeyPair keyPair = new KeyStoreKeyFactory(new ClassPathResource("keystore.jks"), "foobar".toCharArray()) 
                    .getKeyPair("test"); 
            converter.setKeyPair(keyPair); 
            return converter; 
        } 
 
        @Bean 
        public JwtTokenStore jwtTokenStore() { 
            return new JwtTokenStore(jwtAccessTokenConverter()); 
        } 
    } 
 
    @Configuration 
    @EnableAuthorizationServer 
    protected static class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter implements 
            EnvironmentAware { 
 
        private static final String ENV_OAUTH = "authentication.oauth."; 
        private static final String PROP_CLIENTID = "clientid"; 
        private static final String PROP_SECRET = "secret"; 
        private static final String PROP_TOKEN_VALIDITY_SECONDS = "tokenValidityInSeconds"; 
 
        private RelaxedPropertyResolver propertyResolver; 
 
        @Autowired 
        private AuthenticationManager authenticationManager; 
 
        @Autowired 
        private JwtAccessTokenConverter jwtAccessTokenConverter; 
 
        @Autowired 
        private JwtTokenStore jwtTokenStore; 
 
        @Autowired 
        @Qualifier("myUserDetailsService") 
        private UserDetailsService userDetailsService; 
 
        @Autowired 
        private DataSource dataSource; 
 
        @Override 
        public void setEnvironment(Environment environment) { 
            this.propertyResolver = new RelaxedPropertyResolver(environment, ENV_OAUTH); 
        } 
 
        @Bean 
        public TokenEnhancer tokenEnhancer() { 
            return new CustomTokenEnhancer(); 
        } 
 
        @Bean 
        @Primary 
        public DefaultTokenServices tokenServices() { 
            DefaultTokenServices tokenServices = new DefaultTokenServices(); 
            tokenServices.setSupportRefreshToken(true); 
            tokenServices.setTokenStore(jwtTokenStore); 
            tokenServices.setAuthenticationManager(authenticationManager); 
            tokenServices.setTokenEnhancer(tokenEnhancer()); 
            return tokenServices; 
        } 
 
        @Override 
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { 
            TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain(); 
            // The order is important here - the custom enhancer must come before the jwtAccessTokenConverter. 
            tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), jwtAccessTokenConverter)); 
            endpoints 
                    .authenticationManager(authenticationManager) 
                    .tokenEnhancer(tokenEnhancerChain) 
                    .tokenStore(jwtTokenStore) 
                    .userDetailsService(userDetailsService); 
        } 
 
        @Override 
        public void configure(AuthorizationServerSecurityConfigurer oauthServer) 
                throws Exception { 
            oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()"); 
        } 
 
        @Override 
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 
            clients.jdbc(dataSource); 
                    /*.withClient(propertyResolver.getProperty(PROP_CLIENTID)) 
                    .scopes("read", "write") 
                    .autoApprove(true) 
                    .authorities(ClientAuthoritiesConstants.CLIENT) 
                    .authorizedGrantTypes("authorization_code", "refresh_token", "password") 
                    .secret(propertyResolver.getProperty(PROP_SECRET)) 
                    .accessTokenValiditySeconds(propertyResolver.getProperty(PROP_TOKEN_VALIDITY_SECONDS, Integer 
                    .class, 1800));*/ 
        } 
    } 
 
    /** 
     * Configures the global LDAP authentication 
     */ 
    @Configuration 
    protected static class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter implements EnvironmentAware { 
 
        private static final String ENV_LDAP = "authentication.ldap."; 
        private static final String PROP_SEARCH_BASE = "userSearchBase"; 
        private static final String PROP_SEARCH_FILTER = "userSearchFilter"; 
        private static final String PROP_GROUP_SEARCH_FILTER = "groupSearchFilter"; 
        private static final String PROP_LDAP_URL = "url"; 
        private static final String PROP_LDAP_USER = "userDn"; 
        private static final String PROP_LDAP_PASS = "password"; 
 
        private RelaxedPropertyResolver propertyResolver; 
 
        /** 
         * Maps the LDAP user to the Principle that we'll be using in the app 
         */ 
        public UserDetailsContextMapper userDetailsContextMapper() { 
            return new UserDetailsContextMapper() { 
                @Override 
                public UserDetails mapUserFromContext(DirContextOperations ctx, String username, 
                                                      Collection<? extends GrantedAuthority> authorities) { 
                    // Get the common name of the user 
                    String commonName = ctx.getStringAttribute("cn"); 
                    // Get the users email address 
                    String email = ctx.getStringAttribute("mail"); 
                    // Get the domino user UNID 
                    String uId = ctx.getStringAttribute("uid"); 
                    return new CustomUserDetails(email, "", commonName, authorities); 
                } 
 
                @Override 
                public void mapUserToContext(UserDetails user, DirContextAdapter ctx) { 
                    throw new IllegalStateException("Only retrieving data from LDAP is currently supported"); 
                } 
 
            }; 
        } 
 
        @Override 
        public void setEnvironment(Environment environment) { 
            this.propertyResolver = new RelaxedPropertyResolver(environment, ENV_LDAP); 
        } 
 
        @Override 
        public void init(AuthenticationManagerBuilder auth) throws Exception { 
            auth 
                    .ldapAuthentication() 
                    .userSearchBase(propertyResolver.getProperty(PROP_SEARCH_BASE)) 
                    .groupSearchBase(propertyResolver.getProperty(PROP_SEARCH_BASE)) 
                    .userSearchFilter(propertyResolver.getProperty(PROP_SEARCH_FILTER)) 
                    .groupSearchFilter(propertyResolver.getProperty(PROP_GROUP_SEARCH_FILTER)) 
                    .userDetailsContextMapper(userDetailsContextMapper()) 
                    .contextSource() 
                    .url(propertyResolver.getProperty(PROP_LDAP_URL)) 
                    .managerDn(propertyResolver.getProperty(PROP_LDAP_USER)) 
                    .managerPassword(propertyResolver.getProperty(PROP_LDAP_PASS)); 
        } 
    } 
} 

任何人都有任何想法,为什么在给定有效的刷新 token 时,身份验证服务器为什么不发行新 token ?

请您参考如下方法:

有这个问题。我发送的是“Bearer xxxxxx ...”,而TokenEnhancer期望的只是“xxxxx ...”而没有“Bearer”前缀


评论关闭
IT干货网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!