如何使用 yii2-dektrium facebook 登录将 access_token 保存到数据库?

How save access_token to db using yii2-dektrium facebook login?

我正在使用 yii2-dektrium 来允许用户使用他们的 Facebook 帐户登录。

登录完成后,我需要从我的服务器发出 API 请求以获取用户帐户的数据。请求示例之一是:

$client = Yii::$app->authClientCollection->getClient('facebook');
$response = $client->createApiRequest()
        ->setMethod('GET')
        ->setUrl('v2.12/me/accounts')
        ->send();

access_token 保存在会话中,因此我需要将其保存到数据库中。

我已经将一列 access_token 添加到 yii2-dektriumsocial_account 默认值 table 但我不知道如何获取和保存它,以及更多, 如何将其应用于请求。

看了一会儿。我认为保存它的方法是覆盖 dektrium\user\controllers\SecurityController.

中的方法 connect
public function connect(ClientInterface $client)
{
    /** @var Account $account */
    $account = \Yii::createObject(Account::className());
    $event   = $this->getAuthEvent($account, $client);
    $this->trigger(self::EVENT_BEFORE_CONNECT, $event);
    $account->connectWithUser($client);
    $this->trigger(self::EVENT_AFTER_CONNECT, $event);
    $this->action->successUrl = Url::to(['/user/settings/networks']);
}

为了申请请求,覆盖 yii\authclient\clients\Facebook

上的 applyAccessTokenToRequest
public function applyAccessTokenToRequest($request, $accessToken)
{
    parent::applyAccessTokenToRequest($request, $accessToken);
    $data = $request->getData();
    if (($machineId = $accessToken->getParam('machine_id')) !== null) {
        $data['machine_id'] = $machineId;
    }
    $data['appsecret_proof'] = hash_hmac('sha256', $accessToken->getToken(), $this->clientSecret);
    $request->setData($data);
}

我无法完成它。而且我不确定这是否是正确的方法。我缺少什么?

第一次保存 access_token 时,您必须覆盖 \dektrium\user\controllers\SecurityController 中的 connect 操作。

class SecurityController extends \dektrium\user\controllers\SecurityController
{
    public function connect(ClientInterface $client)
    {
        // default implementation of connect
        $account = \Yii::createObject(Account::className());
        $event   = $this->getAuthEvent($account, $client);
        $this->trigger(self::EVENT_BEFORE_CONNECT, $event);
        $account->connectWithUser($client);
        $this->trigger(self::EVENT_AFTER_CONNECT, $event);

        // get acess_token from $client
        $access_token['tokenParamKey'] = $client->getAccessToken()->tokenParamKey;
        $access_token['tokenSecretParamKey'] = $client->getAccessToken()->tokenSecretParamKey;
        $access_token['createTimestamp'] = $client->getAccessToken()->createTimestamp;
        $access_token['_expireDurationParamKey'] = $client->getAccessToken()->getExpireDurationParamKey();
        $access_token['_params'] = $client->getAccessToken()->getParams();

        // save acess_token to social_account table
        $model = SocialAccount::find()->where(['provider' => $client->getName()])->andWhere(['user_id' => Yii::$app->user->id])->one();
        $model->access_token = \yii\helpers\Json::encode($access_token);
        $model->save(false);

        $this->action->successUrl = Url::to(['/user/settings/networks']);
    }
}

要在数据库中获取 access_token 存储以供进一步 API 请求创建一个 class 扩展 yii\authclient\SessionStateStorage 并覆盖 get 方法。

namespace app\models\authclient;

class DbStateStorage extends SessionStateStorage
{
    public function get($key)
    {
        // $key is a complex string that ends with 'token' if the value to get is the actual access_token
        $part = explode('_', $key);
        if (count($part) == 3 && $part[2] == 'token') {
            $account = SocialAccount::find()
                ->where(['provider' => $part[1]])
                ->andWhere(['user_id' => Yii::$app->user->id])
                ->one();
            if ($account != null) {
                $access_token = json_decode($account->access_token);
                $token = new \yii\authclient\OAuthToken();
                $token->createTimestamp = $access_token->createTimestamp;
                $token->tokenParamKey = $access_token->tokenParamKey;
                $token->tokenSecretParamKey = $access_token->tokenSecretParamKey;
                $token->setParams((array)$access_token->_params);
                $token->setExpireDurationParamKey($access_token->_expireDurationParamKey);
                return $token;
            }
        }
        if ($this->session !== null) {
            return $this->session->get($key);
        }
        return null;
    }
}

最后将 DbStateStorage 设置为您的 authclient

class Facebook extends \dektrium\user\clients\Facebook
{
    public function __construct()
    {
        $this->setStateStorage('app\models\authclient\DbStateStorage');
    }
}