Spring OAuth2RestTemplate无法获得新的accessToken

时间:2017-08-01 05:31:09

标签: spring-security-oauth2 netflix-zuul spring-oauth2

我正在使用带有 authorization_code流 @EnableZuulProxy 的spring-boot-oauth2。我跟随tut-spring-security-and-angular-js with oauth2中的示例。  为开发目的,我将 access_token_validty 设置为60秒。 Everythings工作正常,直到访问令牌仍然有效。但是当访问令牌过期时(我等了一会儿就过期了),我得到了例外,如下所示..

WARN  SendErrorFilter:78 Error during filtering
com.netflix.zuul.exception.ZuulException: Filter threw Exception
    at com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:227)
    at com.netflix.zuul.FilterProcessor.runFilters(FilterProcessor.java:157)
    at com.netflix.zuul.FilterProcessor.preRoute(FilterProcessor.java:133)
    at com.netflix.zuul.ZuulRunner.preRoute(ZuulRunner.java:105)
    at com.netflix.zuul.http.ZuulServlet.preRoute(ZuulServlet.java:125)
    at com.netflix.zuul.http.ZuulServlet.service(ZuulServlet.java:74)
    at org.springframework.web.servlet.mvc.ServletWrappingController.handleRequestInternal(ServletWrappingController.java:157)
    at org.springframework.cloud.netflix.zuul.web.ZuulController.handleRequest(ZuulController.java:44)
    at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:50)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:116)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:110)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:116)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at com.t3k.products.t3k_portal.backend.config.SecurityConfig$1.doFilterInternal(SecurityConfig.java:112)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:124)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter.doFilter(OAuth2ClientContextFilter.java:60)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter.doFilter(OAuth2ClientContextFilter.java:60)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:106)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1455)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Unknown Source)
Caused by: org.springframework.security.authentication.BadCredentialsException: Cannot obtain valid access token
    at org.springframework.cloud.security.oauth2.proxy.OAuth2TokenRelayFilter.getAccessToken(OAuth2TokenRelayFilter.java:99)
    at org.springframework.cloud.security.oauth2.proxy.OAuth2TokenRelayFilter.run(OAuth2TokenRelayFilter.java:79)
    at com.netflix.zuul.ZuulFilter.runFilter(ZuulFilter.java:112)
    at com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:193)
    ... 102 more

我使用的是spring-boot 1.5.4版,我还将OAuth2RestTemplate配置为this github问题。任何建议都会非常感激。

3 个答案:

答案 0 :(得分:0)

正在使用相同的教程并在实现访问令牌刷新时遇到同样的问题。

Caused by: org.springframework.security.authentication.BadCredentialsException: Cannot obtain valid access token
    at org.springframework.cloud.security.oauth2.proxy.OAuth2TokenRelayFilter.getAccessToken(OAuth2TokenRelayFilter.java:99) ~[spring-cloud-security-1.2.1.RELEASE.jar:1.2.1.RELEASE]

具体 - 当我收到错误时,我的测试应用程序被修改为使用通常的令牌,而不是JWT,但我认为解决问题并不重要。

澄清问题:

1)为客户添加密码授予:

@Configuration
@EnableAuthorizationServer
protected static class AuthServerConfig
    extends AuthorizationServerConfigurerAdapter {

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.inMemory()
        .withClient("app0")
        .secret("secret0")
        .authorizedGrantTypes("authorization_code","refresh_token","password")
        .scopes("some_scope");
}

2)通过curl执行以下请求(可以使用postman或其他首选实用程序)

curl -X POST \
  http://localhost:9999/uaa/oauth/token \
  -H 'authorization: Basic YXBwMDpzZWNyZXQw' \
  -H 'content-type: multipart/form-data;' \
  -F grant_type=password \
  -F scope=some_scope \
  -F username=john \
  -F password=123

3)它返回

{
    "access_token": "cc5fff72-8f09-4770-87f5-f2237ce5978f",
    "token_type": "bearer",
    "refresh_token": "da55eb5c-6d31-4d70-9af8-bad8ce8a777f",
    "expires_in": 43199,
    "scope": "some_scope"
}

4)获取refresh_token的值并在下一个curl命令

中使用它
curl -X POST \
  http://localhost:9999/uaa/oauth/token \
  -H 'authorization: Basic YXBwMDpzZWNyZXQw' \
  -H 'content-type: multipart/form-data;' \
  -F grant_type=refresh_token \
  -F scope=some_scope \
  -F refresh_token=da55eb5c-6d31-4d70-9af8-bad8ce8a777f

