php身份证验证_PHP的身份验证和访问控制
php身份證驗(yàn)證
IBM安全身份和訪問管理
在IBM白皮書“ 何時(shí)需要訪問 ”中了解有關(guān)在Internet規(guī)模上管理訪問控制的更多信息。
在本文的第一部分中,我向您介紹了Sentry 2,逐步介紹了它的安裝和配置,并提供了一些使用它為PHP應(yīng)用程序?qū)崿F(xiàn)身份驗(yàn)證工作流的示例。 除其他外,我演示了如何通過激活電子郵件來設(shè)置注冊表。 實(shí)施密碼重置工作流程; 以及創(chuàng)建一個(gè)支持創(chuàng)建,編輯和刪除用戶帳戶的用戶帳戶管理器。
在第二篇也是最后一篇文章中,我將深入探討Sentry 2權(quán)限模型,說明如何創(chuàng)建組,為其分配用戶和權(quán)限以及使用權(quán)限檢查有選擇地啟用應(yīng)用程序功能。 我還將展示如何通過登錄限制和臨時(shí)用戶停用來強(qiáng)化應(yīng)用程序,并說明如何將Sentry 2與第三方身份驗(yàn)證服務(wù)(如Google和Twitter)結(jié)合使用。 進(jìn)來,讓我們開始吧!
分配用戶權(quán)限
首先,出發(fā)點(diǎn)是:權(quán)限。 Sentry 2開箱即用地提供了一種合理的權(quán)限模型,既支持直接權(quán)限(直接分配給用戶的權(quán)限)又支持間接權(quán)限(分配給組并由該組成員的用戶繼承的權(quán)限)。
為了說明它是如何工作的,請參見清單1,其中有一個(gè)創(chuàng)建用戶帳戶并為其分配權(quán)限的簡單示例。
清單1.用戶權(quán)限授予
<?php // set up autoloader require ('vendor\autoload.php');// configure database $dsn = 'mysql:dbname=appdata;host=localhost'; $u = 'sentry'; $p = 'g39ejdl'; Cartalyst\Sentry\Facades\Native\Sentry::setupDatabaseResolver(new PDO($dsn, $u, $p));// create user record try {$user = Cartalyst\Sentry\Facades\Native\Sentry::createUser(array('email' => 'test@example.com','password' => 'guessme','first_name' => 'Test','last_name' => 'User','activated' => true,'permissions' => array('read' => 1, 'write' => 1)));} catch (Exception $e) {echo $e->getMessage(); } ?>如清單1所示,將權(quán)限分配給用戶帳戶非常簡單:只需在傳遞給createUser()方法的數(shù)組中添加一個(gè)“ permissions”鍵,然后指定一組權(quán)限。 要分配或更改現(xiàn)有用戶帳戶的權(quán)限,請檢索相應(yīng)的User對象,分配新的權(quán)限,然后將該對象save()到數(shù)據(jù)庫中。 權(quán)限名稱是完全可自定義的,完全可以由您定義。 分配給權(quán)限名稱的值表示是允許(1),拒絕(-1)還是繼承(0)。
清單2通過允許您另外指定用戶是否有權(quán)“查看”,“添加”,“編輯”或“刪除”其他用戶帳戶,來更新您在本文第一部分中看到的用戶帳戶創(chuàng)建腳本。
清單2.交互式用戶權(quán)限授予
<?php if (isset($_POST['submit'])): ?> <?php// set up autoloaderrequire ('vendor\autoload.php');// configure database$dsn = 'mysql:dbname=appdata;host=localhost';$u = 'sentry';$p = 'g39ejdl';Cartalyst\Sentry\Facades\Native\Sentry::setupDatabaseResolver(new PDO($dsn, $u, $p));// validate input and create user recordtry {$email = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);$fname = strip_tags($_POST['first_name']);$lname = strip_tags($_POST['last_name']);$password = strip_tags($_POST['password']);$user = Cartalyst\Sentry\Facades\Native\Sentry::createUser(array('email' => $email,'password' => $password,'first_name' => $fname,'last_name' => $lname,'permissions' => $_POST['perms'],'activated' => true,));echo 'User successfully created.';} catch (Exception $e) {echo 'User could not be created. ' . $e->getMessage();} ?> <?php else: ?> <html> <head></head> <body> <h1>Add User</h2><form action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>" method="post">Email address: <br/><input type="text" name="email" /> <br/>Password: <br/><input type="password" name="password" /> <br/>First name: <br/><input type="text" name="first_name" /> <br/>Last name: <br/><input type="text" name="last_name" /> <br/>Permissions: <br/><input type="checkbox" name="perms[view]" value="1" />View<input type="checkbox" name="perms[add]" value="1" />Add<input type="checkbox" name="perms[edit]" value="1" />Edit<input type="checkbox" name="perms[delete]" value="1" />Delete<input type="submit" name="submit" value="Create" /></form> </body> </html> <?php endif; ?>圖1說明了修改后的用戶帳戶創(chuàng)建表單的外觀。 在提交表單時(shí),使用“權(quán)限”鍵將選中的權(quán)限分配給新創(chuàng)建的帳戶。
圖1.具有權(quán)限授予的帳戶創(chuàng)建表單
驗(yàn)證用戶權(quán)限
分配權(quán)限只是難題的第一步。 在應(yīng)用程序的不同位置,通常將需要檢查用戶是否具有執(zhí)行特定任務(wù)所需的權(quán)限,并拒絕對缺少足夠特權(quán)的用戶進(jìn)行訪問。 Sentry 2使用hasAccess()方法使此操作變得容易,該方法可讓您測試用戶是否有權(quán)訪問所需的權(quán)限。 考慮清單3,該清單修改了本文第一部分中的用戶編輯工具,以僅在登錄用戶具有相應(yīng)權(quán)限的情況下顯示添加,編輯和刪除鏈接。
清單3.用戶權(quán)限檢查
<?php // set up autoloader require ('vendor\autoload.php');// configure database $dsn = 'mysql:dbname=appdata;host=localhost'; $u = 'sentry'; $p = 'g39ejdl'; Cartalyst\Sentry\Facades\Native\Sentry::setupDatabaseResolver(new PDO($dsn, $u, $p));try {$currentUser = Cartalyst\Sentry\Facades\Native\Sentry::getUser(); if (!$currentUser->hasAccess('view')) {throw new Exception ('You don\'t have permission to view this page.');}$users = Cartalyst\Sentry\Facades\Native\Sentry::findAllUsers(); ?> <html><head></head><body><h1>Users</h1><table border="1"><tr><td>Email address</td><td>First name</td><td>Last name</td><td>Last login</td></tr><?php foreach ($users as $u): ?><?php $userArr = $u->toArray(); ?><tr><td><?php echo $userArr['email']; ?></td><td><?php echo isset($userArr['first_name']) ? $userArr['first_name'] : '-'; ?></td><td><?php echo isset($userArr['last_name']) ? $userArr['last_name'] : '-'; ?></td><td><?php echo isset($userArr['last_login']) ? $userArr['last_login'] : '-'; ?></td><?php if ($currentUser->hasAccess('edit')): ?><td><a href="edit.php?id=<?php echo $userArr['id']; ?>">Edit</a></td><?php endif; ?><?php if ($currentUser->hasAccess('delete')): ?><td><a href="delete.php?id=<?php echo $userArr['id']; ?>">Delete</a></td><?php endif; ?></tr><?php endforeach; ?></table><?php if ($currentUser->hasAccess('add')): ?><a href="create.php">Add new user</a><?php endif; ?><body> </html> <?php } catch (Exception $e) {echo $e->getMessage(); } ?>清單3設(shè)置了Sentry 2數(shù)據(jù)庫連接,然后使用getUser()方法檢索與當(dāng)前登錄用戶相對應(yīng)的User對象。 然后,它在各個(gè)位置使用對象的hasAccess()方法來決定用戶是否有權(quán)查看用戶帳戶列表(“視圖”)以及該列表中每個(gè)帳戶旁邊顯示的編輯鏈接(“編輯”,“刪除”或“添加”)。
清單4提供了另一個(gè)示例,該示例首先在允許刪除帳戶之前檢查登錄用戶是否具有“刪除”權(quán)限。
清單4.用戶權(quán)限檢查
<?php if (isset($_GET['id'])) {// set up autoloaderrequire ('vendor\autoload.php');// configure database$dsn = 'mysql:dbname=appdata;host=localhost';$u = 'sentry';$p = 'g39ejdl';Cartalyst\Sentry\Facades\Native\Sentry::setupDatabaseResolver(new PDO($dsn, $u, $p));try {$currentUser = Cartalyst\Sentry\Facades\Native\Sentry::getUser(); if (!$currentUser->hasAccess('delete')) {throw new Exception ('You don\'t have permission to view this page.');}// find user by id and delete$id = strip_tags($_GET['id']); $user = Cartalyst\Sentry\Facades\Native\Sentry::findUserById($id);$user->delete();echo 'User successfully deleted.';} catch (Exception $e) {echo $e->getMessage();} } ?>建立群組
Sentry 2還允許您將用戶分為幾組。 如果要允許不同的用戶級別使用不同的功能級別,則此功能特別有用。 組是使用createGroup()方法創(chuàng)建的,如清單5所示。
清單5.組創(chuàng)建
<?php // set up autoloader require ('vendor\autoload.php');// configure database $dsn = 'mysql:dbname=appdata;host=localhost'; $u = 'sentry'; $p = 'g39ejdl'; Cartalyst\Sentry\Facades\Native\Sentry::setupDatabaseResolver(new PDO($dsn, $u, $p));// create group record try {$group1 = Cartalyst\Sentry\Facades\Native\Sentry::createGroup(array('name' => 'staff','permissions' => array('view' => 1,'add' => 0,'edit' => 1,'delete' => 0)));$group2 = Cartalyst\Sentry\Facades\Native\Sentry::createGroup(array('name' => 'managers','permissions' => array('view' => 1,'add' => 1,'edit' => 1,'delete' => 1)));} catch (Exception $e) {echo $e->getMessage(); } ?>清單5創(chuàng)建了兩個(gè)新組,名為“ staff”和“ managers”。 “工作人員”組僅具有“查看”和“編輯”權(quán)限,而“管理人員”組也具有“編輯”和“刪除”權(quán)限。
組記錄存儲(chǔ)在“組”表中。 使用DESC命令查看此表的結(jié)構(gòu)。
mysql> DESC groups;圖2說明了此表的結(jié)構(gòu)。
圖2. Sentry 2組表的結(jié)構(gòu)
清單6演示了將用戶添加到組的過程。
清單6.組的用戶分配
<?php // set up autoloader require ('vendor\autoload.php');// configure database $dsn = 'mysql:dbname=appdata;host=localhost'; $u = 'sentry'; $p = 'g39ejdl'; Cartalyst\Sentry\Facades\Native\Sentry::setupDatabaseResolver(new PDO($dsn, $u, $p));// create user record try {$user = Cartalyst\Sentry\Facades\Native\Sentry::createUser(array('email' => 'test@example.com','password' => 'guessme','first_name' => 'Test','last_name' => 'User','activated' => true));$group = Cartalyst\Sentry\Facades\Native\Sentry::findGroupByName('managers');$user->addGroup($group); } catch (Exception $e) {echo $e->getMessage(); } ?>將用戶添加到組是一個(gè)分為兩個(gè)步驟的過程。 首先,使用findGroupByName()方法檢索一個(gè)Group對象,然后調(diào)用User對象的addGroup()方法以將該組附加到用戶帳戶。
合并用戶和組權(quán)限
組提供了一種方便的方式來隱式分配權(quán)限給用戶。 只需將用戶分配給組,該用戶將自動(dòng)繼承該組的權(quán)限。 按照清單5中的示例,屬于“ staff”組的用戶將自動(dòng)繼承該組的“查看”和“編輯”權(quán)限,而屬于經(jīng)理組的用戶將自動(dòng)繼承該組的權(quán)限,同時(shí)還“編輯”和“刪除”權(quán)限”。
通過在創(chuàng)建或更新用戶帳戶時(shí)顯式指定不同的值,可以覆蓋用戶的默認(rèn)組權(quán)限。 考慮清單7,它說明了這一點(diǎn)。
清單7.清單7:組權(quán)限覆蓋
<?php // set up autoloader require ('vendor\autoload.php');// configure database $dsn = 'mysql:dbname=appdata;host=localhost'; $u = 'sentry'; $p = 'g39ejdl'; Cartalyst\Sentry\Facades\Native\Sentry::setupDatabaseResolver(new PDO($dsn, $u, $p));// create user record try {$user = Cartalyst\Sentry\Facades\Native\Sentry::createUser(array('email' => 'john@example.com','password' => 'guessme','first_name' => 'John','last_name' => 'User','activated' => true,'permissions' => array('edit' => '-1')));$group = Cartalyst\Sentry\Facades\Native\Sentry::findGroupByName('managers');$user->addGroup($group); } catch (Exception $e) {echo $e->getMessage(); } ?>在清單7中,用戶“ john@example.com”屬于“ managers”組,因此默認(rèn)情況下將具有所有權(quán)限。 但是,在創(chuàng)建帳戶時(shí),已明確拒絕該帳戶的“編輯”權(quán)限。 結(jié)果,用戶將僅獲得“查看”,“添加”和“刪除”權(quán)限。
清單8演示了使用getMergedPermissions()方法來檢索用戶的直接和間接合并權(quán)限。
清單8.合并的用戶和組權(quán)限
<?php // set up autoloader require ('vendor\autoload.php');// configure database $dsn = 'mysql:dbname=appdata;host=localhost'; $u = 'sentry'; $p = 'g39ejdl'; Cartalyst\Sentry\Facades\Native\Sentry::setupDatabaseResolver(new PDO($dsn, $u, $p));// if form submitted if (isset($_POST['submit'])) {try {// validate input$username = filter_var($_POST['username'], FILTER_SANITIZE_EMAIL);$password = strip_tags(trim($_POST['password']));// set login credentials$credentials = array('email' => $username,'password' => $password,);// authenticate// if authentication fails, capture failure messageCartalyst\Sentry\Facades\Native\Sentry::authenticate($credentials, false); } catch (Exception $e) {$failMessage = $e->getMessage();} }// check if user logged in if (Cartalyst\Sentry\Facades\Native\Sentry::check()) {$currentUser = Cartalyst\Sentry\Facades\Native\Sentry::getUser(); } ?> <html> <head></head> <body> <?php if (isset($currentUser)): ?>Logged in as <?php echo $currentUser->getLogin(); ?>. <a href="logout.php">[Log out]</a> <br/>Permissions: <?php echo implode(', ', array_keys($currentUser->getMergedPermissions(), '1')); ?><?php else: ?><h1>Log In</h1><div><?php echo (isset($failMessage)) ? $failMessage : null; ?></div> <form method="post">Username: <input type="text" name="username" /> <br/>Password: <input type="password" name="password" /> <br/><input type="submit" name="submit" value="Log In" /></form><?php endif; ?> </body> </html>圖3顯示了清單8中計(jì)算的“ john@example.com”權(quán)限。
圖3.用戶權(quán)限顯示
Sentry 2還提供了特殊的“超級用戶”權(quán)限,該權(quán)限用作向用戶分配“所有可用權(quán)限”的快捷方式。 清單9展示了它的運(yùn)行。
清單9.超級用戶權(quán)限授予
<?php // set up autoloader require ('vendor\autoload.php');// configure database $dsn = 'mysql:dbname=appdata;host=localhost'; $u = 'sentry'; $p = 'g39ejdl'; Cartalyst\Sentry\Facades\Native\Sentry::setupDatabaseResolver(new PDO($dsn, $u, $p));// create user record try {$user = Cartalyst\Sentry\Facades\Native\Sentry::createUser(array('email' => 'root@example.com','password' => 'guessme','first_name' => 'Root','last_name' => 'User','activated' => true,'permissions' => array('superuser' => '1')));} catch (Exception $e) {echo $e->getMessage(); } ?>限制用戶登錄
Sentry 2還具有一個(gè)有趣的功能,可以提高應(yīng)用程序的安全性:如果登錄嘗試失敗的次數(shù)過多,則會(huì)自動(dòng)限制登錄。 在這種情況下,需要了解一些有趣的方法:
- setAttemptLimit()方法設(shè)置限制登錄前允許的最大嘗試次數(shù)。
- setSuspensionTime()方法設(shè)置應(yīng)限制登錄的分鐘數(shù)。
- getLoginAttempts()方法檢索登錄嘗試的次數(shù)。
- clearLoginAttempts()方法清除失敗的登錄嘗試次數(shù),并取消掛起登錄帳戶。
- check()方法檢索登錄的當(dāng)前狀態(tài),無論是否受到限制。
- suspend()方法掛起登錄帳戶, unsuspend()方法將其恢復(fù)為活動(dòng)狀態(tài)。
- ban()方法禁止登錄帳戶, unBan()方法將其恢復(fù)為活動(dòng)狀態(tài)。
清單10顯示了將限制添加到登錄工作流程是多么容易。
清單10.登錄限制
<?php // set up autoloader require ('vendor\autoload.php');// configure database $dsn = 'mysql:dbname=appdata;host=localhost'; $u = 'sentry'; $p = 'g39ejdl'; Cartalyst\Sentry\Facades\Native\Sentry::setupDatabaseResolver(new PDO($dsn, $u, $p));// enable throttling $throttleProvider = Cartalyst\Sentry\Facades\Native\Sentry::getThrottleProvider(); $throttleProvider->enable();// if form submitted if (isset($_POST['submit'])) {try {// validate input$username = filter_var($_POST['username'], FILTER_SANITIZE_EMAIL);$password = strip_tags(trim($_POST['password']));// configure throttling$throttle = $throttleProvider->findByUserLogin($username);$throttle->setAttemptLimit(3);$throttle->setSuspensionTime(5);$credentials = array('email' => $username,'password' => $password,);Cartalyst\Sentry\Facades\Native\Sentry::authenticate($credentials, false); } catch (Exception $e) {// all other authentication failures$failMessage = $e->getMessage();} }// check if user logged in if (Cartalyst\Sentry\Facades\Native\Sentry::check()) {$currentUser = Cartalyst\Sentry\Facades\Native\Sentry::getUser(); } ?> <html> <head></head> <body> <?php if (isset($currentUser)): ?>Logged in as <?php echo $currentUser->getLogin(); ?><a href="logout.php">[Log out]</a><?php else: ?><h1>Log In</h1><div><?php echo (isset($failMessage)) ? $failMessage : null; ?></div> <form method="post">Username: <input type="text" name="username" /> <br/>Password: <input type="password" name="password" /> <br/><input type="submit" name="submit" value="Log In" /></form><?php endif; ?> </body> </html>清單10實(shí)現(xiàn)了您在前面的示例中看到的標(biāo)準(zhǔn)Sentry 2登錄工作流程,但有兩個(gè)明顯的區(qū)別:
- getThrottleProvider()方法用于檢索全局限制提供程序的實(shí)例。 此提供程序?qū)ο笥米鞯卿浵拗频闹饕刂泣c(diǎn)。 調(diào)用對象的enable()方法將激活Sentry 2的內(nèi)置限制功能。
- 節(jié)流對象的findByUserLogin()方法用于檢索用戶節(jié)流對象的實(shí)例。 對象的setAttemptLimit()和setSuspensionTime()方法用于配置登錄限制的關(guān)鍵參數(shù)-嘗試次數(shù)和暫停時(shí)間。
如果現(xiàn)在嘗試使用錯(cuò)誤的密碼登錄到應(yīng)用程序,則在三次嘗試失敗后,您的帳戶將自動(dòng)暫停五分鐘。 這對試圖通過使用字典猜測密碼的僵尸程序和自動(dòng)腳本提供了可靠的響應(yīng)。
與第三方網(wǎng)絡(luò)集成(Twitter)
如您所見,Sentry 2提供了對存儲(chǔ)在其自己的數(shù)據(jù)庫中的用戶進(jìn)行身份驗(yàn)證所需的一切。 但是,如今,您通常希望您的應(yīng)用程序還支持通過第三方OAuth提供程序(例如Google,Facebook或Twitter)登錄。
Sentry Social 3是Sentry 2的一個(gè)附加組件,旨在與社交網(wǎng)絡(luò)集成。 但是,此組件只能在商業(yè)許可下使用,因此,它可能不是最適合您的項(xiàng)目的組件。 因此,另一種解決方案是使用每個(gè)第三方提供商提供的開源OAuth庫(在大多數(shù)情況下)。
放松,實(shí)際上并不像聽起來那樣復(fù)雜。 為了說明這一點(diǎn),我將通過將Sentry 2與當(dāng)今兩個(gè)最受歡迎的社交網(wǎng)絡(luò)(Twitter和Google+)集成在一起,向您展示一些不同的身份驗(yàn)證和帳戶創(chuàng)建工作流程的示例。
如果您曾經(jīng)嘗試使用Twitter,Google或Facebook憑據(jù)登錄到應(yīng)用程序,則可能會(huì)注意到該應(yīng)用程序能夠訪問該網(wǎng)絡(luò)上的帳戶詳細(xì)信息,并使用該信息預(yù)先填寫自己的注冊表格。 清單11通過使用Zend Framework 1.x中的兩個(gè)組件(特別是Zend_Oauth_Consumer和Zend_Json)來連接到Twitter API并檢索身份驗(yàn)證用戶的屏幕名稱,演示了此工作流程。 然后,此信息將用于填充應(yīng)用程序的本地帳戶創(chuàng)建表單,該表單在提交后會(huì)在Sentry 2數(shù)據(jù)庫中創(chuàng)建一個(gè)新的用戶帳戶。
清單11假定您在PHP包含路徑中具有Zend Framework的工作副本。 注意,在使用清單11中的代碼之前,必須首先在Twitter上注冊您的應(yīng)用程序,獲取使用者密鑰和機(jī)密(圖4中的示例),然后將此信息插入到清單11中的適當(dāng)位置。 請參閱相關(guān)信息的鏈接,Zend框架和用于管理應(yīng)用Twitter API的開發(fā)者控制臺(tái)。
圖4. Twitter應(yīng)用程序控制臺(tái)設(shè)置
清單11.使用Twitter進(jìn)行用戶身份驗(yàn)證和配置文件檢索
<?php session_start(); if (isset($_POST['submit'])) {// if form submitted// use input to create user accountrequire ('vendor\autoload.php');// configure database$dsn = 'mysql:dbname=appdata;host=localhost';$u = 'sentry';$p = 'g39ejdl';Cartalyst\Sentry\Facades\Native\Sentry::setupDatabaseResolver(new PDO($dsn, $u, $p));try {$email = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);$fname = strip_tags($_POST['name']);$password = strip_tags($_POST['password']);$user = Cartalyst\Sentry\Facades\Native\Sentry::createUser(array('email' => $email,'password' => $password,'first_name' => $fname,));echo 'User successfully created.'; } catch (Exception $e) {echo 'User could not be created. ' . $e->getMessage();}} else {// if form not submitted// connect to Twitter via Oauth// ask for user authorization and retrieve user's name via Twitter API// pre-populate account creation formrequire_once 'Zend/Loader.php';Zend_Loader::loadClass('Zend_Oauth_Consumer');Zend_Loader::loadClass('Zend_Json');$config = array('callbackUrl' => 'http://yourhost/path/to/script.php','siteUrl' => 'https://api.twitter.com/oauth','consumerKey' => 'YOUR-CONSUMER-KEY','consumerSecret' => 'YOUR-CONSUMER-SECRET');$consumer = new Zend_Oauth_Consumer($config);// get access tokenif (!empty($_GET) && isset($_SESSION['TWITTER_REQUEST_TOKEN'])) {$token = $consumer->getAccessToken($_GET,unserialize($_SESSION['TWITTER_REQUEST_TOKEN']));$_SESSION['TWITTER_ACCESS_TOKEN'] = serialize($token);} // fetch a request tokenif (!isset($_SESSION['TWITTER_REQUEST_TOKEN'])) {$token = $consumer->getRequestToken();$_SESSION['TWITTER_REQUEST_TOKEN'] = serialize($token);$consumer->redirect();}// use access token to connect to Twitter API// decode response and retrieve user's screen name// generate form with name pre-filledif (isset($_SESSION['TWITTER_ACCESS_TOKEN'])) {$token = unserialize($_SESSION['TWITTER_ACCESS_TOKEN']);$client = $token->getHttpClient($config);$client->setUri('https://api.twitter.com/1.1/account/verify_credentials.json');$client->setMethod(Zend_Http_Client::GET);$response = $client->request(); $data = Zend_Json::decode($response->getBody()); ?><html><head></head><body> <form method="post">Name: <input type="text" name="name" value="<?php echo $data['name']; ?>" /> <br/>Email address: <input type="text" name="email" value="" /> <br/>Password: <input type="password" name="password" value="" /> <br/><input type="submit" name="submit" value="Create Account" /></form></body></html> <?php} } ?>清單11從開始一個(gè)新的會(huì)話開始,該會(huì)話將用作在身份驗(yàn)證過程中接收到的OAuth訪問和請求令牌的存儲(chǔ)容器。 然后,它使用Zend Framework自動(dòng)加載器加載所需的類并初始化新的Zend_Oauth_Consumer對象。 然后,該代碼實(shí)現(xiàn)標(biāo)準(zhǔn)的OAuth工作流程,首先獲取請求令牌,然后將用戶重定向到Twitter以登錄,認(rèn)證并獲取訪問令牌。
有了訪問令牌,清單11現(xiàn)在可以向Twitter API的/verify_credentials端點(diǎn)發(fā)出經(jīng)過身份驗(yàn)證的請求。 對此請求的響應(yīng)是一個(gè)JSON文檔,其中包含簡短的用戶個(gè)人資料,包括用戶的屏幕名稱。 現(xiàn)在,可以很容易地解碼JSON數(shù)據(jù),從中提取用戶的屏幕名稱,并使用此信息來預(yù)先填充帳戶創(chuàng)建表單。 用戶現(xiàn)在只需簡單地添加他或她的電子郵件地址并提交表單,這將啟動(dòng)Sentry 2并使用您之前看到的createUser()方法創(chuàng)建一個(gè)用戶帳戶。
圖5顯示了正在進(jìn)行的Twitter身份驗(yàn)證的示例以及由此產(chǎn)生的帳戶創(chuàng)建表單,其中用戶的屏幕名稱已經(jīng)從Twitter API中填充。
圖5. Twitter身份驗(yàn)證過程
如果您想知道清單11為什么也不能用用戶的電子郵件地址預(yù)先填充帳戶創(chuàng)建表單,原因很簡單:Twitter不會(huì)通過其API公開電子郵件地址。 由于電子郵件地址是Sentry 2使用的主要帳戶標(biāo)識符,因此用戶必須手動(dòng)請求并輸入此信息才能完成帳戶創(chuàng)建過程。 不過,請不要擔(dān)心,這是特定于Twitter的約束,清單12(使用Google+)對此有所不同。
與第三方網(wǎng)絡(luò)集成(Google)
Google+作為社交網(wǎng)絡(luò)正變得越來越流行,并且Google還提供了PHP OAuth客戶端的可靠實(shí)現(xiàn)。 該客戶端可以免費(fèi)下載,可以連接到所有Google API,包括Google+ API。 但是,在使用以下清單中的代碼之前,您必須首先在Google上注冊您的應(yīng)用程序,獲取客戶ID和密碼,然后將此信息插入每個(gè)清單中的適當(dāng)位置(圖6中的示例)。 請參閱相關(guān)信息的鏈接,谷歌PHP OAuth用戶端和谷歌的API控制臺(tái)。
圖6. Google應(yīng)用程序控制臺(tái)設(shè)置
清單12提供了一個(gè)示例,該示例針對Google OAuth服務(wù)進(jìn)行身份驗(yàn)證,從Google+ API檢索經(jīng)過身份驗(yàn)證的用戶名和電子郵件地址,并使用此信息自動(dòng)創(chuàng)建新的Sentry 2用戶帳戶。
清單12.使用Google進(jìn)行用戶身份驗(yàn)證和帳戶創(chuàng)建
<?php // load required classes require_once 'vendor/google-api-php-client/src/Google_Client.php'; require_once 'vendor/google-api-php-client/src/contrib/Google_Oauth2Service.php'; require_once 'vendor/google-api-php-client/src/contrib/Google_PlusService.php'; require_once 'vendor\autoload.php';// configure database $dsn = 'mysql:dbname=appdata;host=localhost'; $u = 'sentry'; $p = 'g39ejdl'; Cartalyst\Sentry\Facades\Native\Sentry::setupDatabaseResolver(new PDO($dsn, $u, $p));// start session session_start();// initialize OAuth 2.0 client // set scopes $client = new Google_Client(); $client->setApplicationName('Project X'); $client->setClientId('YOUR-CLIENT-ID'); $client->setClientSecret('YOUR-CLIENT-SECRET'); $client->setRedirectUri('http://yourhost/path/to/script.php'); $client->setScopes(array('https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile','https://www.googleapis.com/auth/plus.login' )); $oauth2Service = new Google_Oauth2Service($client); $plusService = new Google_PlusService($client);// if code received, authenticate and store token in session if (isset($_GET['code'])) {$client->authenticate();$_SESSION['token'] = $client->getAccessToken();$redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));exit; }// if token available in session, set token in client if (isset($_SESSION['token'])) {$client->setAccessToken($_SESSION['token']); }// if token available in client, access API // get user name and email address // generate random password // create user in Sentry2 database and notify user with email if ($client->getAccessToken()) {$userinfo = $oauth2Service->userinfo->get();$profile = $plusService->people->get('me');$email = filter_var($userinfo['email'], FILTER_SANITIZE_EMAIL);$fname = $profile['name']['givenName'];$lname = $profile['name']['familyName'];$password = substr(md5(rand()),0,7);try { $user = Cartalyst\Sentry\Facades\Native\Sentry::createUser(array('email' => $email,'password' => $password,'first_name' => $fname,'last_name' => $lname,'activated' => true,));$body = <<<EOM Your account was successfully created. Please log in with the credentials below: Email: $email Password: $password EOM;@mail($email, 'Account created successfully', $body); } catch (Exception $e) {$failMessage = $e->getMessage();}$_SESSION['token'] = $client->getAccessToken();} else {$authUrl = $client->createAuthUrl(); } ?> <html> <head></head> <body> <?php if (isset($authUrl)): ?><a href='<?php echo $authUrl; ?>'>Register with Google+</a><?php else: ?><div><?php echo (isset($failMessage)) ? $failMessage : "Account created for '$fname $lname'. Credentials: $email / $password"; ?></div> <?php endif; ?> </body> </html>清單12首先加載GooglePHP OAuth庫,建立Sentry 2數(shù)據(jù)庫連接并開始一個(gè)新PHP會(huì)話。 然后,它將初始化Google OAuth客戶端,設(shè)置客戶端ID和從Google API控制臺(tái)獲取的密碼,并且重要的是,定義客戶端的范圍。 最后,它初始化兩個(gè)服務(wù)對象,一個(gè)用于OAuth服務(wù),一個(gè)用于Google+服務(wù),并使用客戶端的createAuthUrl()方法創(chuàng)建一個(gè)身份驗(yàn)證URL。
按照標(biāo)準(zhǔn)的OAuth工作流程,單擊身份驗(yàn)證URL的鏈接會(huì)將用戶帶到Google身份驗(yàn)證頁面(圖7)。 用戶對應(yīng)用程序進(jìn)行身份驗(yàn)證并確認(rèn)其有權(quán)訪問的數(shù)據(jù)之后,將生成訪問令牌并將其存儲(chǔ)在會(huì)話中。 通過此訪問令牌,客戶端可以訪問選定的Google API。
圖7. Google身份驗(yàn)證過程
使用訪問令牌,服務(wù)對象可以獲取身份驗(yàn)證用戶的配置文件信息,例如名字,姓氏和電子郵件地址。 然后,此信息與自動(dòng)生成的隨機(jī)密碼結(jié)合在一起,以在Sentry 2數(shù)據(jù)庫中創(chuàng)建并激活新的用戶帳戶。 然后使用PHP的mail()函數(shù)將包括自動(dòng)生成的密碼在內(nèi)的帳戶信息通過電子郵件發(fā)送給用戶。
此方法的一種變體是從第三方網(wǎng)絡(luò)信息創(chuàng)建用戶帳戶,然后手動(dòng)將用戶登錄到應(yīng)用程序。 清單13是遵循此方法的清單12的修訂版。
清單13.用戶身份驗(yàn)證和使用Google登錄
<?php // load required classes require_once 'vendor/google-api-php-client/src/Google_Client.php'; require_once 'vendor/google-api-php-client/src/contrib/Google_Oauth2Service.php'; require_once 'vendor/google-api-php-client/src/contrib/Google_PlusService.php'; require_once 'vendor\autoload.php';// configure database $dsn = 'mysql:dbname=appdata;host=localhost'; $u = 'sentry'; $p = 'g39ejdl'; Cartalyst\Sentry\Facades\Native\Sentry::setupDatabaseResolver(new PDO($dsn, $u, $p));// start session session_start();// initialize OAuth 2.0 client // set scopes $client = new Google_Client(); $client->setApplicationName('Project X'); $client->setClientId('YOUR-CLIENT-ID'); $client->setClientSecret('YOUR-CLIENT-SECRET'); $client->setRedirectUri('http://yourhost/path/to/script.php'); $client->setScopes(array('https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile','https://www.googleapis.com/auth/plus.login' )); $oauth2Service = new Google_Oauth2Service($client); $plusService = new Google_PlusService($client);// if code received, authenticate and store token in session if (isset($_GET['code'])) {$client->authenticate();$_SESSION['token'] = $client->getAccessToken();$redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));exit; }// if token available in session, set token in client if (isset($_SESSION['token'])) {$client->setAccessToken($_SESSION['token']); }// if logout request, destroy session and revoke token if (isset($_REQUEST['logout'])) {unset($_SESSION['token']); $client->revokeToken();Cartalyst\Sentry\Facades\Native\Sentry::logout(); }// if token available in client, access API // get user name and email address // check if user present in Sentry2 database and auto-login // or create new user account and log user in if ($client->getAccessToken()) {$userinfo = $oauth2Service->userinfo->get();$profile = $plusService->people->get('me');$email = $userinfo['email'];$fname = $profile['name']['givenName'];$lname = $profile['name']['familyName'];try {try { $user = Cartalyst\Sentry\Facades\Native\Sentry::findUserByLogin($email);} catch (Cartalyst\Sentry\Users\UserNotFoundException $e) {$password = substr(md5(rand()),0,7);$user = Cartalyst\Sentry\Facades\Native\Sentry::createUser(array('email' => $email,'password' => $password,'first_name' => $fname,'last_name' => $lname,'activated' => true,));$createdMessage = "Account created for '$fname $lname'. Credentials: $email / $password";}Cartalyst\Sentry\Facades\Native\Sentry::login($user, false); if (Cartalyst\Sentry\Facades\Native\Sentry::check()) {$currentUser = Cartalyst\Sentry\Facades\Native\Sentry::getUser();}} catch (Exception $e) {$failMessage = $e->getMessage();}$_SESSION['token'] = $client->getAccessToken();} else {$authUrl = $client->createAuthUrl(); } ?> <html> <head></head> <body> <?php if (isset($authUrl)): ?><a href='<?php echo $authUrl; ?>'>Log in with Google+</a><?php else: ?><div><?php echo (isset($failMessage)) ? $failMessage : null; ?></div> <div><?php echo (isset($createdMessage)) ? $createdMessage : null; ?></div> Logged in as <?php echo $currentUser->getLogin(); ?>. [<a href='?logout'>Log out</a>]<?php endif; ?> </body> </html>大多數(shù)清單13中的代碼是一樣的,在清單12 。 主要區(qū)別在于,在完成Google身份驗(yàn)證過程后,腳本將檢查是否已經(jīng)存在具有相同電子郵件地址的Sentry 2帳戶,如果不存在,則會(huì)創(chuàng)建一個(gè)。 用戶帳戶出現(xiàn)在系統(tǒng)上之后,Sentry 2 login()方法用于手動(dòng)進(jìn)行身份驗(yàn)證并將用戶登錄到應(yīng)用程序。 還支持注銷工作流,該工作流將用戶從應(yīng)用程序中注銷,并撤消Google API訪問令牌。
摘要
如這些示例所示,Sentry 2為PHP Web應(yīng)用程序中的身份驗(yàn)證和粒度訪問控制提供了功能全面的框架。 通過添加容易獲得的開源庫,可以將其與第三方社交網(wǎng)絡(luò)和身份驗(yàn)證提供程序集成,從而以最小的開發(fā)工作量滿足各種常見用例。 下次您要構(gòu)建Web應(yīng)用程序時(shí),自己嘗試一下,看看您的想法!
翻譯自: https://www.ibm.com/developerworks/opensource/library/se-sentry2/index.html
php身份證驗(yàn)證
總結(jié)
以上是生活随笔為你收集整理的php身份证验证_PHP的身份验证和访问控制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cocos2dx入门2:安装及基本介绍
- 下一篇: APP创业经:比开发更难的是APP运营和