中文字幕一区二区人妻电影,亚洲av无码一区二区乱子伦as ,亚洲精品无码永久在线观看,亚洲成aⅴ人片久青草影院按摩,亚洲黑人巨大videos

在PHP中構(gòu)建簡(jiǎn)單的登錄

發(fā)布于:2021-02-18 00:02:20

0

240

0

php laravel Okta react

從頭開(kāi)始為您的Web應(yīng)用程序構(gòu)建用戶身份驗(yàn)證系統(tǒng)可能是一項(xiàng)非常棘手的工作。一開(kāi)始看起來(lái)很簡(jiǎn)單,但是有很多細(xì)節(jié)你必須考慮-正確散列密碼,保護(hù)用戶會(huì)話,提供一種重置忘記密碼的方法。大多數(shù)現(xiàn)代框架都提供了處理所有這些問(wèn)題的樣板代碼,但即使您沒(méi)有使用框架,也不要絕望。在本文中,我將向您展示如何從頭開(kāi)始構(gòu)建一個(gè)PHP應(yīng)用程序(只需依賴一個(gè)外部庫(kù)DotEnv,這樣我們就可以將機(jī)密存儲(chǔ)在代碼庫(kù)外部的.env文件中)。該應(yīng)用程序?qū)⒗肙kta簡(jiǎn)單的OAuth2.0API提供用戶登錄/注銷、新用戶注冊(cè)和“忘記密碼”表單。

所有你需要遵循的教程是一個(gè)Okta開(kāi)發(fā)人員帳戶(你可以免費(fèi)創(chuàng)建一個(gè)),PHP和Composer。

為什么使用Okta進(jìn)行身份驗(yàn)證?

Okta使身份管理比以前更簡(jiǎn)單、更安全、更可擴(kuò)展。Okta是一個(gè)API服務(wù),允許您創(chuàng)建、編輯和安全地存儲(chǔ)用戶帳戶和用戶帳戶數(shù)據(jù),并將它們與一個(gè)或多個(gè)應(yīng)用程序連接。我們的API使您能夠:

  • 對(duì)您的用戶進(jìn)行身份驗(yàn)證和授權(quán)

  • 存儲(chǔ)有關(guān)用戶的數(shù)據(jù)

  • 執(zhí)行基于密碼的社交登錄

  • 使用多因素身份驗(yàn)證保護(hù)您的應(yīng)用程序

  • 等等!有關(guān)更多信息,請(qǐng)查看我們的產(chǎn)品文檔

注冊(cè)一個(gè)永久免費(fèi)的開(kāi)發(fā)人員帳戶,完成后,回來(lái)學(xué)習(xí)如何從頭開(kāi)始使用用戶身份驗(yàn)證構(gòu)建PHP應(yīng)用程序。

創(chuàng)建一個(gè)免費(fèi)的Okta開(kāi)發(fā)者帳戶

在繼續(xù)之前,您需要登錄到您的Okta帳戶(或者免費(fèi)創(chuàng)建一個(gè)新帳戶)并創(chuàng)建一個(gè)OAuth應(yīng)用程序。您需要為應(yīng)用程序獲取客戶機(jī)ID和客戶機(jī)機(jī)密,還需要一個(gè)API令牌,以便應(yīng)用程序可以遠(yuǎn)程注冊(cè)用戶。

以下是逐步說(shuō)明:

轉(zhuǎn)到“應(yīng)用程序”菜單項(xiàng)并單擊“添加應(yīng)用程序”按鈕:

 

  1. 選擇Web并單擊Next。

 

輸入標(biāo)題,然后設(shè)置http://localhost:8080/作為基本URI和登錄重定向URI,然后單擊“完成”。您可以保留其余的設(shè)置:

 

  1. 從應(yīng)用程序設(shè)置復(fù)制客戶端ID和客戶端機(jī)密。

  2. 轉(zhuǎn)到API>;令牌,然后單擊創(chuàng)建令牌:

 

為您的令牌輸入一個(gè)標(biāo)題,并確保復(fù)制令牌的值并安全地存儲(chǔ)它。你只能看到它一次-如果你丟失了它,你需要?jiǎng)?chuàng)建一個(gè)新的令牌。