5)得到答案:

{"error":"server_error","error_description":"UserDetailsService is required."}

使用错误说明可以轻松地found on GitHub

找到合适的解决方案和解释

简单地说,有必要将UserDetailsS​​ervice注入AuthorizationServerConfiguration并将其添加到AuthorizationServerEndpointsConfigurer配置中。例如:

@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
        throws Exception {
    endpoints
        .authenticationManager(authenticationManager)
        .userDetailsService(userDetailsService);

}

如果在此修改后发生以下错误

***************************
APPLICATION FAILED TO START
***************************

Description:

Field userDetailsService in demo.AuthserverApplication$AuthServerConfig required a bean of type 'org.springframework.security.core.userdetails.UserDetailsService' that could not be found.


Action:

Consider defining a bean of type 'org.springframework.security.core.userdetails.UserDetailsService' in your configuration.

这意味着auth服务器代码缺少显式定义的UserDetailsS​​ervice(就像在问题中提到的原始教程一样)

出于测试目的,内存中的UserDetailsS​​ervice bean可以像这样指定

@EnableResourceServer
public class AuthserverApplication extends WebMvcConfigurerAdapter {

    @Bean
    public UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("john").password("123").roles("USER").build());
        manager.createUser(User.withUsername("ivan").password("123").roles("USER").build());
        return manager;
    }

答案 1 :(得分:0)

OAuth服务器调用用户详细信息查询,因此需要为UserDetailsS​​ervice注入一个bean。在我的情况下,我能够通过LdapUserDetailsS​​ervice获得这个,因为我的用户详细信息保存在LDAP中。

答案 2 :(得分:0)

