분류 php

PHP의 REST API 인증 예제 – JWT 자습서

컨텐츠 정보

  • 조회 464 (작성일 )

본문

이전에는 PHP에서 간단한 REST API를 만드는 방법을 배웠습니다. 데이터베이스 레코드 생성, 읽기, 업데이트 및 삭제 (CRUD 작업)는 우리 프로젝트에 유용했습니다.


오늘은 REST API와 JSON 웹 토큰 또는 JWT를 사용하여 사용자를 인증하는 방법을 배웁니다.


이 자습서에서는 기본 가입 또는 등록 양식, 로그인 및 로그 아웃 작업, 사용자 계정 업데이트 등을 다룹니다.


1.0 프로젝트 개요 

1.1 JWT 란?

1.2 JWT 간단한 비유

1.3 JWT는 어떻게 생겼습니까?

1.4 JWT와 OAuth


2.0 최종 출력


3.0 파일 구조 


4.0 데이터베이스 설정 

4.1 데이터베이스 생성

4.2 테이블 생성

4.3 구성을 위한 디렉토리 생성

4.4 데이터베이스 연결 파일 만들기


5.0 사용자 등록을 위한 API 생성 

5.1 사용자 생성을 위한 파일 생성

5.2 데이터베이스 및 사용자 테이블에 연결

5.3 제출 된 데이터를 개체 속성에 할당

5.4 create() 메서드 사용

5.5 사용자 개체 클래스 만들기

5.6 create() 메서드 추가

5.7 출력


6.0 사용자 로그인을 위한 API 생성

6.1 사용자 로그인을 위한 파일 생성

6.2 데이터베이스 및 사용자 테이블에 연결

6.3 이메일 존재 여부 확인

6.4 emailExists() 메서드 추가

6.5 JWT 인코딩을 위한 파일 포함

6.6 JSON 웹 토큰 생성

6.7 사용자 로그인 실패 알림

6.8 핵심 구성 파일 생성

6.9 GitHub에서 PHP-JWT 다운로드

6.10 출력


7.0 JWT 유효성 검사를 위한 API 생성 

7.1 JWT 유효성 검사를 위한 파일 생성

7.2 JWT 디코딩을 위한 파일 포함

7.3 주어진 JWT 검색

7.4 존재하는 경우 JWT 디코딩

7.5 디코딩 실패시 오류 표시

7.6 JWT가 비어 있는 경우 오류 메시지 표시

7.7 출력


8.0 사용자 계정 용 API 생성 

8.1 사용자 계정 업데이트를 위한 파일 생성

8.2 JWT 디코딩을 위한 파일 포함

8.3 데이터베이스 및 사용자 테이블에 연결

8.4 주어진 JWT 검색

8.5 JWT가 있는 경우 디코딩

8.6 디코딩 실패시 오류 메시지 표시

8.7 사용자 속성 값 설정

8.8 update() 메서드 사용

8.9 사용자 클래스에 update() 메서드 추가

8.10 JWT 재생성

8.11 JWT가 비어있는 경우 오류 메시지 표시

8.12 출력


9.0 사용자 등록을 위한 인터페이스 생성 

9.1 인덱스 페이지 생성

9.2 탐색 모음 추가

9.3 콘텐츠 섹션 추가

9.4 부트 스트랩 4 및 사용자 정의 CSS 링크 추가

9.5 사용자 지정 CSS 파일 만들기

9.6 jQuery 및 Bootstrap 4 스크립트 링크 추가

9.7 가입 HTML 양식 표시

9.8 가입 양식 제출시 트리거

9.9 프롬프트 메시지 제거

9.10 serializeObject() 함수 추가

9.11 출력


10.0 로그인 페이지 만들기 

10.1 로그인 메뉴 클릭시 트리거

10.2 로그인 HTML 양식 표시

10.3 setCookie() 함수 추가

10.4 메뉴 모양 변경

10.5 출력


11.0 로그인 응답 표시 

11.1 제출 된 양식 트리거

11.2 HTTP 요청 생성

11.3 홈 페이지 HTML 표시

11.4 홈 페이지 HTML 추가

11.5 getCookie() 함수 추가

11.6 유효하지 않은 로그인에 대한 오류 표시

11.7 출력


12.0 홈 메뉴 클릭시 

12.1 홈 페이지를 표시하는 트리거 추가

12.2 로그인 메뉴 설정

12.3 JWT가 유효하지 않은 경우 로그인 페이지 표시

12.4 출력


13.0 사용자 계정 페이지 표시 

13.1 계정 양식을 표시하는 트리거 추가

13.2 JWT가 유효한지 확인

13.3 JWT가 유효한 경우 계정 양식 표시

13.4 JWT가 유효하지 않은 경우 로그인 페이지 표시

13.5 사용자 계정 업데이트를 위한 트리거 추가

13.6 양식 데이터 및 JWT 가져 오기

13.7 API로 데이터 보내기

13.8 오류 메시지 표시

13.9 출력


14.0 사용자 로그 아웃을 위한 JavaScript 추가 

14.1 로그 아웃에 트리거 추가

14.2 출력


15.0 소스 코드 다운로드

16.0 다음은?

17.0 관련 튜토리얼

18.0 참고


https://codeofaninja.com/2018/09/rest-api-authentication-example-php-jwt-tutorial.html 


1.0 프로젝트 개요 


1.1 JWT 란? 


기술적인 측면에서 JSON 웹 토큰 또는 JWT는 당사자 간에 정보를 JSON 개체로 안전하게 전송하기 위한 컴팩트하고 독립적인 방법을 정의하는 개방형 표준 (RFC 7519)입니다.


이 정보는 디지털 서명이 되어 있으므로 확인하고 신뢰할 수 있습니다. JWT는 비밀 (HMAC 알고리즘 사용) 또는 RSA 또는 ECDSA를 사용하는 공개 / 개인 키 쌍을 사용하여 서명 할 수 있습니다.


  • JWT는 일반적으로 여러 응용 프로그램 또는 도메인이 있는 조직에 사용됩니다. 사용자는 한 번 인증 (로그인)하고 해당 조직의 여러 애플리케이션, 도메인 또는 리소스에 액세스 할 수 있는 권한을 부여 받아야 합니다.
  • JWT는 여러 서버를 사용하는 애플리케이션에도 사용됩니다.
  • 단일 서버 애플리케이션에서 사용자는 세션 ID로 권한을 부여 받을 수 있습니다. 서버는 모든 HTTP 요청에서 유효한 세션 ID를 찾아야 합니다 (조회를 통해). 세션 ID는 서버에 저장됩니다.
  • 애플리케이션을 확장해야 하고 여러 서버가 필요한 경우 사용자 권한 부여에 세션 ID를 사용할 수 없습니다. 모든 HTTP 요청은 세션 ID가 존재하지 않는 다른 서버로 라우팅 됩니다. 사용자는 예기치 않게 로그 아웃 됩니다.
  • JWT는 인증 된 사용자 정보를 서버가 아닌 클라이언트 측에 저장하여 다중 서버 인증 문제를 해결하는 데 도움이 됩니다. JWT는 모든 HTTP 요청에서 전송되며 애플리케이션에서 사용하는 모든 서버의 유효성을 (코드로) 확인할 수 있습니다.


여기여기에서 더 많은 것을 읽을 수 있습니다.


1.2 JWT 간단한 비유 


다음은 내 자신의 간단한 비유입니다. 더 나은 것이 있다고 생각되면 이메일로 알려주십시오. 제 이메일 주소는 mike@codeofaninja.com입니다.


  1. John (고객)은 학생입니다. Michael (서버)은 교수입니다. John은 자신의 테스트 문서 (로그인 자격 증명)를 Michael에게 보냅니다.
  2. Michael은 테스트 문서 (JWT)를 확인하고 확인하고 서명했습니다. 이것은 John이 Michael의 학생임을 증명합니다.
  3. Michael은 서명 된 테스트 용지 (JWT)를 John에게 보냅니다.
  4. John이 테스트 (HTTP 요청)에 대해 추가 질문이 있는 경우 서명 한 테스트 문서를 Michael에게 제시 할 수 있습니다.
  5. Michael은 시험지에 서명했기 때문에 대답 할 것입니다.
  6. 자, 이것이 유용한 부분입니다. Michael은 사용할 수 없습니다. Vincent (다른 서버)는 사용 가능한 교수입니다.
  7. John은 테스트 (HTTP 요청)에 대한 추가 질문이 있습니다. Vincent는 John이 Michael의 학생이라는 증거가 필요합니다.
  8. John은 서명 한 시험지 (JWT)를 Vincent에게 제출했습니다. Vincent는 Michael이 서명했기 때문에 (답변) 대답합니다.
  9. 시험지에 서명이 없으면 Michael과 Vincent는 John의 추가 질문에 대답하지 않습니다.

당신에게 유용 할 수 있는 또 다른 비유를 찾았습니다. 여기에서 읽으십시오.


아래 비디오는 비유를 설명하는 데 도움이 될 것입니다.





1.3 JWT는 어떻게 생겼습니까? 


JSON 웹 토큰 또는 JWT는 점으로 구분 된 세 부분이 있는 문자열처럼 보입니다. 다음은 JWT의 예입니다.


eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9leGFtcGxlLm9yZyIsImF1ZCI6Imh0dHA6XC9cL2V4YW1wbGUuY29tIiwiaWF0IjoxMzU2OTk5NTI0LCJuYmYiOjEzNTcwMDAwMDAsImRhdGEiOnsiaWQiOiI5IiwiZmlyc3RuYW1lIjoiTWlrZSIsImxhc3RuYW1lIjoiRGFsaXNheSIsImVtYWlsIjoibWlrZUBjb2Rlb2ZhbmluamEuY29tIn19.h_Q4gJ3epcpwdwNCNCYxtiKdXsN34W9MEjxZ7sx21Vs


직렬화 된 형식의 JWT는 다음 형식의 문자열을 나타냅니다.


header.payload.signature 


헤더 구성 요소에는 JWT 서명을 계산하는 방법에 대한 정보가 포함되어 있습니다. 페이로드 구성 요소는 JWT 내부에 저장되는 데이터입니다. 이것은 사용자 ID, 이름 및 이메일과 같은 사용자 정보 일 수 있습니다.


서명 구성 요소를 생성하려면 인코딩 된 헤더, 인코딩 된 페이로드, 비밀, 헤더에 지정된 알고리즘을 가져 와서 서명해야 합니다.


이 튜토리얼에서는 PHP-JWT라는 라이브러리를 사용할 것이기 때문에 JWT 생성, 인코딩 및 디코딩에 대해 걱정할 필요가 없습니다.


1.4 JWT와 OAuth 


위의 JWT를 설명했습니다. JWT는 토큰 형식이며 간단한 인증 프로토콜이라고 말할 수 있습니다. OAuth는 JWT를 토큰으로 사용할 수 있는 인증 프레임 워크입니다.

OAuth는 인터넷 사용자가 웹 사이트 또는 애플리케이션이 다른 웹 사이트의 정보에 액세스 할 수 있도록 허용하지만 비밀번호는 제공하지 않는 방법으로 사용됩니다.


다음과 같은 경우 JWT를 사용합니다.

  • 단일 클라이언트 애플리케이션과 같은 매우 간단한 사용 사례가 있습니다.
  • 사용자는 자신의 애플리케이션을 통해서만 리소스에 액세스합니다.
  • API에 대한 구현이 빠르고 간단한 상태 비 저장 HTTP 인증을 원합니다.

다음과 같은 경우 OAuth를 사용합니다.

  • 사용자는 소유하지 않은 다른 애플리케이션을 통해 리소스에 액세스 할 수 있습니다.
  • 브라우저 기반 앱, 기본 모바일 앱 또는 데스크톱 앱에 API를 제공하려고 합니다.
  • 토큰을 추적하는 인증 서버를 사용하려고 합니다.

여기여기에서 더 많은 것을 읽으십시오.


2.0 최종 출력 


2.1 LEVEL 1 소스 코드 출력 


이 튜토리얼에서 달성하고자 하는 것을 시각화 하는 것이 중요합니다. 이 튜토리얼이 끝나면 아래 스크린 샷에서 볼 수 있는 레벨 1 소스 코드를 얻을 수 있습니다.


확대하려면 아래 사진을 클릭하고 슬라이드 쇼를 탐색하려면 화살표 아이콘을 사용하십시오.


1-home-page-not-logged-in.jpg?fit=1022%2C627&ssl=1 

2.2 LEVEL 2 소스 코드 출력 


곧 스크린 샷이 제공됩니다! 아래 섹션 14.2의 기능 목록을 참조하십시오.


LEVEL 2 소스 코드는 LEVEL 1 소스 코드 공부를 마치면 배울 수 있는 더 놀라운 기능을 보여줍니다.


지금은 아래의 LEVEL 1 소스 코드에 대한 전체 자습서를 진행하겠습니다. 코딩하자!


3.0 파일 구조 


이 튜토리얼이 끝나면 다음과 같은 폴더와 파일을 갖게 됩니다.


├─ rest-api-authentication-example/ - name of the project folder.
├─── api/ - main folder of the API.
├────── config/
├───────── core.php - file used for common settings or variables.
├───────── database.php - file used for connecting to the database.
├────── libs/
├───────── php-jwt-master/ - folder of the JWT library developed by Google.
├────── objects/
├───────── user.php - the class file that will handle the database queries.
├────── create_user.php - the file that will process the input of from "sign up" form.
├────── login.php - the file that will encode and generate a JSON web token.
├────── update_user.php - the file that will process the input of from "user account" form.
├────── validate_token.php - the file that will validate or decode the JSON web token.
├─── custom.css - contains any customization in the user interface.
├─── index.html - contains HTML and JavaScript that renders different user interfaces. 



4.0 데이터베이스 설정 


4.1 데이터베이스 생성 


  • PhpMyAdmin localhost/phpmyadmin을 엽니다.
  • api_db라는 데이터베이스 만들기

4.2 테이블 생성 


  • api_db 데이터베이스에서 users라는 새 테이블을 만듭니다.
  • 사용자 테이블에 다음 필드를 입력하십시오.

users-table-fields.jpg?resize=1084%2C230&ssl=1 

4.3 구성을 위한 디렉토리 생성 


  • 주 프로젝트 폴더를 만들고 rest-api-authentication-example을 이름으로 입력합니다.
  • XAMPP를 사용하는 경우 htdocs 폴더 내에 만들어야 합니다. 제 경우에는 C:\xampp\htdocs 디렉토리 내에 만들었습니다.
  • rest-api-authentication-example 폴더를 엽니다.
  • API 폴더를 만듭니다.
  • api 폴더를 엽니다.
  • config 폴더를 만듭니다.

4.4 데이터베이스 연결 파일 만들기 


  • config 폴더를 엽니다.
  • database.php라는 새 파일을 만듭니다.

다음 코드를 넣으십시오.


<?php
// used to get mysql database connection
class Database{
 
    // specify your own database credentials
    private $host = "localhost";
    private $db_name = "api_db";
    private $username = "root";
    private $password = "";
    public $conn;
 
    // get the database connection
    public function getConnection(){
 
        $this->conn = null;
 
        try{
            $this->conn = new PDO("mysql:host=" . $this->host . ";dbname=" . $this->db_name, $this->username, $this->password);
        }catch(PDOException $exception){
            echo "Connection error: " . $exception->getMessage();
        }
 
        return $this->conn;
    }
}
?>


5.0 사용자 등록을 위한 API 생성 


5.1 사용자 생성을 위한 파일 생성 


  • rest-api-authentication-example 폴더를 엽니다.
  • api라는 폴더를 만듭니다.
  • api 폴더를 엽니다.
  • create_user.php라는 새 파일을 만듭니다.

이 새 파일에 특정 URL의 JSON 데이터 만 허용하도록 헤더를 설정해야 합니다. 다음 코드를 넣으십시오.


<?php
// required headers
header("Access-Control-Allow-Origin: http://localhost/rest-api-authentication-example/");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
 
// database connection will be here


5.2 데이터베이스 및 사용자 테이블에 연결 


사용자 등록 정보를 데이터베이스에 저장하고 있으므로 데이터베이스 연결이 필요합니다. 나중에 insert 쿼리를 만들기 때문에 user 테이블도 인스턴스화해야합니다.


// 데이터베이스 연결은 다음 코드로 create_user.php 파일의 주석입니다.


// files needed to connect to database
include_once 'config/database.php';
include_once 'objects/user.php';
 
// get database connection
$database = new Database();
$db = $database->getConnection();
 
// instantiate product object
$user = new User($db);
 
// submitted data will be here


5.3 제출 된 데이터를 개체 속성에 할당 


사용자 정보는 HTML 양식과 JavaScript 코드를 통해 제출됩니다. 이 코드는 나중에 볼 것입니다.


제출 된 데이터를 이름, 성 등과 같은 개체 속성에 할당해야 합니다.


// 제출 된 데이터는 여기에서 create_user.php 파일의 주석이 다음 코드로 바뀝니다.


// get posted data
$data = json_decode(file_get_contents("php://input"));
 
// set product property values
$user->firstname = $data->firstname;
$user->lastname = $data->lastname;
$user->email = $data->email;
$user->password = $data->password;
 
// use the create() method here


5.4 create() 메서드 사용 


아래 코드 중 하나는 사용자 데이터가 비어 있지 않은지 확인합니다. 또한 사용자 개체의 create() 메서드를 사용합니다. 사용자가 생성되었는지 여부를 사용자에게 알려줍니다.


// 여기서 create_user.php 파일의 create() 메서드를 다음 코드로 바꿉니다.


// create the user
if(
    !empty($user->firstname) &&
    !empty($user->email) &&
    !empty($user->password) &&
    $user->create()
){
 
    // set response code
    http_response_code(200);
 
    // display message: user was created
    echo json_encode(array("message" => "User was created."));
}
 
// message if unable to create user
else{
 
    // set response code
    http_response_code(400);
 
    // display message: unable to create user
    echo json_encode(array("message" => "Unable to create user."));
}
?>


5.5 사용자 개체 클래스 만들기 


이전 섹션은 사용자 개체 클래스 없이는 작동하지 않습니다. 여기에서 데이터베이스 쿼리를 포함하는 모든 user 메서드를 배치합니다.


개인 또는 공용 범위에 익숙하지 않은 경우 이 리소스에서 배우십시오.

  • api 폴더를 엽니다.
  • objects 폴더를 엽니다.
  • user.php라는 새 파일을 만듭니다.
  • 다음 코드를 넣으십시오.
<?php
// 'user' object
class User{
 
    // database connection and table name
    private $conn;
    private $table_name = "users";
 
    // object properties
    public $id;
    public $firstname;
    public $lastname;
    public $email;
    public $password;
 
    // constructor
    public function __construct($db){
        $this->conn = $db;
    }
 
// create() method will be here
}



5.6 create() 메서드 추가 


아래 코드는 INSERT 쿼리, 데이터 위생 및 바인딩을 보여 주며, 데이터베이스에서 사용자의 암호를 보호하기 위해 내장 된 password_hash() 메서드를 사용했습니다.


실행이 성공하면 사용자 정보가 데이터베이스에 저장됩니다.


// create() 메서드를 user.php 파일의 주석으로 대체합니다.


// create new user record
function create(){
 
    // insert query
    $query = "INSERT INTO " . $this->table_name . "
            SET
                firstname = :firstname,
                lastname = :lastname,
                email = :email,
                password = :password";
 
    // prepare the query
    $stmt = $this->conn->prepare($query);
 
    // sanitize
    $this->firstname=htmlspecialchars(strip_tags($this->firstname));
    $this->lastname=htmlspecialchars(strip_tags($this->lastname));
    $this->email=htmlspecialchars(strip_tags($this->email));
    $this->password=htmlspecialchars(strip_tags($this->password));
 
    // bind the values
    $stmt->bindParam(':firstname', $this->firstname);
    $stmt->bindParam(':lastname', $this->lastname);
    $stmt->bindParam(':email', $this->email);
 
    // hash the password before saving to database
    $password_hash = password_hash($this->password, PASSWORD_BCRYPT);
    $stmt->bindParam(':password', $password_hash);
 
    // execute the query, also check if query was successful
    if($stmt->execute()){
        return true;
    }
 
    return false;
}
 
// emailExists() method will be here


5.7 출력 


API를 테스트하려면 POSTMAN을 사용해야 합니다. 여기에서 POSTMAN 버전을 다운로드하십시오.


  • 먼저 사용자가 성공적으로 생성되었는지 테스트합니다.
  • POSTMAN을 시작합니다.
  • 요청 URL로 다음을 입력하십시오.


  • "Body"탭을 클릭하십시오.
  • "raw"를 클릭하십시오.
  • 다음 JSON을 입력하십시오.
{
 "firstname" : "Mike",
 "lastname" : "Dalisay",
 "email" : "mike@codeofaninja.com",
 "password" : "555"
}


  • 파란색 "Send"버튼을 클릭합니다. 출력은 다음과 같습니다.


{
    "message": "User was created."
}


  • POSTMAN에서는 다음과 같이 표시됩니다.

user-was-created-2.jpg?resize=1452%2C693&ssl=1 


  • 사용자 생성에 실패했는지 테스트하려면 위의 비밀번호 값을 제거하면 됩니다.
  • 파란색 "Send"버튼을 클릭합니다.
  • 다음과 같이 표시되어야 합니다.

unable-to-create-user-3.jpg?resize=1448%2C701&ssl=1 


6.0 사용자 로그인을 위한 API 생성 


6.1 사용자 로그인을 위한 파일 생성 


아래 코드에서 요청이 어디에서 왔는지, 어떤 유형의 데이터가 허용되는지 알 수 있도록 파일 헤더를 설정했습니다.

  • rest-api-authentication-example 폴더를 엽니다.
  • login.php라는 새 파일을 만듭니다.
  • 다음 코드를 넣으십시오.
<?php
// required headers
header("Access-Control-Allow-Origin: http://localhost/rest-api-authentication-example/");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
 
// database connection will be here


6.2 데이터베이스 및 사용자 테이블에 연결 


데이터베이스의 사용자 이메일과 비밀번호를 비교하므로 데이터베이스 연결이 필요합니다.


이메일이 존재하는지 확인하고 해시 된 암호를 읽을 수 있도록 사용자 테이블도 인스턴스화해야합니다.


// 데이터베이스 연결은 여기에 login.php 파일의 주석이 다음 코드로 바뀝니다.

// files needed to connect to database
include_once 'config/database.php';
include_once 'objects/user.php';
 
// get database connection
$database = new Database();
$db = $database->getConnection();
 
// instantiate user object
$user = new User($db);
 
// check email existence here


6.3 이메일 존재 여부 확인 


아래 코드에서 사용자가 로그인 양식을 통해 제출 한 이메일을 받습니다. 이메일이 데이터베이스에 있는지 확인합니다.


// login.php 파일의 이메일 존재 확인 주석을 다음 코드로 바꿉니다.


// get posted data
$data = json_decode(file_get_contents("php://input"));
 
// set product property values
$user->email = $data->email;
$email_exists = $user->emailExists();
 
// files for jwt will be here


6.4 emailExists() 메서드 추가 


사용자 객체 클래스에 emailExists() 메서드를 추가합니다. 이 메서드는 제출 된 이메일이 있으면 true를 반환하고 그렇지 않으면 false를 반환합니다.


// emailExists() 메서드를 다음 코드로 /api/objects/user.php 파일의 주석으로 대체합니다.


// check if given email exist in the database
function emailExists(){
 
    // query to check if email exists
    $query = "SELECT id, firstname, lastname, password
            FROM " . $this->table_name . "
            WHERE email = ?
            LIMIT 0,1";
 
    // prepare the query
    $stmt = $this->conn->prepare( $query );
 
    // sanitize
    $this->email=htmlspecialchars(strip_tags($this->email));
 
    // bind given email value
    $stmt->bindParam(1, $this->email);
 
    // execute the query
    $stmt->execute();
 
    // get number of rows
    $num = $stmt->rowCount();
 
    // if email exists, assign values to object properties for easy access and use for php sessions
    if($num>0){
 
        // get record details / values
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
 
        // assign values to object properties
        $this->id = $row['id'];
        $this->firstname = $row['firstname'];
        $this->lastname = $row['lastname'];
        $this->password = $row['password'];
 
        // return true because email exists in the database
        return true;
    }
 
    // return false if email does not exist in the database
    return false;
}
 
// update() method will be here


6.5 JWT 인코딩을 위한 파일 포함 


아래 코드는 JSON 웹 토큰을 생성하거나 인코딩하기 위해 포함해야 하는 필수 파일을 보여줍니다.


// 파일을 jwt로 바꾸면 여기에 login.php 파일의 주석이 다음 코드로 표시됩니다.


// generate json web token
include_once 'config/core.php';
include_once 'libs/php-jwt-master/src/BeforeValidException.php';
include_once 'libs/php-jwt-master/src/ExpiredException.php';
include_once 'libs/php-jwt-master/src/SignatureInvalidException.php';
include_once 'libs/php-jwt-master/src/JWT.php';
use \Firebase\JWT\JWT;
 
// generate jwt will be here


6.6 JSON 웹 토큰 생성 


아래 코드는 이메일이 존재하는지 그리고 암호가 데이터베이스에 있는 것과 일치하는지 확인합니다. 내장 된 password_verify () 함수를 사용하여 일치를 수행했습니다.


로그인이 유효하면 JSON 웹 토큰을 생성합니다.


// generate jwt는 login.php 파일의 주석이 다음 코드로 대체됩니다.


// check if email exists and if password is correct
if($email_exists && password_verify($data->password, $user->password)){
 
    $token = array(
       "iat" => $issued_at,
       "exp" => $expiration_time,
       "iss" => $issuer,
       "data" => array(
           "id" => $user->id,
           "firstname" => $user->firstname,
           "lastname" => $user->lastname,
           "email" => $user->email
       )
    );
 
    // set response code
    http_response_code(200);
 
    // generate jwt
    $jwt = JWT::encode($token, $key);
    echo json_encode(
            array(
                "message" => "Successful login.",
                "jwt" => $jwt
            )
        );
 
}
 
// login failed will be here


6.7 사용자 로그인 실패 알림 


이메일이 존재하지 않거나 비밀번호가 일치하지 않으면 사용자에게 로그인 할 수 없다고 알립니다.


// 로그인 실패는 다음 코드로 login.php 파일의 주석입니다.


// login failed
else{
 
    // set response code
    http_response_code(401);
 
    // tell the user login failed
    echo json_encode(array("message" => "Login failed."));
}
?>


6.8 핵심 구성 파일 생성 


login.php 파일은 core.php 파일 없이는 작동하지 않습니다. 이 파일에는 애플리케이션의 공통 설정 또는 변수가 포함되어 있습니다.


토큰을 인코딩하고 디코딩 하기 위해 JWT 라이브러리에서 사용하는 변수가 있습니다. $key의 값은 고유하고 고유 한 비밀 키 여야 합니다.


나머지는 등록 된 클레임 이름이라고 합니다. iss (발급자) 클레임은 JWT를 발행 한 주체를 식별합니다.


aud (audience) 클레임은 JWT가 대상으로 하는 수신자를 식별합니다. iat (issued at) 클레임은 JWT가 발행 된 시간을 식별합니다.


nbf (이전 아님) 클레임은 JWT가 처리를 위해 허용되지 않아야 하는 시간을 식별합니다.


JWT가 처리를 위해 허용되지 않아야 하는 만료 시간 또는 그 이후의 만료 시간을 식별하는 exp (만료 시간)라는 또 다른 유용한 클레임 이름을 사용할 수 있습니다.


이러한 클레임을 포함하는 것은 선택 사항입니다. 여기에서 등록 된 클레임 이름에 대해 자세히 읽어보십시오.


  • api 폴더를 엽니다.
  • config 폴더를 엽니다.
  • core.php라는 새 파일을 만듭니다.
  • 다음 코드를 넣으십시오.
<?php
// show error reporting
error_reporting(E_ALL);
 
// set your default time-zone
date_default_timezone_set('Asia/Manila');
 
// variables used for jwt
$key = "example_key";
$issued_at = time();
$expiration_time = $issued_at + (60 * 60); // valid for 1 hour
?>


6.9 GitHub에서 PHP-JWT 다운로드 


login.php 파일에 포함 된 파일은 이 라이브러리 없이는 작동하지 않습니다.


  • 이 링크에서 라이브러리를 다운로드하십시오.
  • libs 폴더를 만듭니다.
  • 다운로드 한 라이브러리의 압축을 풉니다.
  • 위의 파일 구조가 어떻게 생겼는지 확인하십시오.


6.10 출력 


성공적인 로그인을 테스트하려면 요청 URL로 다음을 입력하십시오.



  • 본문에 다음을 입력하십시오.


{
 "email" : "mike@codeofaninja.com",
 "password" : "555"
}


  • 나중에 리소스에 액세스하는 데 사용할 것이므로 생성 된 JWT를 기록해 두어야 합니다.

successful-login-1.jpg?resize=1450%2C777&ssl=1 


  • 로그인 실패를 테스트하려면 잘못된 비밀번호이므로 비밀번호 값을 111로 변경하십시오.

failed-login-1.jpg?resize=1446%2C793&ssl=1 


7.0 JWT 유효성 검사를 위한 API 생성 


7.1 JWT 유효성 검사를 위한 파일 생성 


이 파일은 JSON 형식으로 출력을 반환하고 지정된 URL의 요청을 수락합니다. 올바른 헤더를 설정하겠습니다.


  • api 폴더를 엽니다.
  • validate_token.php 파일을 생성합니다.
  • 다음 코드를 넣으십시오.
<?php
// required headers
header("Access-Control-Allow-Origin: http://localhost/rest-api-authentication-example/");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
 
// files for decoding jwt will be here


7.2 JWT 디코딩을 위한 파일 포함 


아래 코드는 주어진 JSON 웹 토큰을 디코딩 하는 데 필요한 파일이 포함되어 있음을 보여줍니다.


// jwt 디코딩을 위한 파일을 다음 코드로 validate_token.php 파일의 주석으로 교체합니다.


// required to decode jwt
include_once 'config/core.php';
include_once 'libs/php-jwt-master/src/BeforeValidException.php';
include_once 'libs/php-jwt-master/src/ExpiredException.php';
include_once 'libs/php-jwt-master/src/SignatureInvalidException.php';
include_once 'libs/php-jwt-master/src/JWT.php';
use \Firebase\JWT\JWT;
 
// retrieve gieve jwt here


7.3 주어진 JWT 검색 


아래 코드는 JSON 웹 토큰의 값을 가져 오는 방법을 보여줍니다.


// validate_token.php 파일의 gieve jwt 주석을 다음 코드로 바꿉니다.


// get posted data
$data = json_decode(file_get_contents("php://input"));
 
// get jwt
$jwt=isset($data->jwt) ? $data->jwt : "";
 
// decode jwt here


7.4 존재하는 경우 JWT 디코딩 


JWT가 주어 졌는지 확인하십시오. 참이면 디코딩 하십시오. 응답 코드 200을 반환하고 사용자 액세스가 허용되고 일부 사용자 정보를 알립니다.


// validate_token.php 파일의 jwt 디코딩 주석을 다음 코드로 바꿉니다.


// if jwt is not empty
if($jwt){
 
    // if decode succeed, show user details
    try {
        // decode jwt
        $decoded = JWT::decode($jwt, $key, array('HS256'));
 
        // set response code
        http_response_code(200);
 
        // show user details
        echo json_encode(array(
            "message" => "Access granted.",
            "data" => $decoded->data
        ));
 
    }
 
    // catch will be here
}
 
// error if jwt is empty will be here


7.5 디코딩 실패시 오류 표시 


JWT 디코딩에 실패하면 리소스에 대한 액세스가 거부되었음을 의미합니다. 응답 코드 401을 반환하고 사용자 액세스가 거부되었으며 오류에 대한 일부 정보를 알려야 합니다.


// catch는 validate_token.php 파일의 주석을 다음 코드로 교체합니다.


// if decode fails, it means jwt is invalid
catch (Exception $e){
 
    // set response code
    http_response_code(401);
 
    // tell the user access denied  & show error message
    echo json_encode(array(
        "message" => "Access denied.",
        "error" => $e->getMessage()
    ));
}


7.6 JWT가 비어있는 경우 오류 메시지 표시 


JWT가 비어 있으면 액세스도 거부되었음을 의미합니다. 응답 코드 401을 반환하고 사용자 액세스가 거부되었음을 알려야 합니다.


// jwt가 비어있는 경우 오류를 교체하면 validate_token.php 파일의 주석이 다음 코드로 표시됩니다.


// show error message if jwt is empty
else{
 
    // set response code
    http_response_code(401);
 
    // tell the user access denied
    echo json_encode(array("message" => "Access denied."));
}
?>


7.7 출력 


  • 성공적인 액세스를 테스트하려면 다음 요청 URL을 입력하십시오.



  • 앞서 검색 한 JSON 웹 토큰을 입력합니다. 아래의 JSON 웹 토큰은 귀하의 것과 다릅니다. 컴퓨터에서 JWT가 생성되었는지 확인하십시오.
{
    "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9leGFtcGxlLm9yZyIsImF1ZCI6Imh0dHA6XC9cL2V4YW1wbGUuY29tIiwiaWF0IjoxMzU2OTk5NTI0LCJuYmYiOjEzNTcwMDAwMDAsImRhdGEiOnsiaWQiOiI5IiwiZmlyc3RuYW1lIjoiTWlrZSIsImxhc3RuYW1lIjoiRGFsaXNheSIsImVtYWlsIjoibWlrZUBjb2Rlb2ZhbmluamEuY29tIn19.h_Q4gJ3epcpwdwNCNCYxtiKdXsN34W9MEjxZ7sx21Vs"
}


  • POSTMAN에서 다음과 같이 보일 것입니다.

access-granted.jpg?resize=1449%2C795&ssl=1 


  • 실패한 액세스를 테스트하려면 JWT에 "EDITED"라는 단어를 입력하십시오. 이것은 JWT를 잘못 만들 것입니다. 액세스가 거부됩니다.
  • 다음과 같이 보일 것입니다.

access-denied.jpg?resize=1449%2C707&ssl=1 


8.0 사용자 계정을 위한 API 생성 


8.1 사용자 계정 업데이트를 위한 파일 생성 


이 파일은 JSON 형식으로 출력을 반환하고 지정된 URL의 요청을 수락합니다. 올바른 헤더를 설정하겠습니다.


  • api 폴더를 엽니다.
  • update_user.php 파일을 생성합니다.
  • 다음 코드를 넣으십시오.
<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
 
// files for decoding jwt will be here


8.2 JWT 디코딩을 위한 파일 포함 


아래 코드는 주어진 JSON 웹 토큰을 디코딩 하는 데 필요한 파일이 포함되어 있음을 보여줍니다.


// jwt 디코딩을 위한 파일을 다음 코드로 update_user.php 파일의 주석으로 대체합니다.


// required to encode json web token
include_once 'config/core.php';
include_once 'libs/php-jwt-master/src/BeforeValidException.php';
include_once 'libs/php-jwt-master/src/ExpiredException.php';
include_once 'libs/php-jwt-master/src/SignatureInvalidException.php';
include_once 'libs/php-jwt-master/src/JWT.php';
use \Firebase\JWT\JWT;
 
// database connection will be here


8.3 데이터베이스 및 사용자 테이블에 연결 


데이터베이스에서 사용자 정보를 업데이트해야 합니다. 그렇기 때문에 데이터베이스 연결이 필요합니다.


// 데이터베이스 연결은 다음 코드로 update_user.php 파일의 주석입니다.


// files needed to connect to database
include_once 'config/database.php';
include_once 'objects/user.php';
 
// get database connection
$database = new Database();
$db = $database->getConnection();
 
// instantiate user object
$user = new User($db);
 
// retrieve given jwt here


8.4 주어진 JWT 검색 


아래 코드는 주어진 JSON 웹 토큰의 값을 얻는 방법을 보여줍니다.


// update_user.php 파일의 jwt 주석을 다음 코드로 교체하십시오.


// get posted data
$data = json_decode(file_get_contents("php://input"));
 
// get jwt
$jwt=isset($data->jwt) ? $data->jwt : "";
 
// decode jwt here


8.5 JWT가 있는 경우 디코딩 


JWT가 주어 졌는지 확인하십시오. 참이면 try 블록 내에서 디코딩 합니다.


// decode jwt here update_user.php 파일의 주석을 다음 코드로 바꿉니다.


// if jwt is not empty
if($jwt){
 
    // if decode succeed, show user details
    try {
 
        // decode jwt
        $decoded = JWT::decode($jwt, $key, array('HS256'));
 
        // set user property values here
    }
 
    // catch failed decoding will be here
}
 
// error message if jwt is empty will be here


8.6 디코딩 실패시 오류 메시지 표시 


JWT 디코딩이 실패하면 응답 코드 401을 설정하고 사용자 액세스가 거부되었음을 알리고 오류에 대한 정보를 표시해야 합니다.


// catch 실패 디코딩은 다음 코드로 update_user.php 파일의 주석입니다.


// if decode fails, it means jwt is invalid
catch (Exception $e){
 
    // set response code
    http_response_code(401);
 
    // show error message
    echo json_encode(array(
        "message" => "Access denied.",
        "error" => $e->getMessage()
    ));
}


8.7 사용자 속성 값 설정 


제출 된 데이터 (HTML 양식을 통해)를 사용자 개체 속성으로 설정해야 합니다.


update_user.php 파일의 주석 // set user property values ​​here을 다음 코드로 바꿉니다.


// set user property values
$user->firstname = $data->firstname;
$user->lastname = $data->lastname;
$user->email = $data->email;
$user->password = $data->password;
$user->id = $decoded->data->id;
 
// update user will be here


8.8 update() 메서드 사용 


아래 코드 중 하나는 사용자 객체의 create() 메서드를 사용합니다. true를 반환하면 사용자가 업데이트 되었음을 ​​의미합니다. false를 반환하면 시스템이 사용자 정보를 업데이트 할 수 없습니다.


// update user는 update_user.php 파일의 주석이 다음 코드로 대체됩니다.


// update the user record
if($user->update()){
    // regenerate jwt will be here
}
 
// message if unable to update user
else{
    // set response code
    http_response_code(401);
 
    // show error message
    echo json_encode(array("message" => "Unable to update user."));
}


8.9 사용자 클래스에 update() 메서드 추가 


아래 코드는 UPDATE 쿼리, 데이터 위생 및 바인딩을 보여줍니다.


HTML 형식으로 암호를 입력 한 경우 내장 된 password_hash() 메서드를 사용하여 데이터베이스에서 사용자의 암호를 보호합니다.


실행이 성공하면 데이터베이스에서 사용자 정보가 업데이트 됩니다.


// update() 메서드를 api / objects / user.php 파일의 주석으로 대체합니다.


// update a user record
public function update(){
 
    // if password needs to be updated
    $password_set=!empty($this->password) ? ", password = :password" : "";
 
    // if no posted password, do not update the password
    $query = "UPDATE " . $this->table_name . "
            SET
                firstname = :firstname,
                lastname = :lastname,
                email = :email
                {$password_set}
            WHERE id = :id";
 
    // prepare the query
    $stmt = $this->conn->prepare($query);
 
    // sanitize
    $this->firstname=htmlspecialchars(strip_tags($this->firstname));
    $this->lastname=htmlspecialchars(strip_tags($this->lastname));
    $this->email=htmlspecialchars(strip_tags($this->email));
 
    // bind the values from the form
    $stmt->bindParam(':firstname', $this->firstname);
    $stmt->bindParam(':lastname', $this->lastname);
    $stmt->bindParam(':email', $this->email);
 
    // hash the password before saving to database
    if(!empty($this->password)){
        $this->password=htmlspecialchars(strip_tags($this->password));
        $password_hash = password_hash($this->password, PASSWORD_BCRYPT);
        $stmt->bindParam(':password', $password_hash);
    }
 
    // unique ID of record to be edited
    $stmt->bindParam(':id', $this->id);
 
    // execute the query
    if($stmt->execute()){
        return true;
    }
 
    return false;
}


8.10 JWT 재생성 


특히 사용자 정보가 변경된 경우 새 JSON 웹 토큰을 다시 생성하거나 가져와야 합니다. 아래 코드는 이를 수행하고 응답 코드를 200으로 설정하고 사용자에게 정보가 업데이트 되었음을 ​​알려줍니다.


// regenerate jwt는 update_user.php 파일의 주석이 다음 코드로 대체됩니다.


// we need to re-generate jwt because user details might be different
$token = array(
   "iat" => $issued_at,
   "exp" => $expiration_time,
   "iss" => $issuer,
   "data" => array(
       "id" => $user->id,
       "firstname" => $user->firstname,
       "lastname" => $user->lastname,
       "email" => $user->email
   )
);
$jwt = JWT::encode($token, $key);
 
// set response code
http_response_code(200);
 
// response in json format
echo json_encode(
        array(
            "message" => "User was updated.",
            "jwt" => $jwt
        )
    );



8.11 JWT가 비어있는 경우 오류 메시지 표시 


JWT가 존재하지 않으면 액세스가 거부되었음을 사용자에게 알려야 합니다. 응답 코드 401도 설정했습니다.


JWT가 비어 있으면 // 오류 메시지를 다음 코드로 update_user.php 파일의 주석으로 대체합니다.


// show error message if jwt is empty
else{
 
    // set response code
    http_response_code(401);
 
    // tell the user access denied
    echo json_encode(array("message" => "Access denied."));
}
?>


8.12 출력 


  • 성공적인 사용자 업데이트를 테스트하려면 POSTMAN의 요청 URL로 다음을 입력하십시오.



  • 본문 섹션에서 이전에 검색 한 JSON 웹 토큰으로 새 사용자 정보를 입력합니다.
  • 아래의 JSON 웹 토큰은 귀하의 것과 다릅니다. 컴퓨터에서 JWT가 생성되었는지 확인하십시오.
{
    "firstname" : "Mike",
    "lastname" : "Dalisay",
    "email" : "mike@codeofaninja.com",
    "password" : "555",
    "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9leGFtcGxlLm9yZyIsImF1ZCI6Imh0dHA6XC9cL2V4YW1wbGUuY29tIiwiaWF0IjoxMzU2OTk5NTI0LCJuYmYiOjEzNTcwMDAwMDAsImRhdGEiOnsiaWQiOiI5IiwiZmlyc3RuYW1lIjoiVmluY2UiLCJsYXN0bmFtZSI6IkRhbGlzYXkiLCJlbWFpbCI6Im1pa2VAY29kZW9mYW5pbmphLmNvbSJ9fQ.3Sv65TVYACkNPo4HMr4NvreyZY16wxG-nSorLi_jykI"
}


  • POSTMAN에서 다음과 같이 보일 것입니다.

user-was-updated.jpg?resize=1448%2C763&ssl=1 


  • 위 이미지에서 볼 수 있듯이 새 JWT를 생성하고 클라이언트 애플리케이션에 저장됩니다. 나중에 앱 인터페이스에서 새 정보를 사용할 수 있습니다.
  • 실패한 사용자 업데이트를 테스트하려면 제출 된 JWT에 EDITED라는 단어를 추가하거나 JWT를 제거하면 됩니다. 다음과 같이 보일 것입니다.

unable-to-update-user-access-denied.jpg?resize=1446%2C791&ssl=1 

9.0 사용자 등록을 위한 인터페이스 생성 


9.1 인덱스 페이지 생성 


HTML, CSS 및 JavaScript를 사용하여 만든 간단한 SPA (단일 페이지 응용 프로그램)에서 앞서 만든 API를 사용합니다.


모든 필수 코드는 이 단일 index.html 파일에 있습니다.

  • rest-api-authentication-example 폴더를 엽니 다.
  • index.html 파일을 만듭니다.
  • 다음 코드를 넣으십시오.
<!doctype html>
<html lang="en">
    <head>
        <!-- Required meta tags -->
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
 
        <title>Rest API Authentication Example</title>
 
        <!-- CSS links will be here -->
 
    </head>
<body>
 
<!-- navigation bar will be here -->
 
<!-- script links will be here -->
 
</body>
</html>


9.2 탐색 모음(navigation bar) 추가


내비게이션 바는 홈 페이지, 계정 페이지, 로그인 페이지, 로그 아웃 및 가입 페이지와 같은 메뉴를 클릭하거나 트리거 할 수 있는 곳입니다.


index.html 파일의 <!-탐색 모음이 여기에 있습니다-> 주석을 다음 코드로 바꿉니다.


<!-- navbar -->
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
    <a class="navbar-brand" href="#">Navbar</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarNavAltMarkup">
        <div class="navbar-nav">
            <a class="nav-item nav-link" href="#" id='home'>Home</a>
            <a class="nav-item nav-link" href="#" id='update_account'>Account</a>
            <a class="nav-item nav-link" href="#" id='logout'>Logout</a>
            <a class="nav-item nav-link" href="#" id='login'>Login</a>
            <a class="nav-item nav-link" href="#" id='sign_up'>Sign Up</a>
        </div>
    </div>
</nav>
<!-- /navbar -->
 
<!-- content section will be here -->


9.3 콘텐츠 섹션 추가 


콘텐츠 섹션은 HTML 양식 및 메시지 프롬프트와 같은 콘텐츠가 렌더링 되는 곳입니다.


index.html 파일의 <!-content section will be here-> 주석을 다음 코드로 바꿉니다.


<!-- container -->
<main role="main" class="container starter-template">
 
    <div class="row">
        <div class="col">
 
            <!-- where prompt / messages will appear -->
            <div id="response"></div>
 
            <!-- where main content will appear -->
            <div id="content"></div>
        </div>
    </div>
 
</main>
<!-- /container -->


9.4 부트 스트랩 4 및 사용자 지정 CSS 링크 추가 


우리는 사용자 인터페이스를 보기 좋게 만들기 위해 Bootstrap 4를 사용하고 있습니다. 전체 라이브러리를 다운로드 할 필요가 없도록 CDN 링크를 사용할 것입니다.


다음 섹션에서 사용자 정의 CSS 파일 사용을 살펴 보겠습니다.


index.html 파일의 <!-CSS 링크는 여기에 있습니다-> 주석을 다음 코드로 바꿉니다.


<!-- Bootstrap 4 CSS and custom CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous" />
<link rel="stylesheet" type="text/css" href="custom.css" />


9.5 사용자 지정 CSS 파일 만들기 


우리는 구현하려는 모든 모양 및 느낌 사용자 정의에 사용자 정의 CSS를 사용합니다.

  • rest-api-authentication-example 폴더를 엽니다.
  • custom.css 파일을 생성합니다.
  • 다음 코드를 넣으십시오.
body { padding-top: 5rem; }
.starter-template { padding: 3rem 1.5rem; }
#logout{ display:none; }


9.6 jQuery 및 Bootstrap 4 스크립트 링크 추가 


이 튜토리얼에서는 jQuery 라이브러리를 사용하여 인터페이스를 렌더링하고 HTTP 요청을 작성합니다.


Bootstrap 4가 작동하도록 하려면 자체 JavaScript도 포함해야 합니다.


index.html 파일의 <!-script links will be here-> 주석을 다음 코드로 바꿉니다.


<!-- jQuery & Bootstrap 4 JavaScript libraries -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
 
<!-- jquery scripts will be here -->


9.7 가입 HTML 양식 표시 


내비게이션 바에서 가입 메뉴를 클릭하면 가입 또는 등록 양식이 표시됩니다.


아래 코드는 클릭 트리거와 HTML 양식을 보여줍니다.


index.html 파일의 <!-jquery 스크립트가 여기에 있습니다-> 주석을 다음 코드로 바꿉니다.


<script>
// jQuery codes
$(document).ready(function(){
    // show sign up / registration form
    $(document).on('click', '#sign_up', function(){
 
        var html = `
            <h2>Sign Up</h2>
            <form id='sign_up_form'>
                <div class="form-group">
                    <label for="firstname">Firstname</label>
                    <input type="text" class="form-control" name="firstname" id="firstname" required />
                </div>
 
                <div class="form-group">
                    <label for="lastname">Lastname</label>
                    <input type="text" class="form-control" name="lastname" id="lastname" required />
                </div>
 
                <div class="form-group">
                    <label for="email">Email</label>
                    <input type="email" class="form-control" name="email" id="email" required />
                </div>
 
                <div class="form-group">
                    <label for="password">Password</label>
                    <input type="password" class="form-control" name="password" id="password" required />
                </div>
 
                <button type='submit' class='btn btn-primary'>Sign Up</button>
            </form>
            `;
 
        clearResponse();
        $('#content').html(html);
    });
 
    // trigger when registration form is submitted here
 
    // show login form trigger will be here
 
    // clearResponse() will be here
});
</script>


9.8 가입 양식 제출시 트리거 


제출할 때 양식 데이터를 처리해야 합니다.


여기에 index.html 파일의 주석 등록 양식이 제출되면 트리거를 다음 코드로 교체하십시오.


// trigger when registration form is submitted
$(document).on('submit', '#sign_up_form', function(){
 
    // get form data
    var sign_up_form=$(this);
    var form_data=JSON.stringify(sign_up_form.serializeObject());
 
    // submit form data to api
    $.ajax({
        url: "api/create_user.php",
        type : "POST",
        contentType : 'application/json',
        data : form_data,
        success : function(result) {
            // if response is a success, tell the user it was a successful sign up & empty the input boxes
            $('#response').html("<div class='alert alert-success'>Successful sign up. Please login.</div>");
            sign_up_form.find('input').val('');
        },
        error: function(xhr, resp, text){
            // on error, tell the user sign up failed
            $('#response').html("<div class='alert alert-danger'>Unable to sign up. Please contact admin.</div>");
        }
    });
 
    return false;
});


9.9 프롬프트 메시지 제거 


clearResponse() 메서드는 이전 섹션에서 사용되었습니다. 유일한 목적은 화면에 표시되었을 수 있는 모든 프롬프트 메시지를 제거하는 것입니다.


// clearResponse()는 index.html 파일의 주석이 될 것입니다. 다음 코드로 대체하십시오.


// remove any prompt messages
function clearResponse(){
    $('#response').html('');
}
 
// showLoginPage() will be here
 
// serializeObject will be here


9.10 serializeObject 함수 추가 


serializeObject 함수는 양식 데이터를 JSON 형식으로 변환합니다. HTML 양식에서 API로 값을 보내려면 이 함수가 필요합니다.


// serializeObject는 index.html 파일의 주석이 될 것입니다. 다음 코드로 대체하십시오.


// function to make form values to json format
$.fn.serializeObject = function(){
 
    var o = {};
    var a = this.serializeArray();
    $.each(a, function() {
        if (o[this.name] !== undefined) {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
        } else {
            o[this.name] = this.value || '';
        }
    });
    return o;
};


9.11 출력 


사용자가 탐색 모음에서 가입 링크를 클릭 할 때.


3-sign-up.jpg?resize=1020%2C707&ssl=1 

사용자가 양식을 작성하고 제출 한 후.


4-successful-sign-up.jpg?resize=1020%2C769&ssl=1 


10.0 로그인 페이지 만들기 


10.1 로그인 메뉴 클릭시 트리거 


내비게이션 바에서 로그인 메뉴를 클릭하면 로그인 양식이 표시됩니다.


아래 코드는 클릭 트리거와 showLoginPage(); 로그인 양식을 표시하는 함수.


// show login form trigger는 여기에 index.html 파일의 주석이 될 것임을 다음 코드로 바꿉니다.


// show login form
$(document).on('click', '#login', function(){
    showLoginPage();
});
 
// login form submit trigger will be here


10.2 로그인 HTML 양식 표시 


아래 함수는 사용자가 로그인 할 수 있는 HTML 양식을 보여줍니다.


// showLoginPage()는 index.html 파일의 주석이 될 것임을 다음 코드로 바꿉니다.


// show login page
function showLoginPage(){
 
    // remove jwt
    setCookie("jwt", "", 1);
 
    // login page html
    var html = `
        <h2>Login</h2>
        <form id='login_form'>
            <div class='form-group'>
                <label for