2

今天早上当我意识到 Facebook 登录在我的应用程序中不再工作时,我做得很好。正如我提到的,我正在使用带有剪影版本 2.0-RC1 的游戏框架。

这就是问题:

[Silhouette][facebook] Cannot build OAuth2Info because of invalid response format  : {"access_token":"EAAE2YyQkAUUBANAfoUfhdG8jrRfJnhrgZCaZB5FsZAO1G5Jq0ITTfZA6coj4g0HuUC48JToHCnZCFx8r9Q3JZCulzt6SaEcRqKrxNealsBldH4dpzJpK4oeblZAmxjq9Rjzl2rO3IKPUwllWAv5vEz33cGc4XeqLSgZD","token_type":"bearer","expires_in":5183717}

问题是身份验证的 Json 响应没有 OAuth2Info 期望的正确格式,这很奇怪,因为我们从未接触过身份验证机制,我很担心,因为它可能是库版本问题,更新剪影不是现在的选项...有人遇到这个问题并找到了解决方案吗?请帮帮我...非常感谢。

4

1 回答 1

1

我们必须创建 FacebookProvider 的自定义实现以处理新的 facebook 的答案。这里是

    import com.mohiva.play.silhouette.api.LoginInfo
    import com.mohiva.play.silhouette.api.exceptions.AuthenticationException
    import com.mohiva.play.silhouette.api.util.HTTPLayer
    import com.mohiva.play.silhouette.impl.exceptions.ProfileRetrievalException
    import com.mohiva.play.silhouette.impl.providers.OAuth2Provider._
    import com.mohiva.play.silhouette.impl.providers._
    import com.mohiva.play.silhouette.impl.providers.oauth2.{FacebookProfileBuilder, FacebookProvider}
    import com.mohiva.play.silhouette.impl.providers.oauth2.FacebookProvider._
    import play.api.libs.concurrent.Execution.Implicits._
    import play.api.libs.json.{ JsObject, JsValue }
    import play.api.libs.ws.WSResponse
    import play.api.libs.json._

    import scala.concurrent.Future
    import scala.util.{ Failure, Success, Try }

    /**
     * A Facebook OAuth2 Provider.
     *
     * @param httpLayer The HTTP layer implementation.
     * @param stateProvider The state provider implementation.
     * @param settings The provider settings.
     *
     * @see https://developers.facebook.com/tools/explorer
     * @see https://developers.facebook.com/docs/graph-api/reference/user
     * @see https://developers.facebook.com/docs/facebook-login/access-tokens
     */
    abstract class FacebookProvider(httpLayer: HTTPLayer, stateProvider: OAuth2StateProvider, settings: OAuth2Settings)
      extends OAuth2Provider(httpLayer, stateProvider, settings) {

      /**
       * The content type to parse a profile from.
       */
      type Content = JsValue

      /**
       * Gets the provider ID.
       *
       * @return The provider ID.
       */
      val id = ID

      /**
       * Defines the URLs that are needed to retrieve the profile data.
       */
      protected val urls = Map("api" -> API)

      /**
       * Builds the social profile.
       *
       * @param authInfo The auth info received from the provider.
       * @return On success the build social profile, otherwise a failure.
       */
      protected def buildProfile(authInfo: OAuth2Info): Future[Profile] = {
        httpLayer.url(urls("api").format(authInfo.accessToken)).get().flatMap { response =>
          val json = response.json
          (json \ "error").asOpt[JsObject] match {
            case Some(error) =>
              val errorMsg = (error \ "message").as[String]
              val errorType = (error \ "type").as[String]
              val errorCode = (error \ "code").as[Int]

              throw new ProfileRetrievalException(SpecifiedProfileError.format(id, errorMsg, errorType, errorCode))
            case _ => profileParser.parse(json)
          }
        }
      }

      /**
       * Builds the OAuth2 info from response.
       *
       * @param response The response from the provider.
       * @return The OAuth2 info on success, otherwise a failure.
       */
      override def buildInfo(response: WSResponse): Try[OAuth2Info] = {
        val responseJson = Json.parse(response.body)
        responseJson.validate[OAuth2Info].asEither.fold(
          error => Failure(new AuthenticationException(InvalidInfoFormat.format(id, error))),
          info => Success(info)
        )
      }
    }

    /**
     * The profile parser for the common social profile.
     */
    class FacebookProfileParser extends SocialProfileParser[JsValue, CommonSocialProfile] {

      /**
       * Parses the social profile.
       *
       * @param json The content returned from the provider.
       * @return The social profile from given result.
       */
      def parse(json: JsValue) = Future.successful {
        val userID = (json \ "id").as[String]
        val firstName = (json \ "first_name").asOpt[String]
        val lastName = (json \ "last_name").asOpt[String]
        val fullName = (json \ "name").asOpt[String]
        val avatarURL = (json \ "picture" \ "data" \ "url").asOpt[String]
        val email = (json \ "email").asOpt[String]

        CommonSocialProfile(
          loginInfo = LoginInfo(ID, userID),
          firstName = firstName,
          lastName = lastName,
          fullName = fullName,
          avatarURL = avatarURL,
          email = email)
      }
    }

    /**
     * The profile builder for the common social profile.
     */
    trait FacebookProfileBuilder extends CommonSocialProfileBuilder {
      self: FacebookProvider =>

      /**
       * The profile parser implementation.
       */
      val profileParser = new FacebookProfileParser
    }

    /**
     * The companion object.
     */
    object FacebookWesuraProvider {

      /**
       * The error messages.
       */
      val SpecifiedProfileError = "[Silhouette][%s] Error retrieving profile information. Error message: %s, type: %s, code: %s"

      /**
       * The Facebook constants.
       */
      val ID = "facebook"
      val API = "https://graph.facebook.com/me?fields=name,first_name,last_name,picture,email&return_ssl_resources=1&access_token=%s"

      /**
       * Creates an instance of the provider.
       *
       * @param httpLayer The HTTP layer implementation.
       * @param stateProvider The state provider implementation.
       * @param settings The provider settings.
       * @return An instance of this provider.
       */
      def apply(httpLayer: HTTPL

ayer, stateProvider: OAuth2StateProvider, settings: OAuth2Settings) = {
    new FacebookProvider(httpLayer, stateProvider, settings) with FacebookProfileBuilder
  }
}
于 2017-03-29T20:09:03.833 回答