【问题标题】:Tried accessing nonexisting field (context) on node type (User)尝试访问节点类型(用户)上不存在的字段(上下文)
【发布时间】:2019-08-15 12:46:29
【问题描述】:

我正在从Connection<?> connection 访问connection.fetchUserProfile(),但它提供了org.springframework.social.UncategorizedApiException: (#100) Tried accessing nonexisting field (context) on node type (User)。直到现在,此特定错误从未发生过。

行家:

<dependency>
    <groupId>org.springframework.social</groupId>
    <artifactId>spring-social-facebook</artifactId>
     <version>3.0.0.M3</version>
</dependency>

知道为什么会这样吗?

【问题讨论】:

  • 上下文已被 Facebook 删除,不再存在。如果 Spring 根据一些配置要求这个,你将不得不从那里删除它;否则,您可能需要获取库的更新版本。
  • 我也遇到了同样的问题。我所有的网站都停止工作了。看起来不太好。 Spring Social 已经死了。他们已经停产了。

标签: spring-boot facebook-graph-api spring-social


【解决方案1】:

我遇到了同样的问题,并到处寻找解决方案。运气不好,我最终编写了一个自定义服务,该服务调用 Facebook Graph API 并填充 UserProfile 对象。

为您的项目添加一个新的FBService.java 类:

package net.attacomsian.services;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.*;
import org.springframework.social.connect.UserProfile;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.Collections;

@Service
public class FBService {

    private final RestTemplate restTemplate;

    public FBService(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplate = restTemplateBuilder.build();
    }

    public UserProfile getProfile(String id, String accessToken) {
        try {
            //params
            String params = "fields=id,name,email,first_name,last_name&access_token=" + accessToken;

            //build url
            String url = "https://graph.facebook.com/v3.2/" + id + "?" + params;

            //create headers
            HttpHeaders headers = new HttpHeaders();
            headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

            // create request
            HttpEntity request = new HttpEntity(headers);

            //use rest template
            ResponseEntity<String> response = this.restTemplate.exchange(url, HttpMethod.GET, request, String.class);

            //check for status code
            if (response.getStatusCode().is2xxSuccessful()) {
                JsonNode root =  new ObjectMapper().readTree(response.getBody());

                // return a user profile object
                return new UserProfile(root.path("id").asText(), root.path("name").asText(), root.path("first_name").asText(),
                        root.path("last_name").asText(), root.path("email").asText(), null);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }
}

v3.2 是图形 API 版本。用你自己的替换它。现在将此服务注入您的控制器,而不是调用:

UserProfile profile = connection.fetchUserProfile();

调用新服务getProfile()方法如下:

Profile profile = fbService.getProfile("me", connection.createData().getAccessToken());

它对我来说就像魔法一样。

更新:下面是完整的网络控制器代码,展示了如何使用 Facebook 的自定义服务,同时继续为 Google 的用户配置文件使用默认服务:

@Controller
public class AuthController {

    private FBService fbService;
    private final ProviderSignInUtils providerSignInUtils;

    public AuthController(FBService fbService,
                          ConnectionFactoryLocator connectionFactoryLocator,
                          UsersConnectionRepository connectionRepository) {
        this.fbService = fbService;
        this.providerSignInUtils = new ProviderSignInUtils(connectionFactoryLocator, connectionRepository);
    }

    @GetMapping("/social-signup")
    public String socialSignup(WebRequest request, HttpSession session) {

        Connection<?> connection = providerSignInUtils.getConnectionFromSession(request);
        if (connection == null) {
            return "redirect:/login";
        }

        //fetch user information
        UserProfile profile = null;
        if (connection.getKey().getProviderId().equalsIgnoreCase("google")) {
            profile = connection.fetchUserProfile();
        } else if (connection.getKey().getProviderId().equalsIgnoreCase("facebook")) {
            profile = fbService.getProfile("me", connection.createData().getAccessToken());
        }

        // TODO: continue doing everything else
    }
}

【讨论】:

【解决方案2】:

Facebook 社交好像不会再更新了。

无论如何,我不想花时间切换到另一个库。

我刚刚获取了我需要的字段:

FacebookTemplate facebook = new FacebookTemplate(socialToken);

User facebookUser = facebook.fetchObject(FacebookUtils.LOGGED_USER_ID, User.class, FacebookUtils.USER_FIELD_ID, FacebookUtils.USER_FIELD_EMAIL,
            FacebookUtils.USER_FIELD_FIRST_NAME, FacebookUtils.USER_FIELD_LAST_NAME);

我添加到 FacebookUtils 中的字段:

/** The Constant LOGGED_USER_ID. */
public static final String LOGGED_USER_ID = "me";

/** The Constant USER_FIELD_ID. */
public static final String USER_FIELD_ID = "id";

/** The Constant USER_FIELD_EMAIL. */
public static final String USER_FIELD_EMAIL = "email";

/** The Constant USER_FIELD_FIRST_NAME. */
public static final String USER_FIELD_FIRST_NAME = "first_name";

/** The Constant USER_FIELD_LAST_NAME. */
public static final String USER_FIELD_LAST_NAME = "last_name";

【讨论】:

【解决方案3】:

回答@JohnTD,如果您使用多个社交关系,那么您只需执行以下操作即可合并@attacomsian 回答

   public void getProfile(Connection connection) {
    UserProfile socialMediaProfile = getSocialUserProfile(connection);
      .
      .
}


/**
 * Checks for facebook connection requests so that we can call a custom service
 *
 * @param connection
 * @return
 */
private UserProfile getSocialUserProfile(Connection<?> connection) {
    if (isFacebookConnection(connection)) {
        return facebookService.getProfile("me", connection.createData().getAccessToken());
    } else {
        return connection.fetchUserProfile();
    }
}

private boolean isFacebookConnection(Connection<?> connection) {
    return connection.getApi().toString().indexOf("FacebookTemplate") != -1;
}

【讨论】:

    【解决方案4】:

    我通过用任何其他字段覆盖缺失的字段来解决它。在代码中的某处添加:

        // Patch: spring social facebook tries to get a removed "context" field
        for (int i=0; i<UserOperations.PROFILE_FIELDS.length; i++) {
    
            // To avoid error override with existing "ratings" field
            if (UserOperations.PROFILE_FIELDS[i].equals("context")) {
                UserOperations.PROFILE_FIELDS[i] = "ratings";
            }
        }
    

    【讨论】:

      【解决方案5】:

      EDIT#2:这个问题再次出现在我身上。如果您想弄清楚如何修改某些包并将其添加到 maven,请继续阅读,但是如果您只是想弄清楚如何摆脱该错误(以及其他类似的错误,例如涉及不同的properties) 那么你应该遵循这个答案中的建议:https://stackoverflow.com/a/34133450/754988. 它比我的要好得多。


      虽然 attacomsian 的解决方案可能适用于某些人,但我依赖抽象的 UserProfile 来提供其他服务(例如 Google 登录),而他们的解决方案可能会破坏我。

      我发现一个侵入性较小的操作是前往 ss-facebook's github 并按照他们的说明的前两行从源代码构建:

      git clone git://github.com/SpringSource/spring-social-facebook.git
      cd spring-social-facebook
      

      但在运行./gradlew build 命令之前,请打开此文件进行编辑:

      ./spring-social-facebook/src⁩/main⁩/java⁩/org⁩/springframework⁩/social⁩/facebook⁩/api⁩/UserOperations.java
      

      向下滚动到底部并从数组中删除“上下文”,更改

      static final String[] PROFILE_FIELDS = {
              "id", "about", "age_range", "birthday", "context", "cover", "currency", "devices", "education", "email", 
      
              ....
      
              "website", "work"
          };
      

      static final String[] PROFILE_FIELDS = {
              "id", "about", "age_range", "birthday", "cover", "currency", "devices", "education", "email", 
      
              ....
      
              "website", "work"
          };
      

      现在回到源文件夹并运行最终命令:

      ./gradlew build
      

      您将在那里获得一个 ./build 文件夹,其中包含一个 zip 文件,解压缩它以找到您的工作 jar!我使用 maven,并将我拥有的两个远程依赖项替换为一些本地依赖项,如下所示:

              <dependency>
                  <groupId>org.springframework.social</groupId>
                  <artifactId>spring-social-facebook</artifactId>
                  <version>3.0.0.M1</version>
                  <scope>system</scope>
                  <systemPath>${project.basedir}/src/main/resources/lib/spring-social-facebook-3.0.0.BUILD-SNAPSHOT.jar</systemPath>
              </dependency>
              <dependency>
                  <groupId>org.springframework.social</groupId>
                  <artifactId>spring-social-facebook-web</artifactId>
                  <version>3.0.0.M1</version>
                  <scope>system</scope>
                  <systemPath>${project.basedir}/src/main/resources/lib/spring-social-facebook-web-3.0.0.BUILD-SNAPSHOT.jar</systemPath>
              </dependency>
      

      编辑:我知道这不是在 Maven 中包含这样的自定义 jar 的最佳方式。实际上把它放进去有点像兔子洞,它就像你的 pom 中的其他罐子一样工作。我最终通过运行这些命令来手动安装我制作的两个 jar 使其工作得更好(3.0.1337 是我为避免名称冲突而制作的版本 - 不确定是否有必要)...

      mvn org.apache.maven.plugins:maven-install-plugin:2.3.1:install-file -Dfile=web/src/main/resources/lib/spring-social-facebook-3.0.1337.BUILD-SNAPSHOT.jar -DgroupId=org.springframework.social -DartifactId=spring-social-facebook -Dversion=3.0.1337 -Dpackaging=jar -DlocalRepositoryPath=web/src/main/resources/local-repo -DgeneratePom=true
      
      mvn org.apache.maven.plugins:maven-install-plugin:2.3.1:install-file -Dfile=web/src/main/resources/lib/spring-social-facebook-web-3.0.1337.BUILD-SNAPSHOT.jar -DgroupId=org.springframework.social -DartifactId=spring-social-facebook-web -Dversion=3.0.1337 -Dpackaging=jar -DlocalRepositoryPath=web/src/main/resources/local-repo -DgeneratePom=true
      

      ...进入我在 pom 中声明的本地存储库,如下所示:

      <repositories>
        <repository>
          <id>local-repo</id>
          <url>file://${project.basedir}/src/main/resources/local-repo</url>
        </repository>
      </repositories>
      

      然后我将 jars 添加到源代码管理中,并在我的 gitignore 中添加了一行以忽略 /src/main/resources/local-repo 文件夹。

      如果有人有更好的方法来保留所有原始代码,只需从该文件末尾的数组中删除该“上下文”字符串,并希望避免所有这些垃圾,而是使用简单的单数班级更换或延期,请加入。我只是将所有内容都包括在内,因为它肯定会为我节省一天的时间,让我不得不一一解决这些事情。

      免责声明:我不知道这可能会产生什么副作用,而且我对这个库也不熟悉。尽管我怀疑这是否会造成很大的伤害,并且显然是这一领域的改进,但如果不花更多时间在这个库上工作,我可能无法合理地预见到这种变化。因此,我不提供修改后的 JAR,只是为其他人写下一些简单的说明。继续这些说明,风险自负。

      另外,我刚刚检查了许可证,如果您确实进行了此更改,请确保您按照说明进行操作:

            (b) You must cause any modified files to carry prominent notices
                stating that You changed the files; and
      

      如果我遗漏了任何其他法律内容,请发表评论让我知道。

      【讨论】:

      • 为什么不这样做:
      • 我已经更新了原始答案以包括谷歌身份验证。
      猜你喜欢
      • 2019-12-09
      • 2020-11-19
      • 2017-07-13
      • 2018-07-20
      • 1970-01-01
      • 2015-04-21
      • 1970-01-01
      • 2017-01-09
      • 2017-04-15
      相关资源
      最近更新 更多