简体   繁体   English

Spring Security OAuth2资源服务器始终返回无效令牌

[英]Spring Security OAuth2 Resource Server Always Returning Invalid Token

I am trying to get a basic in-memory OAuth2 server running using the Spring Libraries. 我正在尝试使用Spring库运行基本的内存OAuth2服务器。 I have been following the sparklr example . 我一直在关注sparklr的例子

I currently have configured the Server and almost everything is working, however I cannot access my restricted resource from the resource server. 我目前已配置服务器,几乎一切正常,但我无法从资源服务器访问我的受限资源。

My test workflow: 我的测试工作流程

  1. Access the oauth authorized URI to start the OAuth2 flow: http://localhost:8080/server/oauth/authorize?response_type=code&client_id=client 访问oauth授权的URI以启动OAuth2流: http:// localhost:8080 / server / oauth / authorize?response_type = code&client_id = client

  2. Redirect to the login page: http://localhost:8080/server/login 重定向到登录页面: http:// localhost:8080 / server / login

  3. Handle the approval and redirect to my configured redirect page w/ a code parameter: http://localhost:8080/client?code=HMJO4K 处理批准并重定向到我配置的重定向页面,带有代码参数: http:// localhost:8080 / client?code = HMJO4K

  4. Construct a GET request using Basic Auth using the client id and secret along with the grant type and code: http://localhost:8080/server/oauth/token?grant_type=authorization_code&code=HMJO4K 使用基本身份验证使用客户端ID和密码以及授权类型和代码构造GET请求: http:// localhost:8080 / server / oauth / token?grant_type = authorization_code&code = HMJO4K

  5. Receive an access_token and refresh token object in return 接收一个access_token和刷新令牌对象作为回报

    { access_token: "f853bcc5-7801-42d3-9cb8-303fc67b0453" token_type: "bearer" refresh_token: "57100377-dea9-4df0-adab-62e33f2a1b49" expires_in: 299 scope: "read write" } {access_token:“f853bcc5-7801-42d3-9cb8-303fc67b0453”token_type:“bearer”refresh_token:“57100377-dea9-4df0-adab-62e33f2a1b49”expires_in:299范围:“read write”}

  6. Attempt to access a restricted resource using the access_token: http://localhost:8080/server/me?access_token=f853bcc5-7801-42d3-9cb8-303fc67b0453 尝试使用access_token访问受限资源: http:// localhost:8080 / server / me?access_token = f853bcc5-7801-42d3-9cb8-303fc67b0453

  7. Receive an invalid token reply 收到无效的令牌回复

    { error: "invalid_token" error_description: "Invalid access token: f853bcc5-7801-42d3-9cb8-303fc67b0453" } {error:“invalid_token”error_description:“无效的访问令牌:f853bcc5-7801-42d3-9cb8-303fc67b0453”}

  8. POST to the token uri again to refresh token: http://localhost:8080/server/oauth/token?grant_type=refresh_token&refresh_token=57100377-dea9-4df0-adab-62e33f2a1b49 再次POST到令牌uri以刷新令牌: http:// localhost:8080 / server / oauth / token?grant_type = refresh_token&refresh_token = 57100377-dea9-4df0-adab-62e33f2a1b49

  9. Receive a new token 收到一个新令牌

    { access_token: "ed104994-899c-4cd9-8860-43d5689a9420" token_type: "bearer" refresh_token: "57100377-dea9-4df0-adab-62e33f2a1b49" expires_in: 300 scope: "read write" } {access_token:“ed104994-899c-4cd9-8860-43d5689a9420”token_type:“bearer”refresh_token:“57100377-dea9-4df0-adab-62e33f2a1b49”expires_in:300范围:“read write”}

I am really not sure what I am doing wrong, but it appears that everything other than accessing the restricted uri is working. 我真的不确定我做错了什么,但似乎除了访问受限制的uri之外的一切都正常。 Here is my configuration: 这是我的配置:

@Configuration
public class Oauth2ServerConfiguration {

    private static final String SERVER_RESOURCE_ID = "oauth2-server";

    @Configuration
    @EnableResourceServer
    protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) {
            resources.resourceId(SERVER_RESOURCE_ID);
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                .and().requestMatchers()
                    .antMatchers("/me")
                .and().authorizeRequests()
                    .antMatchers("/me").access("#oauth2.clientHasRole('ROLE_CLIENT')")
            ;
        }
    }

    @Configuration
    @EnableAuthorizationServer
    protected static class AuthotizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

        @Autowired
        private ClientDetailsService clientDetailsService;

        @Autowired
        @Qualifier("authenticationManagerBean")
        private AuthenticationManager authenticationManager;

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory()
                .withClient("client")
                    .resourceIds(SERVER_RESOURCE_ID)
                    .secret("secret")
                    .authorizedGrantTypes("authorization_code", "refresh_token")
                    .authorities("ROLE_CLIENT")
                    .scopes("read","write")
                    .redirectUris("http://localhost:8080/client")
                    .accessTokenValiditySeconds(300)
                    .autoApprove(true)
            ;
        }

        @Bean
        public TokenStore tokenStore() {
            return new InMemoryTokenStore();
        }

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints
                .tokenStore(tokenStore())
                .userApprovalHandler(userApprovalHandler())
                .authenticationManager(authenticationManager)
            ;
        }

        @Override
        public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
            oauthServer.realm("oauth");
        }

        @Bean
        public ApprovalStore approvalStore() throws Exception {
            TokenApprovalStore store = new TokenApprovalStore();
            store.setTokenStore(tokenStore());
            return store;
        }

        @Bean
        public UserApprovalHandler userApprovalHandler() throws Exception {
            TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
            handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
            handler.setClientDetailsService(clientDetailsService);
            handler.setTokenStore(tokenStore());

            return handler;
        }
    }
}

