개발 꿀팁/PHP

php Firebase/ php-jwt 토큰 검증

Jammie 2022. 6. 29. 17:15
반응형

일:JWT 소개:전칭 JSON Web Token, JSON의 오픈 표준(RFC 7519)에 근거해, Token 방식으로 전통적인 Cookie-Session 모드를 대체하고, 각 서버, 클라이언트의 정보 전달 서명 검증에 사용합니다.



2: JWT의 장점:

1: 서비스 측에서 기존 세션 정보를 저장할 필요가 없으며, 도메인 간 전송 문제가 없으며, 서버 오버헤드를 줄일 수 있습니다.

2:jwt는 간단한 구성으로 적은 바이트를 차지해 전송이 용이하다.

3:json 포맷이 통용되어 서로 다른 언어 간에 사용할 수 있습니다.



3. JWT 구성

1:jwt는 세 부분으로 구성된다.

헤더(header)
payload에는 정의 정보와 사용자 정의 정보가 들어 있습니다
비자(signature)

2:구체적 구성:

헤더:

{
  "typ": "JWT", //선언 형식jwt
  "alg": "HS256" //서명 알고리즘은 다음과 같습니다SHA256
}

페이로드(payload)

{
  "iss": "http://www.helloweba.net",
  "aud": "http://www.helloweba.net",
  "iat": 1525317601,
  "nbf": 1525318201,
  "exp": 1525318201,
  "data": {
    "userid": 1,
    "username": "리샤오룽"
  }
}

하중은 표준 및 기타 선언의 두 부분으로 구성된다.

표준성명: JWT 표준규격에 규정된 성명, 그러나 아니다.반드시 기입해야 한다.

표준 선언 필드:

이 JWT를 받는 쪽

iss: jwt 발급자

sub: jwt 대상 사용자

aud:jwt를 받는 쪽

exp: jwt의 만료 시간, 만료 시간 필수발급 시간보다 커야 함

nbf: 정의하기 전, 시간점호 후에야 접속할 수 있다

iat: jwt 발급 시간

jti: jwt의 고유 아이덴티티, 주로 사용일회용 토큰으로 하겠습니다.
기타 성명: 자신이 정의한 필드. 이 부분은 풀 수 있으므로 민감한 정보를 넣지 말 것을 권고합니다. 여기서 data는 내가 정의한 성명입니다.
세 부분을 각각 쉼표로 구분하다

4:사용:PHP가 많다jwt 가방, 예를 들어 lobucci/jwt, 나는 여기서 firebase를 사용한다.git 주소에서 다운로드할 수 있습니다

1: 코드를 뽑아내라

composer require firebase/php-jwt

2:서비스측발급 토큰

<?php
use \Firebase\JWT\JWT; //가져오기JWT
class MainController extends Controller
{

	//발급하다Token
	public function lssue()
	{
		$key = '344'; //key
		$time = time(); //현재 시간
       		$token = [
        	'iss' => 'http://www.helloweba.net', //발급자 선택 가능
           	'aud' => 'http://www.helloweba.net', //해당 JWT를 수신하는 측, 옵션
           	'iat' => $time, //발급시기
           	'nbf' => $time , //(Not Before):time+30을 설정하면 현재 30초 후에 사용할 수 있습니다.
           	'exp' => $time+7200, //유통기한 경과시간, 여기에서 2시간을 설정한다.
            	'data' => [ //사용자 정의 정보, 중요한 정보를 정의하지 않음
             		'userid' => 1,
               		'username' => '리샤오룽'
            ]
        ];
        echo JWT::encode($token, $key); //출력Token
	}

3: 토큰을 해석하고, 프레젠테이션을 위해 여기에 직접 적습니다.

<?php
use \Firebase\JWT\JWT; //가져오기JWT
class MainController extends Controller
{

	public function verification()
	{
		$key = '344'; //key발급할 때랑 똑같아야 돼

		$jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC93d3cuaGVsbG93ZWJhLm5ldCIsImF1ZCI6Imh0dHA6XC9cL3d3dy5oZWxsb3dlYmEubmV0IiwiaWF0IjoxNTI1MzQwMzE3LCJuYmYiOjE1MjUzNDAzMTcsImV4cCI6MTUyNTM0NzUxNywiZGF0YSI6eyJ1c2VyaWQiOjEsInVzZXJuYW1lIjoiXHU2NzRlXHU1YzBmXHU5Zjk5In19.Ukd7trwYMoQmahOAtvNynSA511mseA2ihejoZs7dxt0"; //발급받은Token
		try {
	       		JWT::$leeway = 60;//현재 시간에서 60을 빼면, 시간을 좀 남겨두어라
	       		$decoded = JWT::decode($jwt, $key, ['HS256']); //HS256방식, 여기 발급 시 대응
	       		$arr = (array)$decoded;
	       		print_r($arr);
	    	} catch(\Firebase\JWT\SignatureInvalidException $e) {  //서명이 잘못되었습니다.
	    		echo $e->getMessage();
	    	}catch(\Firebase\JWT\BeforeValidException $e) {  // 사인은 어느 시점 이후에나 사용할 수 있습니다.
	    		echo $e->getMessage();
	    	}catch(\Firebase\JWT\ExpiredException $e) {  // token기한이 지나다
	    		echo $e->getMessage();
	   	}catch(Exception $e) {  //기타 오류
	    		echo $e->getMessage();
	    	}
	    //Firebase여러 개를 정의했습니다 throw new,우리는 여러 개를 잡을 수 있다.catch문제를 정의하다,catch자신의 업무에 가입하다,예를 들어token기한이 지나면 현재로 쓸 수 있다Token새로 고침Token
	}
}

src 디렉터리에 있는 JWT.php에 있는 메서드 decode에서 여러 개의 사용자 정의 throw new를 통해 이상을 던지는 것을 볼 수 있습니다.



그래서 우리는 서로 다른 throw new에 따라 여러 개의 catch를 설치하여 포획할 수 있다.

출력 데이터:

Array
(
    [iss] => http://www.helloweba.net
    [aud] => http://www.helloweba.net
    [iat] => 1525340317
    [nbf] => 1525340317
    [exp] => 1525347517
    [data] => stdClass Object
        (
            [userid] => 1
            [username] => 리샤오룽
        )

)

5:실전 시뮬레이션

1: 시나리오: 클라이언트아이디 패스워드로 로그인한 후, 서비스 측에서 클라이언트에 두 개의 토큰(access_token)과 refresh_token)을 반환한다.

