[vc_row][vc_column][vc_column_text]이번 시간에는 로그인 과정과 로그인 성공시 생성된 token 을 어떻게 저장하고 어떻게 활용하는지 보여드리겠습니다.
token 은 처음 요청시 PHP 에서 생성해서 Mysql 데이타베이스에 저장하고, 이후 요청시에는 DB 에 저장된 token 을 불러서 보내주면 됩니다.
우선 JWT Class 를 사용하는 테마의 functions.php 에 넣어줍니다.
class JWT
{
/**
* Decodes a JWT string into a PHP object.
*
* @param string $jwt The JWT
* @param string|null $key The secret key
* @param bool $verify Don't skip verification process
*
* @return object The JWT's payload as a PHP object
* @throws UnexpectedValueException Provided JWT was invalid
* @throws DomainException Algorithm was not provided
*
* @uses jsonDecode
* @uses urlsafeB64Decode
*/
public static function decode($jwt, $key = null, $verify = true)
{
$tks = explode('.', $jwt);
if (count($tks) != 3) {
throw new UnexpectedValueException('Wrong number of segments');
}
list($headb64, $bodyb64, $cryptob64) = $tks;
if (null === ($header = JWT::jsonDecode(JWT::urlsafeB64Decode($headb64)))) {
throw new UnexpectedValueException('Invalid segment encoding');
}
if (null === $payload = JWT::jsonDecode(JWT::urlsafeB64Decode($bodyb64))) {
throw new UnexpectedValueException('Invalid segment encoding');
}
$sig = JWT::urlsafeB64Decode($cryptob64);
if ($verify) {
if (empty($header->alg)) {
throw new DomainException('Empty algorithm');
}
if ($sig != JWT::sign("$headb64.$bodyb64", $key, $header->alg)) {
throw new UnexpectedValueException('Signature verification failed');
}
}
return $payload;
}
/**
* Converts and signs a PHP object or array into a JWT string.
*
* @param object|array $payload PHP object or array
* @param string $key The secret key
* @param string $algo The signing algorithm. Supported
* algorithms are 'HS256', 'HS384' and 'HS512'
*
* @return string A signed JWT
* @uses jsonEncode
* @uses urlsafeB64Encode
*/
public static function encode($payload, $key, $algo = 'HS256')
{
$header = array('typ' => 'JWT', 'alg' => $algo);
$segments = array();
$segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($header));
$segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($payload));
$signing_input = implode('.', $segments);
$signature = JWT::sign($signing_input, $key, $algo);
$segments[] = JWT::urlsafeB64Encode($signature);
return implode('.', $segments);
}
/**
* Sign a string with a given key and algorithm.
*
* @param string $msg The message to sign
* @param string $key The secret key
* @param string $method The signing algorithm. Supported
* algorithms are 'HS256', 'HS384' and 'HS512'
*
* @return string An encrypted message
* @throws DomainException Unsupported algorithm was specified
*/
public static function sign($msg, $key, $method = 'HS256')
{
$methods = array(
'HS256' => 'sha256',
'HS384' => 'sha384',
'HS512' => 'sha512',
);
if (empty($methods[$method])) {
throw new DomainException('Algorithm not supported');
}
return hash_hmac($methods[$method], $msg, $key, true);
}
/**
* Decode a JSON string into a PHP object.
*
* @param string $input JSON string
*
* @return object Object representation of JSON string
* @throws DomainException Provided string was invalid JSON
*/
public static function jsonDecode($input)
{
$obj = json_decode($input);
if (function_exists('json_last_error') && $errno = json_last_error()) {
JWT::_handleJsonError($errno);
} else if ($obj === null && $input !== 'null') {
throw new DomainException('Null result with non-null input');
}
return $obj;
}
/**
* Encode a PHP object into a JSON string.
*
* @param object|array $input A PHP object or array
*
* @return string JSON representation of the PHP object or array
* @throws DomainException Provided object could not be encoded to valid JSON
*/
public static function jsonEncode($input)
{
$json = json_encode($input);
if (function_exists('json_last_error') && $errno = json_last_error()) {
JWT::_handleJsonError($errno);
} else if ($json === 'null' && $input !== null) {
throw new DomainException('Null result with non-null input');
}
return $json;
}
/**
* Decode a string with URL-safe Base64.
*
* @param string $input A Base64 encoded string
*
* @return string A decoded string
*/
public static function urlsafeB64Decode($input)
{
$remainder = strlen($input) % 4;
if ($remainder) {
$padlen = 4 - $remainder;
$input .= str_repeat('=', $padlen);
}
return base64_decode(strtr($input, '-_', '+/'));
}
/**
* Encode a string with URL-safe Base64.
*
* @param string $input The string you want encoded
*
* @return string The base64 encode of what you passed in
*/
public static function urlsafeB64Encode($input)
{
return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
}
/**
* Helper method to create a JSON error.
*
* @param int $errno An error number from json_last_error()
*
* @return void
*/
private static function _handleJsonError($errno)
{
$messages = array(
JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON'
);
throw new DomainException(
isset($messages[$errno])
? $messages[$errno]
: 'Unknown JSON error: ' . $errno
);
}
}
토큰을 사용하기 위해서는 encode decode 함수를 사용하면 됩니다.
function login($request){
global $wpdb;
$creds = array();
$creds['user_login'] = $request["username"];
$creds['user_password'] = $request["password"];
$creds['remember'] = true;
$user = wp_signon( $creds, false );
if ( is_wp_error($user) ) {
$ret = array();
$ret['code'] = "auth_failed";
$ret['data'] = array("status"=>403);
$ret['message'] = "Invalid Credentials";
return $ret;
} else {
$token['id'] = $user->ID;
$token['pwd'] = $creds['user_password'];
$web_token = JWT::encode($token, 'change.this');
$client_info = array("ip"=>$_SERVER['REMOTE_ADDR'],"agent"=>$_SERVER['HTTP_USER_AGENT']);
$str_client = json_encode($client_info);
$sql = " INSERT INTO ".$wpdb->prefix."msgapi_token (user_id, token, client_id, expire_time ) VALUES (".$token['id'].", '".esc_sql($web_token)."', '".esc_sql($str_client)."', date_add(current_timestamp, interval 1 day) );";
$wpdb->query($sql);
$ret = array();
$ret['token'] = $web_token;
$ret['display_name'] = $user->data->display_name;
$ret['user_email'] = $user->data->user_email;
$ret['user_nicename'] = $user->data->user_nicename;
return $ret;
}
}
$web_token = JWT::encode($token, ‘change.this’);
encode 함수의 첫 번 째 값 id, pwd 를 담은 배열을 넣고, 두 번째 파라미터는 secret key 입니다. 서버 키로 어려운 키를 넣어주세요.
https://api.wordpress.org/secret-key/1.1/salt/
위 링크를 클릭해서 생성된 문자열을 사용하면 좋습니다.
그럼 POSTMan 으로 테스트를 해 볼까요?[/vc_column_text][/vc_column][/vc_row][vc_row][vc_column][vc_column_text]
username, password 를 받아서 token 을 DB 속에 넣고 그 값을 보여주게 됩니다.
DB 에는 어떤 값이 들어있는지 볼까요 ?
이렇게 받은 token 값은 쿠키나 localStorage 에 저장해서 사용할 수 있습니다.
이제 Android APP 에서 사용할 AngularJS 코드를 보기로 하죠.[/vc_column_text][/vc_column][/vc_row][vc_row][vc_column][vc_column_text]Angular.js 의 코드는 크게 두 가지로 볼 수 있습니다.
token 을 받아오고 , cookie 에 저장한 다음 header 를 바꾸는 작업입니다.
( function() {
var app = angular.module( 'jwtAuth', [] );
app.controller( 'MainController', function( $scope, $http ) {
var apiHost = 'http://msgapi.wper.kr/wp-json';
$http.post( apiHost + '/msgapi/v1/token', {
username: 'admin',
password: 'password'
} )
.then( function( response ) {
console.log( response.data )
} )
.catch( function( error ) {
console.error( 'Error', error.data[0] );
} );
} );
} )();
app.config( function( $httpProvider ) {
$httpProvider.interceptors.push( [ '$q', '$location', '$cookies', function( $q, $location, $cookies ) {
return {
'request': function( config ) {
config.headers = config.headers || {};
//Assume that you store the token in a cookie.
var globals = $cookies.getObject( 'globals' ) || {};
//If the cookie has the CurrentUser and the token
//add the Authorization header in each request
if ( globals.currentUser && globals.currentUser.token ) {
config.headers.Authorization = 'Bearer ' + globals.currentUser.token;
}
return config;
}
};
} ] );
} );
중요한 포인트는 config.headers.Authorization = ‘Bearer ‘ + globals.currentUser.token;
이 부분입니다.
역시 POSTMan 에서 로그인 성공 이후 token 값을 가지고, 친구에게 메세지를 보내는 작업들은 다음 시간에 보여드리겠습니다.[/vc_column_text][/vc_column][/vc_row]