注意你的主要組織URL,你也需要這個(gè)。

創(chuàng)建項(xiàng)目骨架

首先在頂層目錄中創(chuàng)建一個(gè)/src目錄和一個(gè)簡(jiǎn)單的composer.json文件,其中只有一個(gè)依賴項(xiàng):DotEnv庫(kù),它允許我們將Okta身份驗(yàn)證詳細(xì)信息保存在代碼庫(kù)外部的.env文件中:

composer.json

{
   "require": {
       "vlucas/phpdotenv": "^2.4"
   },
   "autoload": {
       "psr-4": {
           "Src\": "src/"
       }
   }
}

我們還配置了一個(gè)PSR-4自動(dòng)加載程序,它將自動(dòng)在/src目錄中查找PHP類。

我們現(xiàn)在可以安裝依賴項(xiàng):

composer install

我們有一個(gè)/vendor目錄,并且安裝了DotEnv依賴項(xiàng)(我們也可以使用autoloader從/src加載類,而不需要調(diào)用include())。

讓我們?yōu)槲覀兊捻?xiàng)目創(chuàng)建一個(gè).gitignore文件,其中有兩行,因此/vendor目錄和本地.env文件將被忽略:

/vendor
.env

接下來(lái),我們將為Okta身份驗(yàn)證變量創(chuàng)建一個(gè).env.example文件:

CLIENT_ID=
CLIENT_SECRET=
REDIRECT_URI=http://localhost:8080/
METADATA_URL=https://{yourOktaDomain}/oauth2/default/.well-known/oauth-authorization-server
API_URL_BASE=https://{yourOktaDomain}/api/v1/
API_TOKEN=

以及一個(gè).env文件,我們將在其中填寫來(lái)自O(shè)kta帳戶的實(shí)際詳細(xì)信息(Git將忽略它,這樣它就不會(huì)出現(xiàn)在我們的存儲(chǔ)庫(kù)中)。

項(xiàng)目將具有以下目錄結(jié)構(gòu)(您現(xiàn)在可以創(chuàng)建其余文件):

/public/index.php
/src
   /controllers
   /services
   /views
bootstrap.php
.env
.env.example

/public/index.php文件是我們的簡(jiǎn)單前端控制器。它加載bootstrap.php腳本,然后處理傳入的HTTP請(qǐng)求,將其委托給控制器。以下是初始版本:

/public/index.php

<?php
require('../bootstrap.php');

// view data
$data = null;

view('home', $data);

現(xiàn)在,它只是加載沒(méi)有數(shù)據(jù)的“home”視圖。

bootstrap.php腳本啟動(dòng)自動(dòng)加載,初始化我們的依賴項(xiàng)(在本例中只有DotEnv),啟動(dòng)會(huì)話并提供用于加載視圖文件的助手函數(shù)view()(我們已經(jīng)在/public/index.php中使用了它)。以下是bootstrap.php文件的完整版本:

bootstrap.php

<?php
require 'vendor/autoload.php';
use DotenvDotenv;

$dotenv = new DotEnv( __DIR__ );
$dotenv->load();

session_start();

function view($title, $data = null)
{
   $filename = __DIR__. '/src/views/' . $title . '.php';
   if (file_exists($filename)) {
       include($filename);
   } else {
       throw new Exception('View ' . $title . ' not found!');
   }
}

/src/controllers目錄保存我們的控制器類。/src/services目錄保存服務(wù)層的類。/src/views目錄保存我們的視圖(我們?cè)谶@個(gè)項(xiàng)目中使用簡(jiǎn)單的PHP視圖,沒(méi)有模板系統(tǒng))。

讓我們開(kāi)始構(gòu)建視圖:

/src/views/home.php

<?php view('header', $data); ?>
<section class="hero">
   <div class="hero-body">
       <div class="container">

<?php
   if (isset($data['thank_you'])) {
?>
<div class="notification is-info">
<?php
   echo $data['thank_you'];
?>  
</div>
<?php
   }
?>

<?php
   if (isset($data['loginError'])) {
?>
<div class="notification is-danger">
<?php
   echo $data['loginError'];
?>
</div>
<?php
   }
?>

<?php
   if (isset($_SESSION['username'])) {
?>
           <p class="subtitle is-4">
           This is some great content for logged in users
           <p>
<?php
   } else {
?>
           <p class="subtitle is-4">
           You need to login to access the content!
           </p>
<?php
   }
?>
       </div>
   </div>
</section>
<?php view('footer'); ?>

homepage視圖加載頁(yè)眉和頁(yè)腳,并且能夠顯示通知消息和錯(cuò)誤消息。它還根據(jù)用戶是否登錄(通過(guò)檢查$_SESSION['username']確定)顯示不同的內(nèi)容。

以下是頁(yè)眉和頁(yè)腳視圖的完整版本:

/src/views/header.php

<!DOCTYPE html>
<html>
   <head>
       <meta charset="utf-8">
       <meta http-equiv="X-UA-Compatible" content="IE=edge">
       <meta name="viewport" content="width=device-width, initial-scale=1">
       <meta name="description" content="PHP Login App bd-index-custom-example">
       <title>Core PHP + Okta Login Example </title>
       <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css">
   </head>
   <body>
       <nav id="navbar" class="navbar has-shadow is-spaced">
           <div>
           <div>
               <h1>Core PHP + Okta Login Example</h1>
               <?php
                   if (isset($_SESSION['username'])) {
               ?>
                       <p>
                           Logged in as <?php echo $_SESSION['username'] ?>
                       </p>
                       <p><a href="/?logout">Log Out</a></p>
               <?php
                   } else {
               ?>
                       <p>Not logged in</p>
                       <p><a href="/?login">Log In</a> | <a href="/?forgot">Forgot Password</a> | <a href="/?register">Register</a></p>
               <?php
                   }
               ?>
           </div>
           </div>
       </nav>


/src/views/footer.php

  </body>
</html>

頭部加載bulmacss框架,如果有登錄用戶,則顯示用戶名和注銷鏈接;如果沒(méi)有登錄用戶,則顯示登錄/忘記密碼/注冊(cè)鏈接。

啟動(dòng)內(nèi)置PHP服務(wù)器:

php -S 127.0.0.1:8080 -t public

加載時(shí)http://localhost:8080,您應(yīng)該看到應(yīng)用程序:

  

實(shí)施Okta登錄/注銷

Okta登錄分為幾個(gè)階段:

  1. 建立登錄URL

  2. 重定向到URL

  3. 遠(yuǎn)程執(zhí)行Okta身份驗(yàn)證,然后重定向回我們的重定向URI

  4. 處理響應(yīng)并授權(quán)應(yīng)用程序中的用戶。

我們將public/index.php修改為處理上面的步驟1和步驟2,并將其添加到view('home');行的上方:

// build login URL and redirect the user
if (isset($_REQUEST['login']) && (! isset($_SESSION['username']))) {
   $_SESSION['state'] = bin2hex(random_bytes(5));
   $authorizeUrl = $oktaApi->buildAuthorizeUrl($_SESSION['state']);
   header('Location: ' . $authorizeUrl);
   die();
}

當(dāng)它收到重定向回(包括來(lái)自O(shè)kta的代碼)時(shí),還要處理步驟4:

if (isset($_GET['code'])) {
   $result = $oktaApi->authorizeUser();
   if (isset($result['error'])) {
       $data['loginError'] = $result['errorMessage'];
   }
}

我們還將添加一個(gè)非常簡(jiǎn)單的注銷處理程序,它只是取消設(shè)置會(huì)話變量username

新版本如下:

/public/index.php

<?php
require('../bootstrap.php');

use SrcServicesOktaApiService;

$oktaApi = new OktaApiService;

// view data
$data = null;

// build login URL and redirect the user
if (isset($_REQUEST['login']) && (! isset($_SESSION['username']))) {
   $_SESSION['state'] = bin2hex(random_bytes(5));
   $authorizeUrl = $oktaApi->buildAuthorizeUrl($_SESSION['state']);
   header('Location: ' . $authorizeUrl);
   die();
}

// handle the redirect back
if (isset($_GET['code'])) {
   $result = $oktaApi->authorizeUser();
   if (isset($result['error'])) {
       $data['loginError'] = $result['errorMessage'];
   }
}

if (isset($_REQUEST['logout'])) {
   unset($_SESSION['username']);
   header('Location: /');
   die();
}

view('home', $data);

我們還要構(gòu)建OktaApiService并添加所需的方法(buildAuthorizeUrl()authorizeUser()):

/src/services/OktaApiService.php

<?php
namespace SrcServices;

class OktaApiService
{
   private $clientId;
   private $clientSecret;
   private $redirectUri;
   private $metadataUrl;
   private $apiToken;
   private $apiUrlBase;

   public function __construct()
   {
       $this->clientId = getenv('CLIENT_ID');
       $this->clientSecret = getenv('CLIENT_SECRET');
       $this->redirectUri = getenv('REDIRECT_URI');
       $this->metadataUrl = getenv('METADATA_URL');
       $this->apiToken = getenv('API_TOKEN');
       $this->apiUrlBase = getenv('API_URL_BASE');
   }

   public function buildAuthorizeUrl($state)
   {
       $metadata = $this->httpRequest($this->metadataUrl);
       $url = $metadata->authorization_endpoint . '?' . http_build_query([
           'response_type' => 'code',
           'client_id' => $this->clientId,
           'redirect_uri' => $this->redirectUri,
           'state' => $state,
       ]);
       return $url;
   }

   public function authorizeUser()
   {
       if ($_SESSION['state'] != $_GET['state']) {
           $result['error'] = true;
           $result['errorMessage'] = 'Authorization server returned an invalid state parameter';
           return $result;
       }

       if (isset($_GET['error'])) {
           $result['error'] = true;
           $result['errorMessage'] = 'Authorization server returned an error: '.htmlspecialchars($_GET['error']);
           return $result;
       }

       $metadata = $this->httpRequest($this->metadataUrl);

       $response = $this->httpRequest($metadata->token_endpoint, [
           'grant_type' => 'authorization_code',
           'code' => $_GET['code'],
           'redirect_uri' => $this->redirectUri,
           'client_id' => $this->clientId,
           'client_secret' => $this->clientSecret
       ]);

       if (! isset($response->access_token)) {
           $result['error'] = true;
           $result['errorMessage'] = 'Error fetching access token!';
           return $result;
       }
       $_SESSION['access_token'] = $response->access_token;

       $token = $this->httpRequest($metadata->introspection_endpoint, [
           'token' => $response->access_token,
           'client_id' => $this->clientId,
           'client_secret' => $this->clientSecret
       ]);

       if ($token->active == 1) {
           $_SESSION['username'] = $token->username;
           $result['success'] = true;
           return $result;
       }
   }

   private function httpRequest($url, $params = null)
   {
       $ch = curl_init($url);
       curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
       if ($params) {
           curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
       }
       return json_decode(curl_exec($ch));
   }
}

OktaApiService類中發(fā)生了很多事情,讓我來(lái)解釋一下這個(gè)過(guò)程:

在構(gòu)建授權(quán)URL之前,我們生成一個(gè)隨機(jī)值,用于驗(yàn)證響應(yīng):

$_SESSION['state'] = bin2hex(random_bytes(5));
$authorizeUrl = $oktaApi->buildAuthorizeUrl($_SESSION['state']);

方法buildAuthorizeUrl()使用對(duì)元數(shù)據(jù)URL的調(diào)用來(lái)獲取服務(wù)器的授權(quán)端點(diǎn),然后為該端點(diǎn)構(gòu)建查詢:

      $metadata = $this->httpRequest($this->metadataUrl);
       $url = $metadata->authorization_endpoint . '?' . http_build_query([
           'response_type' => 'code',
           'client_id' => $this->clientId,
           'redirect_uri' => $this->redirectUri,
           'state' => $state,
       ]);

當(dāng)我們得到重定向回,我們收到的狀態(tài)變量,我們發(fā)送的授權(quán)重定向和代碼從Okta。當(dāng)我們得到一個(gè)代碼時(shí),我們調(diào)用authorizeUser()方法,首先驗(yàn)證狀態(tài)值是否匹配并且響應(yīng)中沒(méi)有錯(cuò)誤代碼:

      if ($_SESSION['state'] != $_GET['state']) {
           $result['error'] = true;
           $result['errorMessage'] = 'Authorization server returned an invalid state parameter';
           return $result;
       }

       if (isset($_GET['error'])) {
           $result['error'] = true;
           $result['errorMessage'] = 'Authorization server returned an error: '.htmlspecialchars($_GET['error']);
           return $result;
       }

然后使用token_endpoint(來(lái)自元數(shù)據(jù)調(diào)用)將代碼交換為訪問(wèn)令牌:

      $metadata = $this->httpRequest($this->metadataUrl);

       $response = $this->httpRequest($metadata->token_endpoint, [
           'grant_type' => 'authorization_code',
           'code' => $_GET['code'],
           'redirect_uri' => $this->redirectUri,
           'client_id' => $this->clientId,
           'client_secret' => $this->clientSecret
       ]);

       if (! isset($response->access_token)) {
           $result['error'] = true;
           $result['errorMessage'] = 'Error fetching access token!';
           return $result;
       }
       $_SESSION['access_token'] = $response->access_token;

之后,我們使用內(nèi)省端點(diǎn)來(lái)確認(rèn)令牌有效且處于活動(dòng)狀態(tài),并獲取新授權(quán)用戶的用戶名:

      $token = $this->httpRequest($metadata->introspection_endpoint, [
           'token' => $response->access_token,
           'client_id' => $this->clientId,
           'client_secret' => $this->clientSecret
       ]);

       if ($token->active == 1) {
           $_SESSION['username'] = $token->username;
           $result['success'] = true;
           return $result;
       }

通過(guò)Okta API注冊(cè)新用戶

新用戶注冊(cè)將在UserController類中處理。前面的控制器需要三個(gè)處理器:

public/index.php

...
use SrcControllersUserController;
...
$userController = new UserController($oktaApi);
...
if (isset($_REQUEST['register'])) {
   view('register');
   die();
}

if (isset($_REQUEST['command']) && ($_REQUEST['command'] == 'register')) {
   $userController->handleRegistrationPost();
   die();
}

if (isset($_REQUEST['thankyou'])) {
   $data['thank_you'] = 'Thank you for your registration!';
}
...

單擊寄存器鏈接時(shí),第一個(gè)處理程序只加載register視圖:

/src/views/register.php

<?php view('header', $data); ?>
<section class="hero">
   <div class="hero-body">
       <div class="container">
           <form method="post" action="/">

<?php
   if ($data && $data['errors']) {
?>
<div class="notification is-danger">
<?php
   echo "Errors:";
   echo $data['errorMessage'];
?>  
</div>
<?php
   }
?>

<div class="field">
   <label class="label">First Name</label>
   <div class="control">
       <input class="input" name="first_name" type="text" value="<?php if ($data) { echo $data['input']['first_name']; } ?>">
   </div>
</div>

<div class="field">
   <label class="label">Last Name</label>
   <div class="control">
       <input class="input" name="last_name" type="text" value="<?php if ($data) { echo $data['input']['last_name']; } ?>">
   </div>
</div>

<div class="field">
   <label class="label">Email</label>
   <div class="control">
       <input class="input" name="email" type="email" value="<?php if ($data) { echo $data['input']['email']; } ?>">
   </div>
</div>

<div class="field">
   <label class="label">Password</label>
   <div class="control">
       <input class="input" name="password" type="password" value="">
   </div>
</div>

<div class="field">
   <label class="label">Repeat Password</label>
   <div class="control">
       <input class="input" name="repeat_password" type="password" value="">
   </div>
</div>

<input type="hidden" name="command" value="register">

<div class="control">
   <button class="button is-link">Register</button>
   <a class="button is-link" href="/">Cancel</a>
</div>

           </form>
       </div>
   </div>
</section>
<?php view('footer'); ?>

提交表單時(shí),第二個(gè)處理程序?qū)⑽薪o用戶控制器:

/src/controllers/UserController.php 

<?php
namespace SrcControllers;

use SrcServicesOktaApiService;

class UserController
{

   private $errors = null;
   private $errorMessage = null;

   public function __construct(OktaApiService $oktaApi)
   {
       $this->oktaApi = $oktaApi;
   }

