Rumah >pembangunan bahagian belakang >tutorial php >Pengesahan Pengguna di Symfony2 dengan UserApp.io
Dalam artikel ini, kita akan melihat bagaimana kita boleh melaksanakan mekanisme pengesahan Symfony2 yang memanfaatkan UserApp.io. Kod yang kami tulis juga boleh didapati di perpustakaan kecil ini yang saya buat (kini dalam dev) yang anda boleh cuba. Untuk memasangnya dalam aplikasi Symfony anda, ikuti arahan pada GitHub.
Takeaways Key
Untuk mengesahkan pengguna userapp.io dengan aplikasi Symfony kami, kami akan membuat beberapa kelas:
Apabila kita membuat kelas ini, kita akan mengisytiharkan sebahagian daripada mereka sebagai perkhidmatan dan menggunakannya dalam sistem keselamatan Symfony.
Pertama, kami akan mencipta kelas yang paling penting, Pengesahan Borang (di dalam keselamatan/ folder amalan terbaik kami bernama AppBundle). Inilah kodnya, saya akan menerangkannya selepas itu:
<span><span><?php </span></span><span> </span><span><span>/** </span></span><span><span> * <span>@file AppBundle\Security\UserAppAuthenticator.php </span></span></span><span><span> */ </span></span><span> </span><span><span>namespace AppBundle<span>\Security</span>; </span></span><span> </span><span><span>use Symfony<span>\Component\HttpFoundation\Request</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\Authentication\SimpleFormAuthenticatorInterface</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\Authentication\Token\TokenInterface</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\Exception\AuthenticationException</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\User\UserProviderInterface</span>; </span></span><span><span>use UserApp<span>\API</span> as UserApp; </span></span><span><span>use UserApp<span>\Exceptions\ServiceException</span>; </span></span><span> </span><span><span>class UserAppAuthenticator implements SimpleFormAuthenticatorInterface </span></span><span><span>{ </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>@var UserApp </span></span></span><span><span> */ </span></span><span> <span>private $userAppClient; </span></span><span> </span><span> <span>public function __construct(UserApp $userAppClient) { </span></span><span> <span>$this->userAppClient = $userAppClient; </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>{@inheritdoc} </span></span></span><span><span> */ </span></span><span> <span>public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey) </span></span><span> <span>{ </span></span><span> </span><span> <span>try { </span></span><span> <span>$login = $this->userAppClient->user->login(array( </span></span><span> <span>"login" => $token->getUsername(), </span></span><span> <span>"password" => $token->getCredentials(), </span></span><span> <span>) </span></span><span> <span>); </span></span><span> </span><span> <span>// Load user from provider based on id </span></span><span> <span>$user = $userProvider->loadUserByLoginInfo($login); </span></span><span> <span>} catch(ServiceException $exception) { </span></span><span> <span>if ($exception->getErrorCode() == 'INVALID_ARGUMENT_LOGIN' || $exception->getErrorCode() == 'INVALID_ARGUMENT_PASSWORD') { </span></span><span> <span>throw new AuthenticationException('Invalid username or password'); </span></span><span> <span>} </span></span><span> <span>if ($exception->getErrorCode() == 'INVALID_ARGUMENT_APP_ID') { </span></span><span> <span>throw new AuthenticationException('Invalid app ID'); </span></span><span> <span>} </span></span><span> <span>} </span></span><span> <span>return new UserAppToken( </span></span><span> <span>$user, </span></span><span> <span>$user->getToken(), </span></span><span> <span>$providerKey, </span></span><span> <span>$user->getRoles() </span></span><span> <span>); </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>{@inheritdoc} </span></span></span><span><span> */ </span></span><span> <span>public function supportsToken(TokenInterface $token, $providerKey) </span></span><span> <span>{ </span></span><span> <span>return $token instanceof UserAppToken </span></span><span> <span>&& $token->getProviderKey() === $providerKey; </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>{@inheritdoc} </span></span></span><span><span> */ </span></span><span> <span>public function createToken(Request $request, $username, $password, $providerKey) </span></span><span> <span>{ </span></span><span> <span>return new UserAppToken($username, $password, $providerKey); </span></span><span> <span>} </span></span><span><span>}</span></span>
seperti yang anda lihat, kami melaksanakan SimpleFormAuthenticatorInterface dan akibatnya mempunyai 3 kaedah dan pembina. Yang terakhir mengambil ketergantungan sebagai klien userapp.io instantiated (diluluskan menggunakan bekas perkhidmatan, tetapi lebih banyak lagi dalam satu minit).
Kelas ini digunakan oleh Symfony apabila pengguna cuba log masuk dan mengesahkan dengan aplikasi. Perkara pertama yang berlaku ialah CreateToken () dipanggil. Kaedah ini perlu mengembalikan token pengesahan yang menggabungkan nama pengguna dan kata laluan yang dikemukakan. Dalam kes kami, ia akan menjadi contoh kelas UserApptoken yang akan kami tentukan dalam seketika.
maka kaedah SupportToken () dipanggil untuk memeriksa sama ada kelas ini menyokong token yang dikembalikan oleh CreateToken (). Di sini kami hanya pastikan kami kembali benar untuk jenis token kami.
Akhirnya, authenticateToken () dipanggil dan cuba untuk memeriksa sama ada kelayakan dalam token adalah sah. Di sini, dan menggunakan Perpustakaan PHP UserApp.io, kami cuba log masuk atau membuang pengecualian pengesahan Symfony jika ini gagal. Sekiranya pengesahan berjaya, pembekal pengguna yang bertanggungjawab digunakan untuk membina objek pengguna kami, sebelum membuat dan mengembalikan objek token lain berdasarkan yang terakhir.
kami akan menulis pembekal pengguna kami selepas kami dengan cepat membuat kelas UserApptoken yang mudah.
<span><span><?php </span></span><span> </span><span><span>/** </span></span><span><span> * <span>@file AppBundle\Security\UserAppToken.php </span></span></span><span><span> */ </span></span><span> </span><span><span>namespace AppBundle<span>\Security</span>; </span></span><span> </span><span><span>use Symfony<span>\Component\Security\Core\Authentication\Token\UsernamePasswordToken</span>; </span></span><span> </span><span><span>class UserAppToken extends UsernamePasswordToken { </span></span><span> </span><span><span>}</span></span>
seperti yang anda lihat, ini hanyalah lanjutan kelas usernamepasswordtoken demi penamaan yang lebih tepat (kerana kami menyimpan token dan bukan kata laluan).
Penyedia Pengguna
<span><span><?php </span></span><span> </span><span><span>/** </span></span><span><span> * <span>@file AppBundle\Security\UserAppProvider.php </span></span></span><span><span> */ </span></span><span> </span><span><span>namespace AppBundle<span>\Security</span>; </span></span><span> </span><span><span>use Symfony<span>\Component\Security\Core\Exception\AuthenticationException</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\Exception\UsernameNotFoundException</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\User\UserProviderInterface</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\User\UserInterface</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\Exception\UnsupportedUserException</span>; </span></span><span><span>use UserApp<span>\API</span> as UserApp; </span></span><span><span>use UserApp<span>\Exceptions\ServiceException</span>; </span></span><span><span>use AppBundle<span>\Security\Exception\NoUserRoleException</span>; </span></span><span><span>use AppBundle<span>\Security\UserAppUser</span>; </span></span><span> </span><span><span>class UserAppProvider implements UserProviderInterface </span></span><span><span>{ </span></span><span> <span>/** </span></span><span><span> * <span>@var UserApp </span></span></span><span><span> */ </span></span><span> <span>private $userAppClient; </span></span><span> </span><span> <span>public function __construct(UserApp $userAppClient) { </span></span><span> <span>$this->userAppClient = $userAppClient; </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>{@inheritdoc} </span></span></span><span><span> */ </span></span><span> <span>public function loadUserByUsername($username) </span></span><span> <span>{ </span></span><span> <span>// Empty for now </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>{@inheritdoc} </span></span></span><span><span> */ </span></span><span> <span>public function refreshUser(UserInterface $user) </span></span><span> <span>{ </span></span><span> <span>if (!$user instanceof UserAppUser) { </span></span><span> <span>throw new UnsupportedUserException( </span></span><span> <span>sprintf('Instances of "%s" are not supported.', get_class($user)) </span></span><span> <span>); </span></span><span> <span>} </span></span><span> </span><span> <span>try { </span></span><span> <span>$api = $this->userAppClient; </span></span><span> <span>$api->setOption('token', $user->getToken()); </span></span><span> <span>$api->token->heartbeat(); </span></span><span> <span>$user->unlock(); </span></span><span> <span>} </span></span><span> <span>catch (ServiceException $exception) { </span></span><span> <span>if ($exception->getErrorCode() == 'INVALID_CREDENTIALS') { </span></span><span> <span>throw new AuthenticationException('Invalid credentials'); </span></span><span> <span>} </span></span><span> <span>if ($exception->getErrorCode() == 'AUTHORIZATION_USER_LOCKED') { </span></span><span> <span>$user->lock(); </span></span><span> <span>} </span></span><span> <span>} </span></span><span> </span><span> <span>return $user; </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>{@inheritdoc} </span></span></span><span><span> */ </span></span><span> <span>public function supportsClass($class) </span></span><span> <span>{ </span></span><span> <span>return $class === 'AppBundle\Security\UserAppUser'; </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * </span></span><span><span> * Loads a user from UserApp.io based on a successful login response. </span></span><span><span> * </span></span><span><span> * <span>@param $login </span></span></span><span><span> * <span>@return UserAppUser </span></span></span><span><span> * <span>@throws NoUserRoleException </span></span></span><span><span> */ </span></span><span> <span>public function loadUserByLoginInfo($login) { </span></span><span> </span><span> <span>try { </span></span><span> <span>$api = $this->userAppClient; </span></span><span> <span>$api->setOption('token', $login->token); </span></span><span> <span>$users = $api->user->get(); </span></span><span> <span>} catch(ServiceException $exception) { </span></span><span> <span>if ($exception->getErrorCode() == 'INVALID_ARGUMENT_USER_ID') { </span></span><span> <span>throw new UsernameNotFoundException(sprintf('User with the id "%s" not found.', $login->user_id)); </span></span><span> <span>} </span></span><span> <span>} </span></span><span> </span><span> <span>if (!empty($users)) { </span></span><span> <span>return $this->userFromUserApp($users[0], $login->token); </span></span><span> <span>} </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * Creates a UserAppUser from a user response from UserApp.io </span></span><span><span> * </span></span><span><span> * <span>@param $user </span></span></span><span><span> * <span>@param $token </span></span></span><span><span> * <span>@return UserAppUser </span></span></span><span><span> * <span>@throws NoUserRoleException </span></span></span><span><span> */ </span></span><span> <span>private function userFromUserApp($user, $token) { </span></span><span> </span><span> <span>$roles = $this->extractRolesFromPermissions($user); </span></span><span> </span><span> <span>$options = array( </span></span><span> <span>'id' => $user->user_id, </span></span><span> <span>'username' => $user->login, </span></span><span> <span>'token' => $token, </span></span><span> <span>'firstName' => $user->first_name, </span></span><span> <span>'lastName' => $user->last_name, </span></span><span> <span>'email' => $user->email, </span></span><span> <span>'roles' => $roles, </span></span><span> <span>'properties' => $user->properties, </span></span><span> <span>'features' => $user->features, </span></span><span> <span>'permissions' => $user->permissions, </span></span><span> <span>'created' => $user->created_at, </span></span><span> <span>'locked' => !empty($user->locks), </span></span><span> <span>'last_logged_in' => $user->last_login_at, </span></span><span> <span>'last_heartbeat' => time(), </span></span><span> <span>); </span></span><span> </span><span> <span>return new UserAppUser($options); </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * Extracts the roles from the permissions list of a user </span></span><span><span> * </span></span><span><span> * <span>@param $user </span></span></span><span><span> * <span>@return <span>array</span> </span></span></span><span><span> * <span>@throws NoUserRoleException </span></span></span><span><span> */ </span></span><span> <span>private function extractRolesFromPermissions($user) { </span></span><span> <span>$permissions = get_object_vars($user->permissions); </span></span><span> <span>if (empty($permissions)) { </span></span><span> <span>throw new NoUserRoleException('There are no roles set up for your users.'); </span></span><span> <span>} </span></span><span> <span>$roles = array(); </span></span><span> <span>foreach ($permissions as $role => $permission) { </span></span><span> <span>if ($permission->value === TRUE) { </span></span><span> <span>$roles[] = $role; </span></span><span> <span>} </span></span><span> <span>} </span></span><span> </span><span> <span>if (empty($roles)) { </span></span><span> <span>throw new NoUserRoleException('This user has no roles enabled.'); </span></span><span> <span>} </span></span><span> </span><span> <span>return $roles; </span></span><span> <span>} </span></span><span><span>}</span></span>Sama seperti Kelas Pengesahan Borang, kami menyuntik pelanggan UserApp.io ke dalam kelas ini menggunakan suntikan ketergantungan dan kami melaksanakan UserProviderInterface. Yang terakhir memerlukan kita mempunyai 3 kaedah:
mari kita kembali ke kelas pengesahan kami dan lihat apa sebenarnya yang berlaku apabila pengesahan dengan userapp.io berjaya: kami memanggil kaedah loadUserByLogininfo () adat pada kelas penyedia pengguna yang mengambil objek hasil log masuk yang berjaya dari API dan Menggunakan token pengesahannya untuk meminta kembali dari API objek pengguna log masuk. Hasilnya dibungkus ke dalam kelas UserAppuser tempatan kami melalui kaedah penolong userFromUserApp () dan extractrolesFrompermissions (). Yang terakhir adalah pelaksanaan saya sendiri cara untuk menterjemahkan konsep keizinan dalam userApp.io menjadi peranan dalam Symfony. Dan kami membuang nouserroleException kami sendiri jika userapp.io tidak disediakan dengan kebenaran untuk pengguna. Oleh itu, pastikan pengguna anda di userapp.io mempunyai keizinan yang anda ingin memetakan peranan dalam Symfony.
Kelas pengecualian adalah pelanjutan mudah dari pengecualian php lalai:
<span><span><?php </span></span><span> </span><span><span>/** </span></span><span><span> * <span>@file AppBundle\Security\UserAppAuthenticator.php </span></span></span><span><span> */ </span></span><span> </span><span><span>namespace AppBundle<span>\Security</span>; </span></span><span> </span><span><span>use Symfony<span>\Component\HttpFoundation\Request</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\Authentication\SimpleFormAuthenticatorInterface</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\Authentication\Token\TokenInterface</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\Exception\AuthenticationException</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\User\UserProviderInterface</span>; </span></span><span><span>use UserApp<span>\API</span> as UserApp; </span></span><span><span>use UserApp<span>\Exceptions\ServiceException</span>; </span></span><span> </span><span><span>class UserAppAuthenticator implements SimpleFormAuthenticatorInterface </span></span><span><span>{ </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>@var UserApp </span></span></span><span><span> */ </span></span><span> <span>private $userAppClient; </span></span><span> </span><span> <span>public function __construct(UserApp $userAppClient) { </span></span><span> <span>$this->userAppClient = $userAppClient; </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>{@inheritdoc} </span></span></span><span><span> */ </span></span><span> <span>public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey) </span></span><span> <span>{ </span></span><span> </span><span> <span>try { </span></span><span> <span>$login = $this->userAppClient->user->login(array( </span></span><span> <span>"login" => $token->getUsername(), </span></span><span> <span>"password" => $token->getCredentials(), </span></span><span> <span>) </span></span><span> <span>); </span></span><span> </span><span> <span>// Load user from provider based on id </span></span><span> <span>$user = $userProvider->loadUserByLoginInfo($login); </span></span><span> <span>} catch(ServiceException $exception) { </span></span><span> <span>if ($exception->getErrorCode() == 'INVALID_ARGUMENT_LOGIN' || $exception->getErrorCode() == 'INVALID_ARGUMENT_PASSWORD') { </span></span><span> <span>throw new AuthenticationException('Invalid username or password'); </span></span><span> <span>} </span></span><span> <span>if ($exception->getErrorCode() == 'INVALID_ARGUMENT_APP_ID') { </span></span><span> <span>throw new AuthenticationException('Invalid app ID'); </span></span><span> <span>} </span></span><span> <span>} </span></span><span> <span>return new UserAppToken( </span></span><span> <span>$user, </span></span><span> <span>$user->getToken(), </span></span><span> <span>$providerKey, </span></span><span> <span>$user->getRoles() </span></span><span> <span>); </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>{@inheritdoc} </span></span></span><span><span> */ </span></span><span> <span>public function supportsToken(TokenInterface $token, $providerKey) </span></span><span> <span>{ </span></span><span> <span>return $token instanceof UserAppToken </span></span><span> <span>&& $token->getProviderKey() === $providerKey; </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>{@inheritdoc} </span></span></span><span><span> */ </span></span><span> <span>public function createToken(Request $request, $username, $password, $providerKey) </span></span><span> <span>{ </span></span><span> <span>return new UserAppToken($username, $password, $providerKey); </span></span><span> <span>} </span></span><span><span>}</span></span>
Kembali ke pengesahan kami sekali lagi, kami melihat bahawa jika pengesahan dengan UserApp.io berjaya, objek yang dikelaskan oleh UserAppuser dibina oleh penyedia pengguna yang mengandungi semua maklumat yang diperlukan pada pengguna. Mempunyai objek ini, kita perlu menambahkannya kepada contoh baru kelas UserAppToken dan mengembalikannya.
Jadi pada dasarnya ini berlaku dari saat pengguna cuba log masuk:
Kaedah penyegaran () pada pembekal pengguna juga sangat penting. Kaedah ini bertanggungjawab untuk mendapatkan contoh baru yang sedang dilog masuk dalam pengguna pada setiap halaman yang disahkan. Oleh itu, apabila pengguna yang disahkan pergi ke mana -mana halaman di dalam firewall, kaedah ini akan dicetuskan. Intinya adalah untuk menghidrat objek pengguna dengan sebarang perubahan dalam storan yang mungkin berlaku dalam masa yang sama.
Jelas sekali kita perlu menyimpan panggilan API minimum tetapi ini adalah peluang yang baik untuk meningkatkan masa pengesahan UserApp.io dengan menghantar permintaan jantung. Secara lalai (tetapi boleh dikonfigurasikan), setiap token pengguna yang disahkan sah selama 60 minit tetapi dengan menghantar permintaan denyutan jantung, ini akan dilanjutkan sebanyak 20 minit.
Ini adalah tempat yang bagus untuk melaksanakan juga dua fungsi lain:
Jika anda mahu, anda boleh membuat permintaan API dan mengemas kini objek pengguna dengan data dari userApp.io di sini juga tetapi saya mendapati ia tidak masuk akal untuk kebanyakan kes penggunaan. Data boleh dikemas kini apabila pengguna log keluar dan kembali pada masa akan datang. Tetapi bergantung kepada keperluan, ini boleh dilakukan dengan mudah di sini. Walaupun perlu diingat implikasi prestasi dan kos banyak panggilan API ke userapp.io.
dan pada dasarnya itu adalah logik pengesahan kami.
mari juga buat kelas userAppuser yang telah kita bicarakan sebelumnya:
<span><span><?php </span></span><span> </span><span><span>/** </span></span><span><span> * <span>@file AppBundle\Security\UserAppAuthenticator.php </span></span></span><span><span> */ </span></span><span> </span><span><span>namespace AppBundle<span>\Security</span>; </span></span><span> </span><span><span>use Symfony<span>\Component\HttpFoundation\Request</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\Authentication\SimpleFormAuthenticatorInterface</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\Authentication\Token\TokenInterface</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\Exception\AuthenticationException</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\User\UserProviderInterface</span>; </span></span><span><span>use UserApp<span>\API</span> as UserApp; </span></span><span><span>use UserApp<span>\Exceptions\ServiceException</span>; </span></span><span> </span><span><span>class UserAppAuthenticator implements SimpleFormAuthenticatorInterface </span></span><span><span>{ </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>@var UserApp </span></span></span><span><span> */ </span></span><span> <span>private $userAppClient; </span></span><span> </span><span> <span>public function __construct(UserApp $userAppClient) { </span></span><span> <span>$this->userAppClient = $userAppClient; </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>{@inheritdoc} </span></span></span><span><span> */ </span></span><span> <span>public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey) </span></span><span> <span>{ </span></span><span> </span><span> <span>try { </span></span><span> <span>$login = $this->userAppClient->user->login(array( </span></span><span> <span>"login" => $token->getUsername(), </span></span><span> <span>"password" => $token->getCredentials(), </span></span><span> <span>) </span></span><span> <span>); </span></span><span> </span><span> <span>// Load user from provider based on id </span></span><span> <span>$user = $userProvider->loadUserByLoginInfo($login); </span></span><span> <span>} catch(ServiceException $exception) { </span></span><span> <span>if ($exception->getErrorCode() == 'INVALID_ARGUMENT_LOGIN' || $exception->getErrorCode() == 'INVALID_ARGUMENT_PASSWORD') { </span></span><span> <span>throw new AuthenticationException('Invalid username or password'); </span></span><span> <span>} </span></span><span> <span>if ($exception->getErrorCode() == 'INVALID_ARGUMENT_APP_ID') { </span></span><span> <span>throw new AuthenticationException('Invalid app ID'); </span></span><span> <span>} </span></span><span> <span>} </span></span><span> <span>return new UserAppToken( </span></span><span> <span>$user, </span></span><span> <span>$user->getToken(), </span></span><span> <span>$providerKey, </span></span><span> <span>$user->getRoles() </span></span><span> <span>); </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>{@inheritdoc} </span></span></span><span><span> */ </span></span><span> <span>public function supportsToken(TokenInterface $token, $providerKey) </span></span><span> <span>{ </span></span><span> <span>return $token instanceof UserAppToken </span></span><span> <span>&& $token->getProviderKey() === $providerKey; </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>{@inheritdoc} </span></span></span><span><span> */ </span></span><span> <span>public function createToken(Request $request, $username, $password, $providerKey) </span></span><span> <span>{ </span></span><span> <span>return new UserAppToken($username, $password, $providerKey); </span></span><span> <span>} </span></span><span><span>}</span></span>
Tidak ada yang tertentu di sini, kami hanya memetakan beberapa data dari userApp.io dan melaksanakan beberapa kaedah yang diperlukan oleh antara muka. Di samping itu, kami menambah flagger terkunci/dikunci.
Kelas terakhir yang perlu kita buat adalah yang berkaitan dengan pembalakan pengguna keluar dari userApp.io apabila mereka keluar dari Symfony.
<span><span><?php </span></span><span> </span><span><span>/** </span></span><span><span> * <span>@file AppBundle\Security\UserAppToken.php </span></span></span><span><span> */ </span></span><span> </span><span><span>namespace AppBundle<span>\Security</span>; </span></span><span> </span><span><span>use Symfony<span>\Component\Security\Core\Authentication\Token\UsernamePasswordToken</span>; </span></span><span> </span><span><span>class UserAppToken extends UsernamePasswordToken { </span></span><span> </span><span><span>}</span></span>
di sini sekali lagi kami menyuntik pelanggan php userApp.io dan sejak kami melaksanakan logouthandlerInterface kami perlu mempunyai kaedah logout (). Apa yang kita lakukan di dalamnya adalah log pengguna keluar dari userapp.io jika mereka masih log masuk.
Sekarang kita mempunyai kelas kami, sudah tiba masanya untuk mengisytiharkan mereka sebagai perkhidmatan dan menggunakannya dalam sistem pengesahan kami. Berikut adalah pengisytiharan perkhidmatan berasaskan YML kami:
<span><span><?php </span></span><span> </span><span><span>/** </span></span><span><span> * <span>@file AppBundle\Security\UserAppProvider.php </span></span></span><span><span> */ </span></span><span> </span><span><span>namespace AppBundle<span>\Security</span>; </span></span><span> </span><span><span>use Symfony<span>\Component\Security\Core\Exception\AuthenticationException</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\Exception\UsernameNotFoundException</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\User\UserProviderInterface</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\User\UserInterface</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\Exception\UnsupportedUserException</span>; </span></span><span><span>use UserApp<span>\API</span> as UserApp; </span></span><span><span>use UserApp<span>\Exceptions\ServiceException</span>; </span></span><span><span>use AppBundle<span>\Security\Exception\NoUserRoleException</span>; </span></span><span><span>use AppBundle<span>\Security\UserAppUser</span>; </span></span><span> </span><span><span>class UserAppProvider implements UserProviderInterface </span></span><span><span>{ </span></span><span> <span>/** </span></span><span><span> * <span>@var UserApp </span></span></span><span><span> */ </span></span><span> <span>private $userAppClient; </span></span><span> </span><span> <span>public function __construct(UserApp $userAppClient) { </span></span><span> <span>$this->userAppClient = $userAppClient; </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>{@inheritdoc} </span></span></span><span><span> */ </span></span><span> <span>public function loadUserByUsername($username) </span></span><span> <span>{ </span></span><span> <span>// Empty for now </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>{@inheritdoc} </span></span></span><span><span> */ </span></span><span> <span>public function refreshUser(UserInterface $user) </span></span><span> <span>{ </span></span><span> <span>if (!$user instanceof UserAppUser) { </span></span><span> <span>throw new UnsupportedUserException( </span></span><span> <span>sprintf('Instances of "%s" are not supported.', get_class($user)) </span></span><span> <span>); </span></span><span> <span>} </span></span><span> </span><span> <span>try { </span></span><span> <span>$api = $this->userAppClient; </span></span><span> <span>$api->setOption('token', $user->getToken()); </span></span><span> <span>$api->token->heartbeat(); </span></span><span> <span>$user->unlock(); </span></span><span> <span>} </span></span><span> <span>catch (ServiceException $exception) { </span></span><span> <span>if ($exception->getErrorCode() == 'INVALID_CREDENTIALS') { </span></span><span> <span>throw new AuthenticationException('Invalid credentials'); </span></span><span> <span>} </span></span><span> <span>if ($exception->getErrorCode() == 'AUTHORIZATION_USER_LOCKED') { </span></span><span> <span>$user->lock(); </span></span><span> <span>} </span></span><span> <span>} </span></span><span> </span><span> <span>return $user; </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>{@inheritdoc} </span></span></span><span><span> */ </span></span><span> <span>public function supportsClass($class) </span></span><span> <span>{ </span></span><span> <span>return $class === 'AppBundle\Security\UserAppUser'; </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * </span></span><span><span> * Loads a user from UserApp.io based on a successful login response. </span></span><span><span> * </span></span><span><span> * <span>@param $login </span></span></span><span><span> * <span>@return UserAppUser </span></span></span><span><span> * <span>@throws NoUserRoleException </span></span></span><span><span> */ </span></span><span> <span>public function loadUserByLoginInfo($login) { </span></span><span> </span><span> <span>try { </span></span><span> <span>$api = $this->userAppClient; </span></span><span> <span>$api->setOption('token', $login->token); </span></span><span> <span>$users = $api->user->get(); </span></span><span> <span>} catch(ServiceException $exception) { </span></span><span> <span>if ($exception->getErrorCode() == 'INVALID_ARGUMENT_USER_ID') { </span></span><span> <span>throw new UsernameNotFoundException(sprintf('User with the id "%s" not found.', $login->user_id)); </span></span><span> <span>} </span></span><span> <span>} </span></span><span> </span><span> <span>if (!empty($users)) { </span></span><span> <span>return $this->userFromUserApp($users[0], $login->token); </span></span><span> <span>} </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * Creates a UserAppUser from a user response from UserApp.io </span></span><span><span> * </span></span><span><span> * <span>@param $user </span></span></span><span><span> * <span>@param $token </span></span></span><span><span> * <span>@return UserAppUser </span></span></span><span><span> * <span>@throws NoUserRoleException </span></span></span><span><span> */ </span></span><span> <span>private function userFromUserApp($user, $token) { </span></span><span> </span><span> <span>$roles = $this->extractRolesFromPermissions($user); </span></span><span> </span><span> <span>$options = array( </span></span><span> <span>'id' => $user->user_id, </span></span><span> <span>'username' => $user->login, </span></span><span> <span>'token' => $token, </span></span><span> <span>'firstName' => $user->first_name, </span></span><span> <span>'lastName' => $user->last_name, </span></span><span> <span>'email' => $user->email, </span></span><span> <span>'roles' => $roles, </span></span><span> <span>'properties' => $user->properties, </span></span><span> <span>'features' => $user->features, </span></span><span> <span>'permissions' => $user->permissions, </span></span><span> <span>'created' => $user->created_at, </span></span><span> <span>'locked' => !empty($user->locks), </span></span><span> <span>'last_logged_in' => $user->last_login_at, </span></span><span> <span>'last_heartbeat' => time(), </span></span><span> <span>); </span></span><span> </span><span> <span>return new UserAppUser($options); </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * Extracts the roles from the permissions list of a user </span></span><span><span> * </span></span><span><span> * <span>@param $user </span></span></span><span><span> * <span>@return <span>array</span> </span></span></span><span><span> * <span>@throws NoUserRoleException </span></span></span><span><span> */ </span></span><span> <span>private function extractRolesFromPermissions($user) { </span></span><span> <span>$permissions = get_object_vars($user->permissions); </span></span><span> <span>if (empty($permissions)) { </span></span><span> <span>throw new NoUserRoleException('There are no roles set up for your users.'); </span></span><span> <span>} </span></span><span> <span>$roles = array(); </span></span><span> <span>foreach ($permissions as $role => $permission) { </span></span><span> <span>if ($permission->value === TRUE) { </span></span><span> <span>$roles[] = $role; </span></span><span> <span>} </span></span><span> <span>} </span></span><span> </span><span> <span>if (empty($roles)) { </span></span><span> <span>throw new NoUserRoleException('This user has no roles enabled.'); </span></span><span> <span>} </span></span><span> </span><span> <span>return $roles; </span></span><span> <span>} </span></span><span><span>}</span></span>
Yang pertama adalah perpustakaan php userApp.io yang kami lalui dalam ID aplikasi kami dalam bentuk rujukan kepada parameter. Anda perlu mempunyai parameter yang dipanggil UserApp_ID dengan userapp.io aplikasi ID anda.
Tiga yang lain adalah pengganti bentuk, pembekal pengguna dan kelas logout yang kami tulis sebelum ini. Dan seperti yang anda ingat, masing -masing menerima satu parameter dalam pembina mereka dalam bentuk pelanggan UserApp.io yang ditakrifkan sebagai perkhidmatan pertama.
Seterusnya, sudah tiba masanya untuk menggunakan perkhidmatan ini dalam sistem keselamatan kami, jadi edit fail keselamatan.yml dan lakukan yang berikut:
Di bawah kekunci Pembekal, tambahkan yang berikut:
<span><span><?php </span></span><span> </span><span><span>/** </span></span><span><span> * <span>@file AppBundle\Security\Exception\NoUserRoleException.php </span></span></span><span><span> */ </span></span><span> </span><span><span>namespace AppBundle<span>\Security\Exception</span>; </span></span><span> </span><span><span>class NoUserRoleException extends <span>\Exception</span> { </span></span><span> </span><span><span>}</span></span>
di sini kami menyatakan bahawa aplikasi kami juga mempunyai pembekal pengguna ini supaya dapat menggunakannya.
<span><span><?php </span></span><span> </span><span><span>/** </span></span><span><span> * <span>@file AppBundle\Security\UserAppAuthenticator.php </span></span></span><span><span> */ </span></span><span> </span><span><span>namespace AppBundle<span>\Security</span>; </span></span><span> </span><span><span>use Symfony<span>\Component\HttpFoundation\Request</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\Authentication\SimpleFormAuthenticatorInterface</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\Authentication\Token\TokenInterface</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\Exception\AuthenticationException</span>; </span></span><span><span>use Symfony<span>\Component\Security\Core\User\UserProviderInterface</span>; </span></span><span><span>use UserApp<span>\API</span> as UserApp; </span></span><span><span>use UserApp<span>\Exceptions\ServiceException</span>; </span></span><span> </span><span><span>class UserAppAuthenticator implements SimpleFormAuthenticatorInterface </span></span><span><span>{ </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>@var UserApp </span></span></span><span><span> */ </span></span><span> <span>private $userAppClient; </span></span><span> </span><span> <span>public function __construct(UserApp $userAppClient) { </span></span><span> <span>$this->userAppClient = $userAppClient; </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>{@inheritdoc} </span></span></span><span><span> */ </span></span><span> <span>public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey) </span></span><span> <span>{ </span></span><span> </span><span> <span>try { </span></span><span> <span>$login = $this->userAppClient->user->login(array( </span></span><span> <span>"login" => $token->getUsername(), </span></span><span> <span>"password" => $token->getCredentials(), </span></span><span> <span>) </span></span><span> <span>); </span></span><span> </span><span> <span>// Load user from provider based on id </span></span><span> <span>$user = $userProvider->loadUserByLoginInfo($login); </span></span><span> <span>} catch(ServiceException $exception) { </span></span><span> <span>if ($exception->getErrorCode() == 'INVALID_ARGUMENT_LOGIN' || $exception->getErrorCode() == 'INVALID_ARGUMENT_PASSWORD') { </span></span><span> <span>throw new AuthenticationException('Invalid username or password'); </span></span><span> <span>} </span></span><span> <span>if ($exception->getErrorCode() == 'INVALID_ARGUMENT_APP_ID') { </span></span><span> <span>throw new AuthenticationException('Invalid app ID'); </span></span><span> <span>} </span></span><span> <span>} </span></span><span> <span>return new UserAppToken( </span></span><span> <span>$user, </span></span><span> <span>$user->getToken(), </span></span><span> <span>$providerKey, </span></span><span> <span>$user->getRoles() </span></span><span> <span>); </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>{@inheritdoc} </span></span></span><span><span> */ </span></span><span> <span>public function supportsToken(TokenInterface $token, $providerKey) </span></span><span> <span>{ </span></span><span> <span>return $token instanceof UserAppToken </span></span><span> <span>&& $token->getProviderKey() === $providerKey; </span></span><span> <span>} </span></span><span> </span><span> <span>/** </span></span><span><span> * <span>{@inheritdoc} </span></span></span><span><span> */ </span></span><span> <span>public function createToken(Request $request, $username, $password, $providerKey) </span></span><span> <span>{ </span></span><span> <span>return new UserAppToken($username, $password, $providerKey); </span></span><span> <span>} </span></span><span><span>}</span></span>
Apa yang berlaku di sini ialah kita menentukan kawasan selamat mudah yang menggunakan jenis pengesahan mudah dengan pengesahan kami. Di bawah kekunci logout kami menambah pengendali yang akan dipanggil (kelas UserApplogout kami yang ditakrifkan sebagai perkhidmatan). Selebihnya adalah persediaan keselamatan Symfony biasa jadi pastikan anda mempunyai borang log masuk yang ditunjukkan pada laluan masuk, dan lain -lain. Lihat dokumentasi ini untuk maklumat lanjut.
Dan itu sahaja. Dengan menggunakan pengesahan Simple_Form dengan Pengesahan Borang Custom kami dan Penyedia Pengguna (bersama -sama dengan pengendali logout pilihan), kami telah melaksanakan mekanisme pengesahan Symfony UserApp.io kami sendiri.
Dalam artikel ini, kami telah melihat bagaimana untuk melaksanakan pengesahan bentuk simfoni tersuai menggunakan perkhidmatan userApp.io dan API sebagai pembekal pengguna. Kami telah melalui banyak kod yang bermaksud penjelasan yang sangat singkat mengenai kod itu sendiri. Sebaliknya, saya cuba menerangkan proses pengesahan dengan Symfony dengan membina penyelesaian tersuai yang mengambil kira cara kita dapat berinteraksi dengan userapp.io.
Jika anda mengikuti dan melaksanakan kaedah ini di dalam bundle anda dan ingin menggunakannya seperti ini, teruskan. Anda juga mempunyai pilihan untuk menggunakan perpustakaan yang saya buat yang mempunyai persediaan yang sangat cepat dan mudah yang diterangkan pada halaman GitHub. Saya mengesyorkan yang terakhir kerana saya merancang untuk membangun dan mengekalkannya supaya anda sentiasa boleh mendapatkan versi terkini jika ada bug yang dikeluarkan atau ciri yang diperkenalkan (berharap tidak sebaliknya).
Jika anda ingin menyumbang kepadanya, anda sangat dialu -alukan. Saya juga menghargai memberitahu saya jika anda menghadapi masalah atau berfikir ada cara yang lebih baik untuk mencapai matlamat yang sama.
Mengintegrasikan UserApp.io dengan Symfony2 untuk Pengesahan Pengguna melibatkan beberapa langkah. Pertama, anda perlu memasang perpustakaan userApp menggunakan komposer. Kemudian, anda perlu mengkonfigurasi perkhidmatan UserApp dalam projek Symfony2 anda. Ini melibatkan penubuhan kunci API UserApp dan mengkonfigurasi perkhidmatan UserApp dalam fail Service.yml. Selepas itu, anda boleh menggunakan perkhidmatan userApp di pengawal anda untuk mengesahkan pengguna.
userApp.io Menyediakan ciri yang dipanggil "Peranan Pengguna" yang membolehkan anda menguruskan peranan dan keizinan pengguna. Anda boleh menentukan peranan yang berbeza dan menyerahkannya kepada pengguna. Kemudian, anda boleh menyemak peranan pengguna dalam pengawal Symfony2 anda untuk mengawal akses ke bahagian -bahagian yang berlainan dari aplikasi anda. Menyediakan ciri yang dipanggil "Pendaftaran Pengguna" yang membolehkan anda mengendalikan pendaftaran pengguna dalam permohonan Symfony2 anda. Anda boleh menggunakan perkhidmatan userApp di pengawal anda untuk mendaftarkan pengguna baru. Perkhidmatan UserApp akan mengendalikan proses pendaftaran, termasuk mengesahkan e -mel dan kata laluan pengguna, dan membuat akaun pengguna baru.
Bagaimana saya boleh mengendalikan ralat pengesahan pengguna dengan userapp.io dalam symfony2? Ciri yang dipanggil "pengendalian ralat" yang membolehkan anda mengendalikan ralat pengesahan pengguna dalam aplikasi Symfony2 anda. Anda boleh menggunakan perkhidmatan UserApp dalam pengawal anda untuk menangkap dan mengendalikan kesilapan pengesahan. Perkhidmatan UserApp akan memberikan mesej ralat terperinci yang boleh anda gunakan untuk menyahpepijat dan memperbaiki isu pengesahan.
userapp.io Menyediakan beberapa alat penyelesaian masalah yang dapat membantu anda menyelesaikan masalah dengan userapp.io di Symfony2. Ia menyediakan mesej ralat terperinci, pembalakan, dan alat penyahpepijatan. Anda juga boleh menggunakan API UserApp untuk menyelesaikan masalah dengan perkhidmatan UserApp. API UserApp menyediakan beberapa titik akhir yang boleh anda gunakan untuk menyahpepijat dan menyelesaikan masalah dengan perkhidmatan userApp.
Atas ialah kandungan terperinci Pengesahan Pengguna di Symfony2 dengan UserApp.io. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!