access_token: 인터페이스를 요청하는 토큰

refresh_token: 새로 고침access_token

예를 들면 access_token 설정 2시간 만료, refresh_token 설정 7일 만료, 2시간 후 access_token 만료, 단 refresh_token 아직 7일 이내면 클라이언트가 통과refresh_token 서비스 측에서 a를 새로 고칩니다ccess_token; refresh_token도 7일 이상 경과하면 클라이언트는 다시 로그인하여 access_token과 refresh_token을 얻어야 합니다.

두 개의 to를 구분하기 위해서ken, 페이로드(payload)에 scopes: 도메인 필드를 추가합니다.

access_token에서 설정: scopes: role_access

refresh_token에서 설정: scopes: role_refresh

어떤 분들은 t를 하나 쓰시는데oken, 긴 시간 만료로 설정하거나, 몇 시간 만료로 설정하거나, 만료되면 만료된 토큰을 새 토큰과 교환하는 것은 문제가 있습니다. 일부 사람들은 문제가 있습니다.토큰에는 두 개의 시간이 있다고 합니다. 하나는 만료 시간이고 하나는 새로 고침입니다.시간, 리프레시 시간만 있으면 새 토큰으로 교환할 수 있다.만약 다른 사람이 너를 가졌다면이 토큰도, 만약 유통기한 내에 있다면, 마찬가지로 토큰을 갱신할 수 있지 않을까요?두 개의 토큰을 다 얻지 않는 한 상대적으로 두 번째 아이템이 더 안전하다.

직접 코드:

<?php
use \Firebase\JWT\JWT; //가져오기JWT
class MainController extends Controller
{

	public function authorizations()
	{
		$key = 'ffdsfsd@4_45'; //key
		$time = time(); //현재 시간

		//공용 정보
		$token = [
        	'iss' => 'http://www.helloweba.net', //발급자 선택 가능
            'iat' => $time, //발급시기
            'data' => [ //사용자 정의 정보, 중요한 정보를 정의하지 않음
             	'userid' => 1,
            ]
        ];

		$access_token = $token;
		$access_token['scopes'] = 'role_access'; //tokenID, 인터페이스 요청token
		$access_token['exp'] = $time+7200; //access_token유통기한 경과시간, 여기에서 2시간을 설정한다.

		$refresh_token = $token;
		$refresh_token['scopes'] = 'role_refresh'; //token표시, 새로 고침access_token
		$refresh_token['exp'] = $time+(86400 * 30); //access_token만료일, 여기 30일을 설정합니다.

		$jsonList = [
			'access_token'=>JWT::encode($access_token,$key),
			'refresh_token'=>JWT::encode($refresh_token,$key),
			'token_type'=>'bearer' //token_type:토큰 유형을 나타냅니다. 이 값은 대소문자가 민감하지 않습니다. 여기서 사용합니다bearer
		];
                Header("HTTP/1.1 201 Created");
		echo json_encode($jsonList); //클라이언트 토큰으로 메시지 보내기
	}
}

출력은 다음과 같습니다.

{
	"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC93d3cuaGVsbG93ZWJhLm5ldCIsImlhdCI6MTUyNTQxNzg5NywiZGF0YSI6eyJ1c2VyaWQiOjF9LCJzY29wZXMiOiJyb2xlX2FjY2VzcyIsImV4cCI6MTUyNTQyNTA5N30.Nxp1yutwt8Fxj5XEzes4j-X4tCBQwE0htEV3Msm2D8s",
	"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC93d3cuaGVsbG93ZWJhLm5ldCIsImlhdCI6MTUyNTQxNzg5NywiZGF0YSI6eyJ1c2VyaWQiOjF9LCJzY29wZXMiOiJyb2xlX3JlZnJlc2giLCJleHAiOjE1MjgwMDk4OTd9.YY8Lid3nk3bnV-ZnAYneKJxGiaD73waqTpC3bHz3wsY",
	"token_type": "bearer"
}

HTTP 헤더 응답은 토큰 클라이언트 2개가 저장되고, 하나는 인터페이스를 취하고, 하나는 인터페이스를 새로 고치는 것이다.



클라이언트가 요청할 때 HTTP 헤더에 Authorization: bearer token,베어러 뒤에 공간이 있으니 주의하세요.PHP로 시뮬레이션을 해보세요.





요청 정보는 다음과 같습니다. PHP는 Authorization 정보를 획득하여 판단합니다.



이것은 단지 하나의 생각일 뿐이다.여러분은 자신의 생각대로 할 수 있다.이런 생각의 서비스는 토큰을 보존할 필요가 없다.토큰은 만료되지 않지만 토큰을 로그아웃하려면 레디스(redis)에 등록할 수 있다.

반응형