作为tut-spring-security-and-angular-js的示例,我还有3个应用 UI API Auth 。我的 UI 应用程序有3种方案可以从我的 API 应用程序中获取数据。

  1. 来自我的 UI 应用程序本身(我必须从数据库加载一些设置和信息)
  2. 对于登录用户(我的 UI 应用程序显示与当前登录用户及其角色相关的一些内容)
  3. 用于客户端(某些页面使用JQuery加载数据ajax calls.eg:show表格格式为JQuery DataTable
  4. 对于案例1:我使用spring-oauth2 密码流和管理员帐户。所以我创建了以

    的形式获取刷新令牌和访问令牌
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.Map;
    
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.HttpMethod;
    import org.springframework.http.converter.FormHttpMessageConverter;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.http.converter.StringHttpMessageConverter;
    import org.springframework.util.Assert;
    import org.springframework.web.client.RestTemplate;
    
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.SerializationFeature;
    import com.fasterxml.jackson.datatype.joda.JodaModule;
    import com.jayway.restassured.RestAssured;
    import com.jayway.restassured.config.ObjectMapperConfig;
    import com.jayway.restassured.mapper.factory.Jackson2ObjectMapperFactory;
    import com.jayway.restassured.response.Response;
    import com.jayway.restassured.specification.RequestSpecification;
    
    @Configuration
    public class RestServiceConfig implements InitializingBean {
    
    
        private static final Logger applicationLogger = LogManager.getLogger("applicationLogs." + RestServiceConfig.class.getName());
    
        private static String applicationResourceUrl;
    
        private static String authServerTokenURI;
    
        private static String authServerClientId;
    
        private static String authServerClientSecret;
    
        private static String rootUserName;
    
        private static String rootUserSecret;
    
        @Value("${security.oauth2.client.access-token-uri}")
        public void setAuthServerTokenURI(String url) {
            authServerTokenURI = url;
        }
    
        @Value("${security.oauth2.client.client-id}")
        public void setAuthServerClientId(String clientId) {
            authServerClientId = clientId;
        }
    
        @Value("${security.oauth2.client.client-secret}")
        public void setAuthServerClientSecret(String secret) {
            authServerClientSecret = secret;
        }
    
        @Value("${root-user.name}")
        public void setRootUserName(String name) {
            rootUserName = name;
        }
    
        @Value("${root-user.secret}")
        public void setRootUserSecret(String secret) {
            rootUserSecret = secret;
        }
    
        @Value("${api-server.application}/api/")
        public void setApplicationResourceUrl(String url) {
            applicationResourceUrl = url;
        }
    
        private static String refreshToken;
        private static String accessToken;
    
    
        public static final String createURL(String path) {
            applicationLogger.info("Create REST service URI ==> " + applicationResourceUrl + path);
            return applicationResourceUrl + path;
    
        }
    
        public static final Response processed(String url, HashMap<String, ?> headers, Object body, HttpMethod method) {
            RequestSpecification request = getRestTemplate().contentType("application/json");
            if (headers != null) {
                request.headers(headers);
            }
            Response response = null;
            switch (method) {
            case POST: {
                response = request.body(body).post(createURL(url));
                break;
            }
            case PUT: {
                response = request.body(body).put(createURL(url));
                break;
            }
            case GET: {
                response = request.get(createURL(url));
                break;
            }
            case DELETE: {
                response = request.body(body).delete(createURL(url));
                break;
            }
            default:
                break;
    
            }
            // if access-token has expired, obtained new one and resend current
            // request
            if (response.getStatusCode() == 401) {
                accessToken = obtainAccessToken(refreshToken);
                return processed(url, headers, body, method);
            }
            return response;
    
        }
    
        public static <T> T parse(Response response, Class<T> responseType) {
            if (response.getStatusCode() != 200 || response.body().asString().equals("")) {
                return null;
            }
            return response.getBody().as(responseType);
        }
    
        private static final RequestSpecification getRestTemplate() {
            return RestAssured.given().header("Authorization", "Bearer " + accessToken);
        }
    
        private static final String obtainRootUserRefreshToken() {
            applicationLogger.info("----- Generation New refresh-token for Root User -----");
            final Map<String, String> params = new HashMap<String, String>();
            params.put("grant_type", "password");
            params.put("client_id", authServerClientId);
            params.put("username", rootUserName);
            params.put("password", rootUserSecret);
        // @formatter:off
            final Response response = RestAssured.given()
                    .auth().preemptive().basic(authServerClientId, authServerClientSecret)
                    .and()
                        .with().params(params)
                        .when().post(authServerTokenURI);
        // @formatter:on
            String refreshToken = response.jsonPath().getString("refresh_token");
            applicationLogger.info("Obtained New Refresh Token ==> " + refreshToken);
            Assert.notNull(refreshToken, "Failed for fetching Refresh Token. This problem can be caused by failed to connect Authetication server.");
            return refreshToken;
        }
    
        private synchronized final static String obtainAccessToken(String refreshToken) {
            applicationLogger.info("----- Generation New access-token for Root User with refresh-token[" + refreshToken + "] -----");
            final Map<String, String> params = new HashMap<String, String>();
            params.put("grant_type", "refresh_token");
            params.put("client_id", authServerClientId);
            params.put("refresh_token", refreshToken);
        // @formatter:off
            final Response response = RestAssured.given()
                .auth().preemptive().basic(authServerClientId, authServerClientSecret)
                .with().params(params)
                .when().post(authServerTokenURI);
        // @formatter:on
            String accessToken = response.jsonPath().getString("access_token");
            Assert.notNull(accessToken, "Failed for fetching Access Token. This problem can be caused by failed to connect Authetication server.");
            return accessToken;
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            // RestAssured.defaultParser = Parser.JSON;
            RestAssured.config = RestAssured.config().objectMapperConfig(ObjectMapperConfig.objectMapperConfig().jackson2ObjectMapperFactory(new Jackson2ObjectMapperFactory() {
                @SuppressWarnings("rawtypes")
                @Override
                public ObjectMapper create(Class cls, String charset) {
                    // create custom objectMapper to parse Joda DateTime for RestAssured
                    ObjectMapper objectMapper = new ObjectMapper();
                    objectMapper.registerModule(new JodaModule());
                    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
                    objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
                    return objectMapper;
                }
            }));
            refreshToken = obtainRootUserRefreshToken();
            accessToken = obtainAccessToken(refreshToken);
        }
    
    }
    

    以下是从我的 API 服务器

    获取应用程序设置的示例代码
    public List<Setting> loadApplicationSettings() {
        // @formatter:off
        SettingCriteria criteria = new SettingCriteria();
        criteria.setApplicationId(1234l);
        criteria.setStatus(Status.ACTIVE);
        final Response response = RestServiceConfig.processed(
                "settings/search/list", 
                null, 
                criteria,HttpMethod.POST);
            // @formatter:on        
        return Arrays.asList(response.getBody().as(Setting[].class));
    }
    

    对于案例2:我使用@EnableZuulProxy作为tut-spring-security-and-angular-js

    注意:请勿将zuul映射设为公开映射。请参阅this answer

    对于案例3:我使用了spring-oauth2的Oauth2RestTemplate作为

    import java.net.URI;
    import java.net.URISyntaxException;
    
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Conditional;
    import org.springframework.http.HttpMethod;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.RequestEntity;
    import org.springframework.http.ResponseEntity;
    import org.springframework.security.oauth2.client.OAuth2RestOperations;
    import org.springframework.stereotype.Service;
    import org.springframework.util.LinkedMultiValueMap;
    import org.springframework.util.MultiValueMap;
    
    
    @Service
    public class OAuth2RestService {
        private static final Logger serviceLogger = LogManager.getLogger("serviceLogs." + OAuth2RestService.class.getName());
    
        @Autowired
        private OAuth2RestOperations restTemplate;
    
        public <T> T get(String url, Class<T> responseType, HttpHeader... headers) {
            return processRestService(url, HttpMethod.GET, null, responseType, headers);
        }
    
        public <T> T post(String url, Object body, Class<T> responseType, HttpHeader... headers) {
            return processRestService(url, HttpMethod.POST, body, responseType, headers);
        }
    
        public <T> T put(String url, Object body, Class<T> responseType, HttpHeader... headers) {
            return processRestService(url, HttpMethod.PUT, body, responseType, headers);
        }
    
        public <T> T delete(String url, Object body, Class<T> responseType, HttpHeader... headers) {
            return processRestService(url, HttpMethod.DELETE, body, responseType, headers);
        }
    
        private <T> T processRestService(String url, HttpMethod method, Object body, Class<T> responseType, HttpHeader... headers) {
            serviceLogger.info("Request URL [ " + url + " ] | Request Method [ " + method.name() + " ] | Expected Response-Type [ " + responseType + " ]");
            try {
                MultiValueMap<String, String> headerInfos = null;
                if (headers != null && headers.length > 0) {
                    headerInfos = new LinkedMultiValueMap<String, String>();
                    for (HttpHeader header : headers) {
                        headerInfos.add(header.getName(), header.getValue().toString());
                    }
                }
                RequestEntity<Object> requestEntity = new RequestEntity<Object>(body, headerInfos, method, new URI(RestServiceConfig.createURL(url)));
                ResponseEntity<T> response = restTemplate.exchange(requestEntity, responseType);
                if (response.getStatusCode() == HttpStatus.OK) {
                    return response.getBody();
                }
            }
            catch (URISyntaxException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    

    我们必须将OAuth2RestOperations配置为自己。

    @Configuration
    public class AppConfig {
    
        @Bean
        public RequestContextListener requestContextListener() {
            return new RequestContextListener();
        }
    
        @Bean
        @Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
        public OAuth2RestOperations oAuth2RestOperations(OAuth2ProtectedResourceDetails details, OAuth2ClientContext oauth2ClientContext) {
            OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(details, oauth2ClientContext);
            return oAuth2RestTemplate;
        }
    
    }
    

    HttpHeader类

    public class HttpHeader {
        private String name;
        private Object value;
    
        public HttpHeader(String name, Object value) {
            this.name = name;
            this.value = value;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Object getValue() {
            return value;
        }
    
        public void setValue(Object value) {
            this.value = value;
        }
    
    }
    

    以下是使用Oauth2RestService

    的示例代码
    @Controller
    @RequestMapping("/company")
    public class CompanyController extends BaseController {
    
        @Autowired
        private OAuth2RestService restService;
    
        @GetMapping
        public String company(Model model) {
            CompanyCriteria criteria = new CompanyCriteria();
            criteria.setWithStaticContent(true);
            criteria.setWithSubKey(true);
            List<CompanyBean> companies = Arrays.asList(restService.post("company/search/list", criteria, CompanyBean[].class));
            model.addAttribute("companies", companies);
            return "home_page";
        }
    
    }
    

    另一个api电话

    .....
    UserCriteria criteria = new UserCriteria();
    criteria.setEmail(email);
    HashMap<String, Object> myHeaders = new HashMap<>();
    myHeaders.put("key", "value");
    restService.put("user/search", criteria, Long.class, new HttpHeader("someHeaders", myHeaders));
    

    如果不是为了获取单个用户并发的访问令牌,那么Everythings工作正常。

    例如,在执行客户端请求之前,我为每个请求提供了一些过滤器,这些请求是从我的 API 服务器获取一些数据。但是我从客户端获得了JQuery ajax调用方法,这些方法是异步运行的。在这种情况下,我的过滤器也会运行异步,当我的密码流的管理员帐户的访问令牌已过期时,这会出错。 见线程Concurrency problems refreshing OAuth2 tokens。所以我在现有过期时获取新访问令牌的方法中添加了synchronized

    我希望对你有所帮助。如果您从我的代码中发现了一些弱点或代码,请不要费心去纠正我。