Мы внедряли Sign In With Apple на сайте, здесь инструкция для PHP для внедрения кнопки Sign In Witn Apple на сайт в фреймворке Yii 2
yiisoft/yii2-authclient - поддержка OAuth 2 в Yii 2
firebase/php-jwt - Apple использует JWT токены
| <?php | |
| namespace frontend\auth; | |
| use Firebase\JWT\JWK; | |
| use Firebase\JWT\JWT; | |
| use Yii; | |
| use yii\authclient\OAuth2; | |
| class AppleAuthClient extends OAuth2 | |
| { | |
| public $authUrl = 'https://appleid.apple.com/auth/authorize'; | |
| public $tokenUrl = 'https://appleid.apple.com/auth/token'; | |
| public $keysUrl = 'https://appleid.apple.com/auth/keys'; | |
| public $teamId; | |
| public $keyId; | |
| public $keyFile; | |
| public function buildAuthUrl(array $params = []) | |
| { | |
| $params = array_merge($params, [ | |
| 'response_mode' => 'form_post', | |
| ]); | |
| return parent::buildAuthUrl($params); | |
| } | |
| public function fetchAccessToken($authCode, array $params = []) | |
| { | |
| //Генерируем clientSecret | |
| $payload = [ | |
| 'iat' => time(), | |
| 'exp' => time() + 3600, | |
| 'iss' => $this->teamId, | |
| 'aud' => 'https://appleid.apple.com', | |
| 'sub' => $this->clientId, | |
| ]; | |
| $key = file_get_contents($this->keyFile); | |
| $this->clientSecret = JWT::encode($payload, $key, 'ES256', $this->keyId); | |
| //Получаем токен | |
| return parent::fetchAccessToken($authCode, $params); | |
| } | |
| protected function initUserAttributes() | |
| { | |
| //Запрашиваем Public keys от Apple, чтобы валидировать токен | |
| $request = $this->createRequest() | |
| ->setUrl($this->keysUrl); | |
| $response = $this->sendRequest($request); | |
| $publicKeys = JWK::parseKeySet($response); | |
| //Получаем пользовательские данные из закодированного JWT токена | |
| $userData = JWT::decode($this->getAccessToken()->params['id_token'], $publicKeys, ['RS256']); | |
| $userData = (array)$userData; | |
| //Если в POST тоже были данные пользователя, то добавляем их к текущим данным. | |
| if (Yii::$app->request->post('user')) { | |
| $user = json_decode(Yii::$app->request->post('user'), true); | |
| if (!empty($user['name']['firstName'])) { | |
| $userData['first_name'] = $user['name']['firstName']; | |
| } | |
| if (!empty($user['name']['lastName'])) { | |
| $userData['last_name'] = $user['name']['lastName']; | |
| } | |
| if (!empty($user['email'])) { | |
| $userData['post_email'] = $user['email']; | |
| } | |
| } | |
| return $userData; | |
| } | |
| } |
| return [ | |
| 'components' => [ | |
| 'authClientCollection' => [ | |
| 'class' => 'yii\authclient\Collection', | |
| 'clients' => [ | |
| 'apple' => [ | |
| 'class' => \frontend\auth\AppleAuthClient::class, //см файл ниже | |
| //client_id и т.д. создается на сайте Apple Developers, лучше обратиться к разработчику под IOS, чтобы он создал | |
| //можно посмотреть кучу инструкций как это делается в интернете или ютубе по запросу Sign In With Apple service id, | |
| //sign in with apple ceate application, sign in with apple step by step и т.д. | |
| // https://www.youtube.com/watch?v=UafqYgRoIC0&ab_channel=Fireship | |
| 'clientId' => 'ваш client_id, сайт Apple Developers', | |
| 'teamId' => 'ваш team_id, сайт Apple Developers', | |
| 'keyId' => 'ваш key_id, сайт Apple Developers', | |
| 'keyFile' => Yii::getAlias('@common/files/AuthKeyFile_KeyId.p8'), //сюда положить файл ключа с сайта Apple Developers | |
| //returnUrl обрабатывается классом yii\authclient\AuthAction | |
| 'returnUrl' => 'ваш return_url', //https://example.com/auth/auth?authclient=apple, | |
| // должны попасть на AuthController->authAction | |
| 'validateAuthState' => false, | |
| 'scope' => 'name email', | |
| ], | |
| ], | |
| ], | |
| ], | |
| ] |
| namespace frontend\controllers; | |
| use \yii\authclient\AuthAction; | |
| use yii\authclient\ClientInterface; | |
| class AuthController { | |
| public function actions() | |
| { | |
| return [ | |
| //сюда обращается пользователь когда хочет авторизоваться, т.е. у вас есть кнопка Sign In With Apple на сайте и сюда ведет | |
| //ссылка с этой кнопки. | |
| //ответ данного экшена - редирект на страницу Apple | |
| //https://example.com/auth/authLink?authclient=apple | |
| 'auth-link' => [ | |
| 'class' => AuthAction::class, | |
| ], | |
| //returnUrl из конфига. Сюда Apple переадресует пользователя после авторизации | |
| //Будет POST запрос, и параметры формы будут такими: | |
| //code=123123 - уникальный код, по которому можно достать данные пользователя | |
| //user = {"name":{"firstName":"Имя","lastName":"Фамилия"},"email":"email@email.com"} | |
| //user передается только 1 раз при первой авторизации! в дальнейшем будет только code. По code можно достать email, но не | |
| //имя и фамилию | |
| 'auth' => [ | |
| 'class' => AuthAction::class, | |
| 'successCallback' => [$this, 'onAuthSuccess'], | |
| ], | |
| ]; | |
| } | |
| public function onAuthSuccess(ClientInterface $client) | |
| { | |
| $network = $client->getId(); //$network = "apple" | |
| $attributes = $client->getUserAttributes(); //данные пользователя из apple | |
| /* | |
| Вообще-то $attributes - это массив, но я покажу на примере json. | |
| { | |
| "aud": "service_id", | |
| "exp": 1629380175, | |
| "iat": 1629293775, | |
| "iss": "https://appleid.apple.com", | |
| "sub": "1234.asdf.1234", //уникальный ID пользователя в Apple. Лучше varchar(255), т.к. он около 50 символов. Не меняется. | |
| "email": "email@email.com", //email может сменится! | |
| "at_hash": "asdfasdf", | |
| "auth_time": 1629293766, | |
| "email_verified": "true", | |
| "nonce_supported": true, | |
| "first_name": "Имя", | |
| "last_name": "Фамилия", | |
| "post_email": "опять email" | |
| } | |
| */ | |
| //здесь по данным пользователя найти пользователя в базе данных и авторизовать его и вернуть ответ фронтенду | |
| } | |
| } |