Is there something I am missing or am I approaching this incorrectly? 有什么我想念的或者我接近这个错误吗? Any help would be greatly appreciated. 任何帮助将不胜感激。

Your step #6 is wrong - the access token should not be sent in the URL as it is vulnerable this way. 您的步骤#6是错误的 - 访问令牌不应该在URL中发送,因为它以这种方式易受攻击。 rathen than GET, use POST. 比GET更好,使用POST。

Besides, I don't understand your step #1 - why do you call /oauth/authorize? 此外,我不明白你的步骤#1 - 为什么你打电话/ oauth / authorize? it should be done implicitly when you try to get a protected resource. 当您尝试获取受保护资源时,应该隐式执行此操作。 I mean, your flow should start with: 我的意思是,你的流程应该从:

Attempt to access a restricted resource using the access_token: http://localhost:8080/server/me 尝试使用access_token访问受限资源: http:// localhost:8080 / server / me

Then the negotiation will start "behind the scenes": a redirect to "/oauth/authorize" etc. 然后谈判将在“幕后”开始:重定向到“/ oauth / authorize”等。

In addition, in step #8, note that you are not asking for "another access token", but instead it is a request for "refresh token". 此外,在步骤#8中,请注意您不是要求“另一个访问令牌”,而是要求“刷新令牌”。 As if your access-token was expired. 好像您的访问令牌已过期。

Note : The identity provider and the resource server should share the tokenStore! 注意 :身份提供者和资源服务器应该共享tokenStore! Read here: Spring Security OAuth2 pure resource server 阅读此处: Spring Security OAuth2纯资源服务器

HTH HTH

The problem ended up being that the resource server and the authorization server were not getting the same token store reference. 问题最终是资源服务器和授权服务器没有获得相同的令牌存储引用。 Not sure how the wiring was not working correctly, but using a fixed object in the configuration class worked like a charm. 不确定接线是如何工作不正确的,但在配置类中使用固定对象就像一个魅力。 Ultimately, I'll move to a persistence backed token store, which probably would not have had any issues. 最终,我将转移到持久性支持的令牌存储,这可能不会有任何问题。

Thanks goes to @OhadR for the answer and the help! 感谢@OhadR的答案和帮助!

Ultimately, I simplified the configuration, went thru the same workflow, and it worked out 最终,我简化了配置,通过相同的工作流程,并且成功了

@Configuration
public class Oauth2ServerConfiguration {

    private static final String SERVER_RESOURCE_ID = "oauth2-server";

    private static InMemoryTokenStore tokenStore = new InMemoryTokenStore();


    @Configuration
    @EnableResourceServer
    protected static class ResourceServer extends ResourceServerConfigurerAdapter {

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.tokenStore(tokenStore).resourceId(SERVER_RESOURCE_ID);
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.requestMatchers().antMatchers("/me").and().authorizeRequests().antMatchers("/me").access("#oauth2.hasScope('read')");
        }
    }

    @Configuration
    @EnableAuthorizationServer
    protected static class AuthConfig extends AuthorizationServerConfigurerAdapter {

        @Autowired
        private AuthenticationManager authenticationManager;


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

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory()
                .withClient("client")
                    .authorizedGrantTypes("authorization_code","refresh_token")
                    .authorities("ROLE_CLIENT")
                    .scopes("read")
                    .resourceIds(SERVER_RESOURCE_ID)
                    .secret("secret")
            ;
        }
    }
}

Anyone that stumbles upon this post, I recommend looking more at the unit tests for example rather than the full blown sparklr/tonr example, as it has a lot of extra configuration that are not necessarily needed to get started. 任何偶然发现这篇文章的人,我建议更多地考虑单元测试而不是完整的sparklr / tonr示例,因为它有很多额外的配置,不一定需要开始。

This works for me: 这对我有用:

@Configuration
public class Oauth2ServerConfiguration {

    private static final String SERVER_RESOURCE_ID = "oauth2-server";

    @Autowired
    private TokenStore tokenStore;

    @Bean
    public TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }

    @Configuration
    @EnableResourceServer
    protected static class ResourceServer extends ResourceServerConfigurerAdapter {

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.tokenStore(tokenStore).resourceId(SERVER_RESOURCE_ID);
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            // ... Not important at this stage
        }
    }

    @Configuration
    @EnableAuthorizationServer
    protected static class AuthConfig extends AuthorizationServerConfigurerAdapter {

        @Autowired
        private AuthenticationManager authenticationManager;


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

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            //... Not important at this stage
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM