使用 oauth2 休息服务:无法找到令牌的访问令牌

Posted

技术标签:

【中文标题】使用 oauth2 休息服务:无法找到令牌的访问令牌【英文标题】:Rest service with oauth2: Failed to find access token for token 【发布时间】:2016-07-16 05:12:57 【问题描述】:

我尝试创建 spring rest 服务,这是由我自己的 oauth2 资源服务器 autenticated。我创建了资源服务器:

@Configuration
@EnableResourceServer
protected static class ResourceServer extends ResourceServerConfigurerAdapter 

    @Autowired
    private TokenStore tokenStore;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception 
        resources.tokenStore(tokenStore).resourceId("mobileapp");
    

    @Override
    public void configure(HttpSecurity http) throws Exception 
        http.authorizeRequests().antMatchers("/api/shop /**").authenticated().and()
                .authorizeRequests().antMatchers("/auth/**").anonymous();
    


和授权服务器:

@Configuration
@EnableAuthorizationServer
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter 

    @Autowired
    private AuthenticationManager auth;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Bean
    public JdbcTokenStore tokenStore() 
        return new JdbcTokenStore(dataSource);
    

    @Bean
    protected AuthorizationCodeServices authorizationCodeServices() 
        return new JdbcAuthorizationCodeServices(dataSource);
    

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception 
        security.passwordEncoder(passwordEncoder);
    

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception 
        endpoints
                .authorizationCodeServices(authorizationCodeServices())
                .authenticationManager(auth)
                .tokenStore(tokenStore())
                .approvalStoreDisabled();
    

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception 
        clients.jdbc(dataSource)
                .passwordEncoder(passwordEncoder);
                .withClient("mobile")
                .authorizedGrantTypes("password", "refresh_token")
                .authorities("ROLE_CLIENT")
                .scopes("read", "write", "trust")
                .autoApprove(true)
               .resourceIds("mobileapp")
                .secret("123456");
    

当我尝试从服务器接收访问令牌时,使用 curl:

curl -X POST -vu mobile:123456 http://localhost:8080/oauth/token -H “接受:应用程序/json”-d "password=test123&username=admin@gmail.com&grant_type=password&scope=read&client_secret=123456&client_id=mobile"

我收到此错误作为响应消息:

"error":"server_error","error_description":"java.io.NotSerializableException: org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"

在tomcat日志中也有

o.s.s.o.p.token.store.JdbcTokenStore - 未能找到访问令牌 令牌

编辑: 密码编码器的bean定义:

@Bean
public BCryptPasswordEncoder passwordEncoder() 
    BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
    return bCryptPasswordEncoder;

这个bean是在类中创建的,其中声明了OAuth2Config和ResourceServer。

我检查了代码,发现使用了哪个表弹簧,表是空的。我的问题是:它应该是自动生成的还是我的代码有问题?

提前感谢您的帮助。

【问题讨论】:

你能用@BeanBCryptPasswordEncoder bean 的定义更新问题吗? 我添加了 BCryptPasswordEncoder bean 定义。 谢谢,我认为@Bean 看起来不错(尽管您可以使用PasswordEncoder 接口作为其类型)。当我在本地测试它时,我必须使用像withClient(...).secret(passwordEncoder.encode("123456")) 这样的加密密码设置withClient(..).secret(...),但这并不能解释序列化错误(它宁愿解释BadCredentials 响应,当我不编码时得到响应它。当你不设置security.passwordEncoder(...)时,你检查过一切正常吗? 对不起,我收回最后一句话,我没有看到你在clients配置中也配置了passwordEncoder,所以那里不需要passwordEncoder.encode()。跨度> 【参考方案1】:

重写 JdbcTokenStore 类并将此函数替换为。

public OAuth2AccessToken readAccessToken(String tokenValue) 
    OAuth2AccessToken accessToken = null;

    try 
        accessToken = new DefaultOAuth2AccessToken(tokenValue);
    
    catch (EmptyResultDataAccessException e) 
        if (LOG.isInfoEnabled()) 
            LOG.info("Failed to find access token for token "+tokenValue);
        
    
    catch (IllegalArgumentException e) 
        LOG.warn("Failed to deserialize access token for " +tokenValue,e);
        removeAccessToken(tokenValue);
    

    return accessToken;

您找不到访问令牌的问题已解决。在 OAuth2Config 中使用该类。

【讨论】:

这其实是正确的答案。我不知道为什么它没有被勾选。找了一个星期才发现它藏在这里!【参考方案2】:

您的模型必须具有未序列化的 BCryptPasswordEncoder。在您的用户 bmodel 中使其成为瞬态。

private transient BCryptPasswordEncoder passwordEncoder;

【讨论】:

【参考方案3】:

就 Postgres 而言,解决方案将 BYTEA 用于 ALL tokenauthentication 列。

这些列在此架构参考中定义为LONGVARBINARY:https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql

换句话说,如果您使用的是 Postgres,请将 LONGVARBINARY 替换为 BYTEA

干杯

【讨论】:

以上是关于使用 oauth2 休息服务:无法找到令牌的访问令牌的主要内容,如果未能解决你的问题,请参考以下文章

用户在springboot中调用注册休息API时如何获取oAuth2访问令牌?

Oauth2:资源服务器应该如何知道访问令牌是不是有效?

Android中的Oauth2刷新令牌更新

Spring Security OAuth2 JWT 匿名令牌

无法在跨客户端谷歌 oauth2.0 中交换访问令牌和刷新令牌的授权码

即使访问令牌有效,也无法使用刷新令牌刷新 Google OAuth2 的访问令牌