   public function handleRegistrationPost()
   {
       if ($_SERVER['REQUEST_METHOD'] === 'POST') {

           $input = [
               'first_name' => $_POST['first_name'],
               'last_name' => $_POST['last_name'],
               'email' => $_POST['email'],
               'password' => $_POST['password'],
               'repeat_password' => $_POST['repeat_password'],
           ];

           // local form validation
           $this->validateRegistrationForm($input);
           if ($this->errors) {
               $viewData = [
                   'input' => $input,
                   'errors' => $this->errors,
                   'errorMessage' => $this->errorMessage
               ];
               view('register', $viewData);
               return true;
           }

           // if local validation passes, attempt to register the user
           // via the Okta API
           $result = $this->oktaApi->registerUser($input);
           $result = json_decode($result, true);
           if (isset($result['errorCode'])) {
               $viewData = [
                   'input' => $input,
                   'errors' => true,
                   'errorMessage' => '<br>(Okta) ' . $result['errorCauses'][0]['errorSummary']
               ];
               view('register', $viewData);
               return true;
           }

           header('Location: /?thankyou');
           return true;
       }

       header('HTTP/1.0 405 Method Not Allowed');
       die();
   }

   private function validateRegistrationForm($input)
   {
       $errorMessage = '';
       $errors = false;

       // validate field lengths
       if (strlen($input['first_name']) > 50) {
           $errorMessage .= "<br>'First Name' is too long (50 characters max)!";
           $errors = true;            
       }
       if (strlen($input['last_name']) > 50) {
           $errorMessage .= "<br>'Last Name' is too long (50 characters max)!";
           $errors = true;            
       }
       if (strlen($input['email']) > 100) {
           $errorMessage .= "<br>'Email' is too long (100 characters max)!";
           $errors = true;            
       }
       if (strlen($input['password']) > 72) {
           $errorMessage .= "<br>'Password' is too long (72 characters max)!";
           $errors = true;            
       }
       if (strlen($input['password']) < 8) {
           $errorMessage .= "<br>'Password' is too short (8 characters min)!";
           $errors = true;            
       }

       // validate field contents
       if (empty($input['first_name'])) {
           $errorMessage .= "<br>'First Name' is required!";
           $errors = true;
       }
       if (empty($input['last_name'])) {
           $errorMessage .= "<br>'Last Name' is required!";
           $errors = true;
       }
       if (empty($input['email'])) {
           $errorMessage .= "<br>'Email' is required!";
           $errors = true;
       } else if (! filter_var($input['email'], FILTER_VALIDATE_EMAIL)) {
           $errorMessage .= "<br>Invalid email!";
           $errors = true;
       }
       if (empty($input['password'])) {
           $errorMessage .= "<br>'Password' is required!";
           $errors = true;
       }
       if (empty($input['repeat_password'])) {
           $errorMessage .= "<br>'Repeat Password' is required!";
           $errors = true;
       }
       if ($input['password'] !== $input['repeat_password']) {
           $errorMessage .= "<br>Passwords do not match!";
           $errors = true;
       }

       $this->errors = $errors;
       $this->errorMessage = $errorMessage;
   }
}

我們還需要將新方法registerUser()添加到OktaApiService類:

/src/services/OktaApiService.php

...
  public function registerUser($input)
   {
       $data['profile'] = [
           'firstName' => $input['first_name'],
           'lastName' => $input['last_name'],
           'email' => $input['email'],
           'login' => $input['email']
       ];
       $data['credentials'] = [
           'password' => [
               'value' => $input['password']
           ]
       ];
       $data = json_encode($data);

       $ch = curl_init($this->apiUrlBase . 'users');
       curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
       curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
       curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
       curl_setopt($ch, CURLOPT_HTTPHEADER, [
           'Accept: application/json',
           'Content-Type: application/json',
           'Content-Length: ' . strlen($data),
           'Authorization: SSWS ' . $this->apiToken
       ]);

       return curl_exec($ch);
   }
...

注冊(cè)成功后,第三個(gè)處理程序只在儀表板上顯示一條消息“感謝您的注冊(cè)”。

表單如下所示,代碼包括驗(yàn)證和錯(cuò)誤處理(屏幕截圖顯示提交空表單后的輸出):

 

如果轉(zhuǎn)到用戶>人員,您可以在Okta管理面板中看到新用戶。

通過(guò)Okta API忘記密碼

“忘記密碼”功能將遵循相同的模式:

/public/index.php中的新處理程序:

...

if (isset($_REQUEST['forgot'])) {
   view('forgot');
   die();
}

if (isset($_REQUEST['command']) && ($_REQUEST['command'] == 'forgot_password')) {
   $userController->handleForgotPasswordPost();
   die();
}

if (isset($_REQUEST['password_reset'])) {
   $data['thank_you'] = 'You should receive an email with password reset instructions';
}
...

單擊忘記密碼鏈接時(shí),第一個(gè)處理程序加載forgot視圖:

/src/views/forgot.php

<?php view('header', $data); ?>
<section class="hero">
   <div class="hero-body">
       <div class="container">
           <form method="post" action="/">

<?php
   if ($data && $data['errors']) {
?>
<div class="notification is-danger">
<?php
   echo "Errors:";
   echo $data['errorMessage'];
?>
</div>
<?php
   }
?>

<div class="field">
   <label class="label">Email</label>
   <div class="control">
       <input class="input" name="email" type="email" value="<?php if ($data) { echo $data['input']['email']; } ?>">
   </div>
</div>

<input type="hidden" name="command" value="forgot_password">

<div class="control">
   <button class="button is-link">Reset Password</button>
   <a class="button is-link" href="/">Cancel</a>
</div>

           </form>
       </div>
   </div>
</section>
<?php view('footer'); ?>

提交表單時(shí),第二個(gè)處理程序?qū)⑽薪o用戶控制器:

/src/controllers/UserController.php

...   public function handleForgotPasswordPost()    {       if ($_SERVER['REQUEST_METHOD'] === 'POST') {            $input = [                'email' => $_POST['email']            ];            // validate the email address            if (empty($input['email']) ||                strlen($input['email']) > 100 ||                (! filter_var($input['email'], FILTER_VALIDATE_EMAIL))) {                $viewData = [                    'input' => $input,                    'errors' => true,                    'errorMessage' => '
Invalid email!'                ];                view('forgot', $viewData);                return true;            }            // search for this user via the OktaApi            $result = $this->oktaApi->findUser($input);            $result = json_decode($result, true);            if (! isset($result[0]['id'])) {                $viewData = [                    'input' => $input,                    'errors' => true,                    'errorMessage' => '
User not found!'                ];                view('forgot', $viewData);                return true;            }            // attempt to send a reset link to this user            $userId = $result[0]['id'];            $result = $this->oktaApi->resetPassword($userId);            header('Location: /?password_reset');            return true;        }        header('HTTP/1.0 405 Method Not Allowed');        die();    } ...

控制器使用來(lái)自OktaApiService的兩種新方法:findUser()resetPassword()

/src/services/OktaApiService.php

...
  public function findUser($input)
   {
       $url = $this->apiUrlBase . 'users?q=' . urlencode($input['email']) . '&limit=1';
       $ch = curl_init($url);
       curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
       curl_setopt($ch, CURLOPT_HTTPHEADER, [
           'Accept: application/json',
           'Content-Type: application/json',
           'Authorization: SSWS ' . $this->apiToken
       ]);

       return curl_exec($ch);
   }

   public function resetPassword($userId)
   {
       $url = $this->apiUrlBase . 'users/' . $userId . '/lifecycle/reset_password';

       $ch = curl_init($url);
       curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
       curl_setopt($ch, CURLOPT_POSTFIELDS, []);
       curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
       curl_setopt($ch, CURLOPT_HTTPHEADER, [
           'Accept: application/json',
           'Content-Type: application/json',
           'Authorization: SSWS ' . $this->apiToken
       ]);

       return curl_exec($ch);
   }
...

第三個(gè)處理程序在觸發(fā)重置過(guò)程后在儀表板上顯示一條消息。

申請(qǐng)已經(jīng)完成了。您可以在Okta授權(quán)服務(wù)器中注冊(cè)新用戶,在Web應(yīng)用程序中對(duì)其進(jìn)行授權(quán),并遠(yuǎn)程觸發(fā)“重置密碼”例程。

像往常一樣,如果你有任何問(wèn)題,評(píng)論,或?qū)@篇文章的關(guān)注,請(qǐng)隨時(shí)在下面留下評(píng)論。