• Как правильно (и в какой момент авторизации) задать параметризованные scope в ЕСИА?

    @Sinator
    ChillyWilly007, мы не нашли признаков.
    В ЕСИА при авторизации под пользователем не предлагается выбор под кем это делается, перед тем как перекинуть обратно на бэк урл.
  • Как правильно (и в какой момент авторизации) задать параметризованные scope в ЕСИА?

    @Sinator
    ChillyWilly007, забыл сначала тебя упомянуть в ответе, так что дублирую, вдруг не получил уведомления.
  • Как правильно (и в какой момент авторизации) задать параметризованные scope в ЕСИА?

    @Sinator
    ChillyWilly007, мы получаем сначала список возможных вариантов, которые привязаны к пользователю, а затем выводим их в нашем интерфейсе для выбора под кем он хочет войти - физ лицо или одним из юриков.
    Даже интерфейс сделали напоминающий ЕСИА.

    5f48d65abbfb2830809828.png

    /*
                 * В GET есть state, значит это бэк урл из ЕСИА после авторизации... обрабатываем
                 */
                elseif($_GET['state']) {
                    $arResult = [
                        'TYPE'  => 'ESIA',
                        'ERROR' => false,
                    ];
    
    
                    try {
                        // Проверяем state запроса и ответа
                        if(!$_GET['state'] == $_SESSION['oauth2.esia.state'])
                            throw new Exception('Идентификатор запроса авторизации недействителен');
    
    
                        /*
                         * Обмениваем code на токен и получаем данные
                         */
                        # Токен
                        $sAccessToken   = $this->getEsiaUserTokenByCode($_GET['code'], $_GET['state']);
    
    
                        # Запрашиваем данные по пользователю в ЕСИА
                        $arEsiaUserData = $this->getEsiaUserData($sAccessToken);
    
    
    
    
                        // Проверяем
                        if($arEsiaUserData['citizenship'] != 'RUS')
                            throw new Exception('Только граждане РФ могут авторизоваться через ЕСИА');
                        if(!$arEsiaUserData['trusted'])
                            throw new Exception('Ваша учетная запись в ЕСИА не подтверждена, подтвердите учетную запись и попробуйте еще раз');
                        if(!$arEsiaUserData['inn'])
                            throw new Exception('Для использования сервиса в ЕСИА должна быть указана информация о ИНН');
    
    
    
                        # Собираем контакты
                        $arContacts = [];
                        foreach($arEsiaUserData['contacts']['elements'] AS $arRow) {
                            if($arRow['vrfStu'] != 'VERIFIED')
                                continue;
    
                            $sType = '';
                            switch($arRow['type']) {
                                case 'EML': $sType = 'EMAIL'; break;
                                case 'MBT': $sType = 'PERSONAL_MOBILE'; break;
                                case 'PHN': $sType = 'PERSONAL_PHONE'; break;
                            }
    
                            if(!$sType)
                                continue;
    
                            $arContacts[$sType] = $arRow['value'];
                        }
                        // Проверяем Email
                        if(!$arContacts['EMAIL'])
                            throw new Exception('Для авторизации в сервисе необходимо указать в ЕСИА информацию о Email адресе');
    
    
    
                        # Собираем адреса
                        $arAddresses = [];
                        foreach($arEsiaUserData['addresses']['elements'] AS $arRow) {
    
                            $sType = '';
                            switch($arRow['type']) {
                                case 'PRG': $sType = 'ADDR_REG'; break;
                                case 'PLV': $sType = 'ADDR_ACTUAL'; break;
                            }
    
                            if(!$sType)
                                continue;
    
                            $arAddresses[$sType] = join(', ', array_diff([
                                $arRow['zipCode'],
                                $arRow['addressStr'],
                                $arRow['house']? "д. {$arRow['house']}":'',
                                $arRow['frame']? "корп. {$arRow['frame']}":'',
                                $arRow['building']? "стр. {$arRow['building']}":'',
                                $arRow['flat'] ? "кв. {$arRow['flat']}":'',
                            ], ['']));
                        }
    
    
                        # Собираем паспорт
                        $arPassport = [];
                        foreach($arEsiaUserData['documents']['elements'] AS $arDoc) {
                            if($arDoc['vrfStu'] != 'VERIFIED' || $arDoc['type'] != 'RF_PASSPORT')
                                continue;
    
                            $arPassport = [
                                'SERIES'     => $arDoc['series'],
                                'NUMBER'     => $arDoc['number'],
                                'ISSUE_DATE' => $arDoc['issueDate'],
                                'ISSUE_CODE' => $arDoc['issueId'],
                                'ISSUE_NAME' => $arDoc['issuedBy'],
                            ];
                            break;
                        }
                        // Проверяем паспорт
                        if(!$arPassport)
                            throw new Exception('Для использования сервиса в ЕСИА должна быть указана информация о паспорте');
    
    
                        # Получаем данные по организациям
                        $arOrgsId = [];
                        // Формируем список OID
                        foreach($arEsiaUserData['organizations']['elements'] AS $arOrg) {
                            $arOrgsId[] = $arOrg['oid'];
                        }
                        // Запрашиваем данные
                        $arEsiaUserOrgData = $this->getEsiaUserOrganizations(
                            [
                                'code' =>  $_GET['code'],
                                'state' => $_GET['state'],
                            ],
                            $arOrgsId
                        );
    
                        // Дополняем массив пользователя
                        $arEsiaUserData['CONTACTS_DATA']  = $arContacts;
                        $arEsiaUserData['ADDRESSES_DATA'] = $arAddresses;
                        $arEsiaUserData['PASSPORT_DATA']  = $arPassport;
    
                        // Сохраняем информацию в сессию для обработки при авторизации/регистрации
                        $_SESSION['ESIA'] = [
                            'TOKEN' => $sAccessToken,
                            'USER'  => $arEsiaUserData,
                            'ORGS'  => $arEsiaUserOrgData,
                        ];
    
    
                        // Редиректим на страницу с выбором учетной записи
                        $sUrl = $this->makeUrl('esia', $this->arUrlTemplates['esia']);
                        $sUrl .= (strpos($sUrl, '?') !== false?'&':'?').'choice=Y';
                        LocalRedirect($sUrl);
    
    
                    } catch (Exception $e) {
                        $arResult['ERROR'] = $e->getMessage();
                    }


    Ну и сам код по организациям:
    public function getEsiaUserOrganizations($arAccess, $arOrgsId, $arScope = null) {
            $arScope = $arScope && is_array($arScope)? $arScope : $this->arDefaultOrgScopes;
    
            if(!$arOrgsId || !is_array($arOrgsId))
                return [];
    
            # Если нет токена, то получаем его по code и state
            if(!$arAccess['access_token']) {
                if(!$arAccess['code'] || !$arAccess['state'])
                    throw new Exception('Не переданы данные для получения токена доступа к организациям');
    
                $arTokenScopes = [];
                foreach($arOrgsId AS $iId) {
                    foreach($arScope AS $sScope)
                        $arTokenScopes[] = "http://esia.gosuslugi.ru/{$sScope}?org_oid={$iId}";
                }
    
                $arAccess['access_token'] = $this->getEsiaCredentialsTokenByCode($arAccess['code'], $arAccess['state'], $arTokenScopes);
            }
    
    
            # Получаем данные по орг.
            $arOrganization = [];
            foreach($arOrgsId AS $iId) {
                // Выполняем запрос
                $obHttpClient = new Bitrix\Main\Web\HttpClient();
                $obHttpClient->setHeader('Content-Type', 'application/json', true);
                $obHttpClient->setHeader('User-Agent', 'PHP-HttpClient', true);
                $obHttpClient->setHeader('Authorization', "Bearer {$arAccess['access_token']}", true);
                $mResponse = $obHttpClient->get($this->getEsiaDomain() . "/rs/orgs/{$iId}");
                $arResponse = json_decode($mResponse, true);
    
                // Проверяем
                if($obHttpClient->getStatus() != 200 || !$arResponse) {
                    $arOrganization[$iId] = ['code' => 'SYS-000000', 'message' => 'Request.incorrectResponseFormat'];
                    continue;
                }
    
                // TODO - при необходимости получения доп инфы можно тут сделать доп подзапрос или использовать embed режим
    
                unset($arResponse['stateFacts']);
                $arOrganization[$iId] = $arResponse;
            }
    
    
            return $arOrganization;
        }


    Запрашиваемые нами скоупы:
    /**
         * @var array Массив со списком scope запрашиваемых у пользователя
         */
        protected $arDefaultUserScopes = [
            'fullname',
            'birthdate',
            'snils',
            'inn',
            'id_doc',
            'email',
            'mobile',
            'usr_org',
            'contacts',
        ];
    
        /**
         * @var array Массив со списком scope запрашиваемых по организации
         */
        protected $arDefaultOrgScopes = [
            'org_shortname',
            'org_fullname',
            'org_type',
            'org_inn',
            'org_ogrn',
            'org_leg',
            'org_agencyterrange',
            'org_agencytype',
            'org_ctts',
        ];