java - Spring 社交 facebook 无法解码从 facebook 访问 token URI 发送的信息

标签 java spring facebook facebook-graph-api oauth-2.0

该代码大约一周前按预期工作,并用于解释访问 token 。现在突然开始抛出异常:

org.springframework.social.MissingAuthorizationException: Authorization is required for the operation, but the API binding was created without authorization.
    at org.springframework.social.facebook.api.impl.AbstractFacebookOperations.requireAuthorization(AbstractFacebookOperations.java:30)
    at org.springframework.social.facebook.api.impl.UserTemplate.getUserProfile(UserTemplate.java:48)
    at org.springframework.social.facebook.connect.FacebookAdapter.setConnectionValues(FacebookAdapter.java:42)
    at org.springframework.social.facebook.connect.FacebookAdapter.setConnectionValues(FacebookAdapter.java:30)
    at org.springframework.social.connect.support.AbstractConnection.setValues(AbstractConnection.java:174)
    at org.springframework.social.connect.support.AbstractConnection.initKey(AbstractConnection.java:137)
    at org.springframework.social.connect.support.OAuth2Connection.<init>(OAuth2Connection.java:75)
    at org.springframework.social.connect.support.OAuth2ConnectionFactory.createConnection(OAuth2ConnectionFactory.java:91)
    at org.springframework.social.security.provider.OAuth2AuthenticationService.getAuthToken(OAuth2AuthenticationService.java:99)
    at org.springframework.social.security.SocialAuthenticationFilter.attemptAuthService(SocialAuthenticationFilter.java:239)
    at org.springframework.social.security.SocialAuthenticationFilter.attemptAuthentication(SocialAuthenticationFilter.java:157)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:211)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:85)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration$MetricsFilter.doFilterInternal(MetricFilterAutoConfiguration.java:90)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1085)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658)
    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513)
    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)

我尝试调试库内的代码,发现返回的响应不是所需的格式,需要由spring-social-facebook-1.1.1.RELEASE-sources.jar-解释> FacebookOAuth2Template-> postForAccessGrant()。在下面的代码片段中,access_token和expires需要与键值一起使用。

@Override
    @SuppressWarnings("unchecked")  
    protected AccessGrant postForAccessGrant(String accessTokenUrl, MultiValueMap<String, String> parameters) {
        MultiValueMap<String, String> response = getRestTemplate().postForObject(accessTokenUrl, parameters, MultiValueMap.class);
        String expires = response.getFirst("expires");
        return new AccessGrant(response.getFirst("access_token"), null, null, expires != null ? Long.valueOf(expires) : null);
    }

从 Facebook 图形访问 token API 返回的响应是:

{{"access_token":"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","token_type":"bearer","expires_in":5157689}=[null]}

response.get 行尝试从值字段中检索这些值,在本例中为 null。因此,它将 accessTokenexpiry 值设置为 null

最佳答案

我添加了下面的类作为项目的临时修复,该项目覆盖了库中的现有类,但这不是一个正确的解决方案。有什么办法可以解决这个问题吗?

package org.springframework.social.facebook.connect;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.social.oauth2.AccessGrant;
import org.springframework.social.oauth2.OAuth2Template;
import org.springframework.social.support.ClientHttpRequestFactorySelector;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

public class FacebookOAuth2Template extends OAuth2Template {

    private static final Logger LOGGER = LogManager.getLogger(FacebookOAuth2Template.class);

    public FacebookOAuth2Template(String clientId, String clientSecret) {
        super(clientId, clientSecret, "https://www.facebook.com/v1.0/dialog/oauth", "https://graph.facebook.com/v1.0/oauth/access_token");
        setUseParametersForClientAuthentication(true);
    }

    @Override
    protected RestTemplate createRestTemplate() {
        RestTemplate restTemplate = new RestTemplate(ClientHttpRequestFactorySelector.getRequestFactory());
        FormHttpMessageConverter messageConverter = new FormHttpMessageConverter() {
            @Override
            public boolean canRead(Class<?> clazz, MediaType mediaType) {
                // always read as x-www-url-formencoded even though Facebook sets contentType to text/plain
                return true;
            }
        };
        restTemplate.setMessageConverters(Collections.<HttpMessageConverter<?>> singletonList(messageConverter));
        return restTemplate;
    }

    @Override
    @SuppressWarnings("unchecked")
    protected AccessGrant postForAccessGrant(String accessTokenUrl, MultiValueMap<String, String> parameters) {
        MultiValueMap<String, String> response = getRestTemplate().postForObject(accessTokenUrl, parameters, MultiValueMap.class);
        String expires = response.getFirst("expires");
        String accessToken = response.getFirst("access_token");
        if(!response.keySet().isEmpty() && (StringUtils.isEmpty(expires) || StringUtils.isEmpty(accessToken))) {
            for(String key : response.keySet()) {
                boolean valuesFound = false;
                HashMap<String, String> map;
                try {
                    //map = (HashMap<String, String>) JSONUtil.fromJSON(key, HashMap.class);
                    ObjectMapper objectMapper = new ObjectMapper();
                    map = objectMapper.readValue(key, HashMap.class);

                    if(StringUtils.isEmpty(expires)) {
                        expires = String.valueOf(map.get("expires_in"));
                        valuesFound = true;
                    }

                    if(StringUtils.isEmpty(accessToken)) {
                        accessToken = map.get("access_token");
                        valuesFound = true;
                    }

                    if(valuesFound) {
                        break;
                    }
                } catch(IOException e) {
                    LOGGER.error(e.getMessage(), e);
                }
            }
        }
        return new AccessGrant(accessToken, null, null, expires != null ? Long.valueOf(expires) : null);
    }
}

关于java - Spring 社交 facebook 无法解码从 facebook 访问 token URI 发送的信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43106228/

相关文章:

java - Spring - Http Basic Auth - 将端点标记为公共(public)

STS 中缺少 Spring/Spring bean 配置文件选项

spring - 如何在过去设置@CreatedDate(用于测试)

javascript - 点击时使用 Facebook Pixel 跟踪注册情况(JS/JQUERY 代码)

python - 通过Python SDK获取facebook OAuth access_token似乎不起作用,有什么想法吗?

ios - 我们可以更改 IOS Safari 浏览器的原生分享按钮(Twitter 和 Facebook)中的 url 吗?

java - 停止后媒体播放器不启动

java - Hibernate PostgreSQL OneToOne 关系首先触发子查询

java - Maven 父 pom 与模块 pom

java - 将 Assets 文件夹子目录复制到外部存储中的特定文件夹