Open ahmadfadlydziljalal opened 1 year ago
I have 2 apps:
Everything is looked good in every step at Yii2 server side:
'components' => [ 'urlManager' => [ 'enablePrettyUrl' => true, 'showScriptName' => false, 'rules' => [ '<alias:\w+>' => 'site/<alias>', 'POST oauth2/<action:\w+>' => 'oauth2/rest/<action>', ] ], ], 'modules' => [ 'oauth2' => [ 'class' => 'filsh\yii2\oauth2server\Module', 'components' => [ 'request' => function () { return \filsh\yii2\oauth2server\Request::createFromGlobals(); }, 'response' => [ 'class' => \filsh\yii2\oauth2server\Response::class, ], ], 'tokenParamName' => 'accessToken', 'tokenAccessLifetime' => 3600 * 24, 'storageMap' => [ 'user_credentials' => 'app\models\User', ], 'grantTypes' => [ 'user_credentials' => [ 'class' => 'OAuth2\GrantType\UserCredentials', ], 'authorization_code' => [ 'class' => 'OAuth2\GrantType\AuthorizationCode' ], 'refresh_token' => [ 'class' => 'OAuth2\GrantType\RefreshToken', //'always_issue_new_refresh_token' => true ] ], 'options' => [ 'allow_implicit' => true ] ], ....
But the problem is, when client side successfully login, why userAttributes is null ? In Yii2 client side, I set the SiteController like this:
/** * {@inheritdoc} */ public function actions() { return [ 'error' => [ 'class' => 'yii\web\ErrorAction', ], 'captcha' => [ 'class' => 'yii\captcha\CaptchaAction', 'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null, ], 'auth' => [ 'class' => 'yii\authclient\AuthAction', 'successCallback' => [$this, 'onAuthSuccess'], ], ]; } public function onAuthSuccess($client) { (new AuthHandler($client))->handle(); }
Then, in AuthHandler:
<?php namespace app\components; use app\models\Auth; use app\models\User; use Exception; use Yii; use yii\authclient\ClientInterface; use yii\helpers\ArrayHelper; use yii\helpers\Html; use yii\helpers\StringHelper; use yii\helpers\VarDumper; /** * AuthHandler handles successful authentication via Yii auth component */ class AuthHandler { /** * @var ClientInterface */ private ClientInterface $client; public function __construct(ClientInterface $client) { $this->client = $client; } /** * @return void * @throws \yii\base\Exception * @throws \yii\db\Exception * @throws Exception */ public function handle() { $attributes = $this->client->getUserAttributes(); /* * for debugging * die(Html::tag('pre', VarDumper::dumpAsString($attributes))); * */ $email = ArrayHelper::getValue($attributes, 'email'); $id = ArrayHelper::getValue($attributes, 'id'); $nickname = str_replace(" ", "-", ArrayHelper::getValue($attributes, 'name')); /* @var Auth $auth */ $auth = Auth::find()->where([ 'source' => $this->client->getId(), 'source_id' => $id, ])->one(); if (Yii::$app->user->isGuest) { if ($auth) { // login $user = $auth->user; $this->updateUserInfo($user); Yii::$app->user->login($user, Yii::$app->params['user.rememberMeDuration']); Yii::$app->getSession()->setFlash( 'success', 'Login by ' . ucfirst($this->client->getId()) . ' Welcome! ' ); } else { // signup if ($email !== null && User::find()->where(['email' => $email])->exists()) { Yii::$app->getSession()->setFlash('error', [ Yii::t('app', "User with the same email as in {client} account already exists but isn't linked to it. Login using email first to link it.", ['client' => $this->client->getTitle()]), ]); } else { $password = Yii::$app->security->generateRandomString(Yii::$app->params['user.passwordMinLength']); $user = new User([ 'username' => $nickname, //'github' => $nickname, 'email' => $email, 'password' => $password, ]); $user->generateAuthKey(); $user->generatePasswordResetToken(); $transaction = User::getDb()->beginTransaction(); if ($user->save()) { $auth = new Auth([ 'user_id' => $user->id, 'source' => $this->client->getId(), 'source_id' => (string)$id, ]); if ($auth->save()) { $transaction->commit(); Yii::$app->getSession()->setFlash( 'success', 'Joined as ' . ucfirst($this->client->getId()) . ', and welcome...! ' ); Yii::$app->user->login($user, Yii::$app->params['user.rememberMeDuration']); } else { Yii::$app->getSession()->setFlash('error', [ Yii::t('app', 'Unable to save {client} account: {errors}', [ 'client' => $this->client->getTitle(), 'errors' => yii\helpers\Json::encode($auth->getErrors()), ]), ]); } } else { Yii::$app->getSession()->setFlash('error', [ Yii::t('app', 'Unable to save user: {errors}', [ 'client' => $this->client->getTitle(), 'errors' => yii\helpers\Json::encode($user->getErrors()), ]), ]); } } } } else { // user already logged in if (!$auth) { // add auth provider $auth = new Auth([ 'user_id' => Yii::$app->user->id, 'source' => $this->client->getId(), 'source_id' => (string)$attributes['id'], ]); if ($auth->save()) { $user = $auth->user; $this->updateUserInfo($user); Yii::$app->getSession()->setFlash('success', [ Yii::t('app', 'Linked {client} account.', [ 'client' => $this->client->getTitle() ]), ]); } else { Yii::$app->getSession()->setFlash('error', [ Yii::t('app', 'Unable to link {client} account: {errors}', [ 'client' => $this->client->getTitle(), 'errors' => yii\helpers\Json::encode($auth->getErrors()), ]), ]); } } else { // there's existing auth Yii::$app->getSession()->setFlash('error', [ Yii::t( 'app', 'Unable to link {client} account. There is another user using it.', ['client' => $this->client->getTitle()] ), ]); } } } /** * @param User $user * @return void * @throws Exception */ private function updateUserInfo(User $user) { $attributes = $this->client->getUserAttributes(); $github = ArrayHelper::getValue($attributes, 'login'); if ($github) { if ($user->github === null) { $user->github = $github; $user->save(); } } } }
Here is the config that I used in Yii2 client side:
<?php namespace app\components; use yii\authclient\OAuth2; class MyAuthClient extends OAuth2 { protected function defaultName() { return 'my_auth_client'; } protected function defaultTitle() { return 'My Auth Client'; } protected function initUserAttributes() { return $this->api('userinfo', 'GET'); } }
'components' => [ 'authClientCollection' => [ 'class' => 'yii\authclient\Collection', 'clients' => [ 'myauth' => [ 'class' => '\app\components\MyAuthClient', 'clientId' => 'testclient', 'clientSecret' => 'testpass', 'authUrl' => 'http://10.60.36.60:8080/authorize', 'tokenUrl' => 'http://10.60.36.60:8080/oauth2/token', 'apiBaseUrl' => 'http://10.60.36.60:8080/apis/oauth2/v1' ], ], ], ....
And, Here is the info:
app\components\MyAuthClient#1 ( [yii\base\Component:_events] => [] [yii\base\Component:_eventWildcards] => [] [yii\base\Component:_behaviors] => null [yii\authclient\BaseClient:_id] => 'myauth' [yii\authclient\BaseClient:_name] => null [yii\authclient\BaseClient:_title] => null [yii\authclient\BaseClient:_userAttributes] => null [yii\authclient\BaseClient:_normalizeUserAttributeMap] => null [yii\authclient\BaseClient:_viewOptions] => null [yii\authclient\BaseClient:_httpClient] => yii\httpclient\Client#2 ( [yii\base\Component:_events] => [] [yii\base\Component:_eventWildcards] => [] [yii\base\Component:_behaviors] => [] [baseUrl] => 'http://10.60.36.60:8080/apis/oauth2/v1' [formatters] => [ 'urlencoded' => yii\httpclient\UrlEncodedFormatter#3 ( [encodingType] => 1 [charset] => null ) ] [parsers] => [ 'json' => yii\httpclient\JsonParser#4 ( [asArray] => true ) ] [requestConfig] => [] [responseConfig] => [] [contentLoggingMaxSize] => 2000 [yii\httpclient\Client:_transport] => yii\httpclient\StreamTransport#5 ( [yii\base\Component:_events] => [] [yii\base\Component:_eventWildcards] => [] [yii\base\Component:_behaviors] => null ) ) [yii\authclient\BaseClient:_requestOptions] => [] [yii\authclient\BaseClient:_stateStorage] => yii\authclient\SessionStateStorage#6 ( [yii\base\Component:_events] => [] [yii\base\Component:_eventWildcards] => [] [yii\base\Component:_behaviors] => null [session] => yii\web\Session#7 ( [yii\base\Component:_events] => [] [yii\base\Component:_eventWildcards] => [] [yii\base\Component:_behaviors] => null [flashParam] => '__flash' [handler] => null [*:_forceRegenerateId] => null [yii\web\Session:_cookieParams] => [ 'httponly' => true ] [yii\web\Session:frozenSessionData] => null [yii\web\Session:_hasSessionId] => true ) ) [version] => '2.0' [apiBaseUrl] => 'http://10.60.36.60:8080/apis/oauth2/v1' [authUrl] => 'http://10.60.36.60:8080/authorize' [scope] => null [autoRefreshAccessToken] => true [parametersToKeepInReturnUrl] => [ 0 => 'authclient' ] [yii\authclient\BaseOAuth:_returnUrl] => 'http://10.60.36.60:8081/auth?authclient=myauth' [yii\authclient\BaseOAuth:_accessToken] => yii\authclient\OAuthToken#8 ( [tokenParamKey] => 'access_token' [tokenSecretParamKey] => 'oauth_token_secret' [createTimestamp] => 1670846067 [yii\authclient\OAuthToken:_expireDurationParamKey] => null [yii\authclient\OAuthToken:_params] => [ 'access_token' => '358d8f2831a027f9e815a5b44f569678445a9429' 'expires_in' => 86400 'token_type' => 'Bearer' 'scope' => null 'refresh_token' => 'da3f5c8c33cd694479ee4a4fb51ccdd7943cf478' ] ) [yii\authclient\BaseOAuth:_signatureMethod] => [] [clientId] => 'testclient' [clientSecret] => 'testpass' [tokenUrl] => 'http://10.60.36.60:8080/oauth2/token' [validateAuthState] => true [enablePkce] => false )
Maybe we need, how to implement the OpenID ?
I have 2 apps:
Everything is looked good in every step at Yii2 server side:
But the problem is, when client side successfully login, why userAttributes is null ? In Yii2 client side, I set the SiteController like this:
Then, in AuthHandler:
Here is the config that I used in Yii2 client side:
And, Here is the info: