1. JWT 라이브러리 설치
// composer 설치 스크립트 다운로드
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
// composer 설치 스크립트 실행
php composer-setup.php
// 설치된 composer를 전역적으로 사용할 수 있도록 디렉토리 이동
mv composer.phar /usr/local/bin/composer
먼저 PHP 외부 라이브러를 쉽게 설치하고 업데이트할 수 있게 해주는 도구인 composer를 설치한다.
composer require firebase/php-jwt
이후 composer를 사용하여
프로젝트를 진행중인 디렉토리에 (/var/www/html)
"firebase/php-jwt" 라이브러리를 설치한다.
설치 후, 디렉토리를 살펴보면
vender 디렉토리가 생성된 것을 확인할 수 있다.
2. JWT 로그인 구현
2.1. loginjwt.php
<?php
// 클래스 자동 로드
require __DIR__.'/vendor/autoload.php';
// jwt 라이브러리 사용
use \Firebase\JWT\JWT;
// DB 접속 정보 가져오기
require_once("../function/dbconn.php");
// 에러 메시지 출력
error_reporting( E_ALL );
ini_set( "display_errors", 1 );
// 사용자 입력 정보 받아오기
$userid = $_POST['userid'];
$userpw = $_POST['userpw'];
// 비밀번호를 HASH 값으로 변경
$userpw = md5($userpw);
// 로그인 검증
$sql = "select name from users where userid='$userid' and userpw='$userpw'";
$result = mysqli_query($conn, $sql);
if($result) {
// 비밀키 값과 페이로드 작성
$key = "secretkeyofalioth";
$payload = array(
"userid" => $userid,
"exp" => time() + 3600
);
// JWT 생성
$jwt = JWT::encode($payload, $key, 'HS256');
// JWT를 쿠키에 담아서 클라이언트에게 전송
setcookie('jwt', $jwt, time() + 3600, '/', '192.168.0.26', false, true);
// 생성된 JWT 출력
// echo json_encode(array("token" => $jwt));
header("Location: indexjwt.php");
exit;
} else {
echo "잘못된 요청";
}
?>
2.2. indexjwt.php
<?php
require __DIR__.'/vendor/autoload.php';
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
// JWT 쿠키 확인
$jwt = $_COOKIE['jwt'] ?? null;
// 에러 메시지 출력
error_reporting( E_ALL );
ini_set( "display_errors", 1 );
?>
<html>
<!-- <head> 생략 -->
<body>
<h1>Alioth's Web Page</h1>
<div class="account-field">
<?php
if($jwt) {
// 비밀키 값
$key = "secretkeyofalioth";
try {
// JWT 디코딩
$decoded = JWT::decode($jwt, new Key($key, 'HS256'));
} catch (Exception $e) {
// 발급해준 토큰이 아닌 경우
// echo 'Token is invalid: ' . $e->getMessage();
echo "<script>alert('Token is invalid');</script>";
echo "<a href='login2.html'>로그인 |</a>";
echo "<a href='signup2.html'> 회원가입</a>";
exit;
}
$userid = $decoded->userid;
// 만료 시간 체크
$exp = $decoded->exp;
$time = time();
if ($time < $exp) {
echo "<a href='mypage.php'>$userid</a>"."님";
?>
|
<a href="logoutjwt.php">로그아웃</a>
<?php
} else {
// echo "토큰 만료로 재 로그인 하세요";
}
} else {
?>
<a href="login2.html">로그인</a>
|
<a href="signup2.html">회원가입</a>
<?php
}
?>
</div>
</body>
</html>
2.3. logoutjwt.php
<?php
// 클라이언트 쿠키 삭제
setcookie('jwt', '', time() - 3600, '/', '192.168.0.26', false, true);
// 로그인 페이지로 리다이렉트
header("Location: login2.html");
exit;
?>
2.4. 클라이언트 - 서버 통신 확인
로그인 시
서버가 jwt 토큰 값을 쿠키에 넣어 응답하는 것을 확인할 수 있다.
jwt 디버거로 페이로드 값을 확인해보면
이상없이 잘 복호화 되는 것을 확인할 수 있다.
이후 클라이언트는 서버와 통신 시 jwt 토큰 값과 함께 요청을 보내고
서버는 이를 보고 클라이언트를 user 라는 사용자로 인식하는 것을 볼 수 있다.
이후 로그아웃 버튼을 누르면
서버가 클라이언트의 jwt 값을 삭제하면서
인증 연결 유지를 끊는 것을 확인할 수 있다.
2.5. 로그아웃 방식
- 클라이언트 측에서 쿠키(토큰) 삭제
하지만 위의 로그아웃 방식은 취약한 점이 있다.
토큰이 클라이언트의 브라우저에서만 삭제되었을 뿐,
서버에서 지정한 만료 기한이 지나기전까지는 서버는 해당 토큰을 인정해준다.
때문에 악의적인 사용자가 user 사용자의 jwt 값을 탈취해서 cookie에 넣어 보내면
서버는 해당 요청을 user 사용자의 요청으로 이해하고 응답한다.
proxy 툴을 통해
index 페이지를 요청하는 헤더 값에
로그아웃 이전에 발급 받았던 jwt 토큰 값을 쿠키로 전달해보니
user 사용자로 로그인 되는 것을 볼 수 있다.
위와 같은 상황을 방지하려면 서버에서 토큰 블랙리스트를 관리해야 한다.
- 토큰 블랙리스트 관리
JWT 토큰이 만료되지 않은 상태에서 로그아웃 요청이 오면
해당 토큰을 블랙리스트 처리한다.
때문에 토큰이 탈취되더라도 로그아웃 이후에는 안전하다.
하지만, 토큰 요청 시
매번 블랙리스트를 확인해야 하므로
서버에서 관리하지 않아도 된다는 토큰의 장점이 무색해질 수 있다.
3. Reference
https://upcurvewave.tistory.com/611
JWT 토큰 기반의 상태 관리시 로그아웃 처리 문제와 간단한 해결 방법
본 글의 탄생 배경 사내에서 JWT 기반의 인증 인가 시스템을 구현할 기회가 있었다. 당시 프로젝트 개발을 구상하는 단계에서 로그아웃에 대한 이슈가 있었다. 당시 해당 이슈를 정리하고 검토하
upcurvewave.tistory.com
https://github.com/firebase/php-jwt
GitHub - firebase/php-jwt: PHP package for JWT
PHP package for JWT. Contribute to firebase/php-jwt development by creating an account on GitHub.
github.com
https://engineerinsight.tistory.com/232
[우테코] JWT 방식에서 로그아웃, Refresh Token 만들기(1): JWT의 Stateless한 특징을 최대한 살리려면?
안녕! 우아한테크코스 5기 [스탬프크러쉬]팀 깃짱이라고 합니다. 스탬프크러쉬 서비스의 소스 코드 바로가기 사장모드: stampcrush.site/admin 고객모드: stampcrush.site 💋 인트로 스탬프크러쉬는 사용
engineerinsight.tistory.com
'Web > Develop_PHP+MySQL' 카테고리의 다른 글
웹 사이트 만들기 - 게시판(페이징) (0) | 2024.05.13 |
---|---|
웹 사이트 만들기 - 게시판(글쓰기) (0) | 2024.05.13 |
웹 페이지 만들기 - 마이페이지 (0) | 2024.04.29 |
웹 페이지 만들기 - 비밀번호 일치 체크하기 (2) | 2024.04.26 |
DB - PHP 연동 과제 (0) | 2024.04.25 |