diff --git a/composer.json b/composer.json index 0a5b00d..91ca569 100644 --- a/composer.json +++ b/composer.json @@ -13,6 +13,7 @@ ], "require": { "citrus-framework/configure": "^1.0", + "citrus-framework/contract": "^1.0", "citrus-framework/formmap": "^1.0", "citrus-framework/http": "^1.0", "citrus-framework/logger": "^1.0", @@ -22,7 +23,8 @@ "ext-mbstring": "*", "ext-posix": "*", "ext-json": "*", - "ext-pdo": "*" + "ext-pdo": "*", + "ext-openssl": "*" }, "require-dev": { "php": "^7.3", diff --git a/src/Authentication.php b/src/Authentication.php index 02900b2..a44166d 100644 --- a/src/Authentication.php +++ b/src/Authentication.php @@ -10,8 +10,8 @@ namespace Citrus; +use Citrus\Authentication\AuthItem; use Citrus\Authentication\Database; -use Citrus\Authentication\Item; use Citrus\Authentication\Protocol; use Citrus\Configure\Configurable; use Citrus\Database\Connection\Connection; @@ -70,10 +70,10 @@ public function loadConfigures(array $configures = []): Configurable /** * 認証処理 * - * @param Item $item + * @param AuthItem $item * @return bool true:認証成功, false:認証失敗 */ - public function authorize(Item $item): bool + public function authorize(AuthItem $item): bool { if (true === is_null($this->protocol)) { @@ -106,10 +106,10 @@ public function deAuthorize(): bool * 認証のチェック * 認証できていれば期間の延長 * - * @param Item|null $item + * @param AuthItem|null $item * @return bool true:チェック成功, false:チェック失敗 */ - public function isAuthenticated(Item $item = null): bool + public function isAuthenticated(AuthItem $item = null): bool { if (true === is_null($this->protocol)) { diff --git a/src/Authentication/Item.php b/src/Authentication/AuthItem.php similarity index 83% rename from src/Authentication/Item.php rename to src/Authentication/AuthItem.php index 10dc0ea..ef80672 100644 --- a/src/Authentication/Item.php +++ b/src/Authentication/AuthItem.php @@ -15,7 +15,7 @@ /** * 認証アイテム */ -class Item extends Columns +class AuthItem extends Columns { /** @var string user id */ public $user_id; @@ -26,6 +26,6 @@ class Item extends Columns /** @var string token */ public $token; - /** @var string keep at */ - public $keep_at; + /** @var string expired at */ + public $expired_at; } diff --git a/src/Authentication/Database.php b/src/Authentication/Database.php index a083a35..5182ee3 100644 --- a/src/Authentication/Database.php +++ b/src/Authentication/Database.php @@ -24,7 +24,7 @@ user_id CHARACTER VARYING(32) NOT NULL, password CHARACTER VARYING(64) NOT NULL, token TEXT, - keep_at TIMESTAMP WITHOUT TIME ZONE, + expired_at TIMESTAMP WITHOUT TIME ZONE, status INTEGER DEFAULT 0 NOT NULL, created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT current_timestamp NOT NULL, updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT current_timestamp NOT NULL, @@ -60,13 +60,13 @@ public function __construct(Connection $connection) /** * 認証処理 * - * @param Item $item + * @param AuthItem $item * @return bool true:認証成功, false:認証失敗 */ - public function authorize(Item $item): bool + public function authorize(AuthItem $item): bool { // ログインID、パスワード のどちらかが null もしくは 空文字 だった場合は認証失敗 - if (true === Strings::isEmpty($item->user_id) || true === Strings::isEmpty($item->password)) + if (true === Strings::isEmpty($item->user_id) or true === Strings::isEmpty($item->password)) { return false; } @@ -75,10 +75,10 @@ public function authorize(Item $item): bool $table_name = Authentication::$AUTHORIZE_TABLE_NAME; // 対象ユーザーがいるか? - $condition = new Item(); + $condition = new AuthItem(); $condition->user_id = $item->user_id; - /** @var Item $result */ - $result = (new Builder($this->connection))->select($table_name, $condition)->execute(Item::class)->one(); + /** @var AuthItem $result */ + $result = (new Builder($this->connection))->select($table_name, $condition)->execute(AuthItem::class)->one(); // いなければ認証失敗 if (true === is_null($result)) { @@ -93,11 +93,11 @@ public function authorize(Item $item): bool // 認証情報の保存 $item->token = Authentication::generateToken(); - $item->keep_at = Authentication::generateKeepAt(); + $item->expired_at = Authentication::generateKeepAt(); $item->password = null; // データベースに現在のトークンと保持期間の保存 - $condition = new Item(); + $condition = new AuthItem(); $condition->rowid = $result->rowid; $condition->rev = $result->rev; (new Builder($this->connection))->update($table_name, $item, $condition)->execute(); @@ -127,10 +127,10 @@ public function deAuthorize(): bool * 認証のチェック * 認証できていれば期間の延長 * - * @param Item|null $item + * @param AuthItem|null $item * @return bool true:チェック成功, false:チェック失敗 */ - public function isAuthenticated(Item $item = null): bool + public function isAuthenticated(AuthItem $item = null): bool { // 指定されない場合はsessionから取得 if (true === is_null($item)) @@ -145,24 +145,24 @@ public function isAuthenticated(Item $item = null): bool return false; } // ユーザーIDとトークン、認証期間があるか - if (true === is_null($item->user_id) or true === is_null($item->token) or true === is_null($item->keep_at)) + if (true === is_null($item->user_id) or true === is_null($item->token) or true === is_null($item->expired_at)) { - Logger::debug('ログアウト:ユーザIDが無い(user_id=%s)、もしくはトークンが無い(token=%s)、もしくはタイムアウト(keep_at=%s)', + Logger::debug('ログアウト:ユーザIDが無い(user_id=%s)、もしくはトークンが無い(token=%s)、もしくはタイムアウト(expired_at=%s)', $item->user_id, $item->token, - $item->keep_at + $item->expired_at ); return false; } // すでに認証期間が切れている - $keep_timestamp = strtotime($item->keep_at); - $now_timestamp = time(); - if ($keep_timestamp < $now_timestamp) + $expired_ts = strtotime($item->expired_at); + $now_ts = time(); + if ($expired_ts < $now_ts) { Logger::debug('ログアウト:タイムアウト(%s) < 現在時間(%s)', - $keep_timestamp, - $now_timestamp + $expired_ts, + $now_ts ); return false; } @@ -171,18 +171,18 @@ public function isAuthenticated(Item $item = null): bool $table_name = Authentication::$AUTHORIZE_TABLE_NAME; // まだ認証済みなので、認証期間の延長 - $authentic = new Item(); - $authentic->keep_at = Authentication::generateKeepAt(); - $condition = new Item(); + $authentic = new AuthItem(); + $authentic->expired_at = Authentication::generateKeepAt(); + $condition = new AuthItem(); $condition->user_id = $item->user_id; $condition->token = $item->token; // 更新 $result = (new Builder($this->connection))->update($table_name, $authentic, $condition)->execute(); // 時間を延長 - /** @var Item $item */ + /** @var AuthItem $item */ $item = Session::$session->call(Authentication::SESSION_KEY); - $item->keep_at = $authentic->keep_at; + $item->expired_at = $authentic->expired_at; Session::$session->add(Authentication::SESSION_KEY, $item); Session::commit(); diff --git a/src/Authentication/JWT.php b/src/Authentication/JWT.php new file mode 100644 index 0000000..3e639b3 --- /dev/null +++ b/src/Authentication/JWT.php @@ -0,0 +1,438 @@ + + * @license http://www.besidesplus.net/ + */ + +namespace Citrus\Authentication; + +use Citrus\Authentication; +use Citrus\CitrusException; +use Citrus\Collection; +use Citrus\Database\Connection\Connection; +use Citrus\Database\DatabaseException; +use Citrus\Intersection; +use Citrus\Logger; +use Citrus\Query\Builder; +use Citrus\Session; +use Citrus\Variable\Strings; + +/** + * JWT認証 + * @see https://jwt.io/ + */ +class JWT extends Protocol +{ + /** @var string HMAC using SHA-256 hash */ + public const HS256 = 'HS256'; + + /** @var string HMAC using SHA-384 hash */ + public const HS384 = 'HS384'; + + /** @var string HMAC using SHA-512 hash */ + public const HS512 = 'HS512'; + + /** @var string RSA using SHA-256 hash */ + public const RS256 = 'RS256'; + + /** @var string RSA using SHA-384 hash */ + public const RS384 = 'RS384'; + + /** @var string RSA using SHA-512 hash */ + public const RS512 = 'RS512'; + + /** @var string RSA method */ + private const METHOD_RSA = 'openssl_sign'; + + /** @var string HMAC method */ + private const METHOD_HMAC = 'hash_hmac'; + + /** + * @var array アルゴリズムリスト + */ + public static $ALGORITHM_METHODS = [ + self::HS256 => ['hash' => 'SHA256', 'method' => self::METHOD_HMAC], + self::HS384 => ['hash' => 'SHA384', 'method' => self::METHOD_HMAC], + self::HS512 => ['hash' => 'SHA512', 'method' => self::METHOD_HMAC], + self::RS256 => ['hash' => OPENSSL_ALGO_SHA256, 'method' => self::METHOD_RSA], + self::RS384 => ['hash' => OPENSSL_ALGO_SHA384, 'method' => self::METHOD_RSA], + self::RS512 => ['hash' => OPENSSL_ALGO_SHA512, 'method' => self::METHOD_RSA], + ]; + + /** @var Connection */ + public $connection; + + /** @var string 秘密鍵 */ + private static $SECRET_KEY = '9b3DdFJYdIP2Cf6OVPrkhBQUpAjHb3Z2G86rw6HSIJg='; + + /** @var string アルゴリズム */ + private static $ALGORITHM = self::HS256; + + /** @var int 認証有効期限(秒) */ + private static $EXPIRE_SEC = (24 * 60 * 60); + + + + /** + * constructor. + * + * @param Connection $connection + */ + public function __construct(Connection $connection) + { + $this->connection = $connection; + } + + + /** + * JWTエンコード処理してトークンを得る + * + * @param array $add_payloads 追加ペイロード + * @return string JWTトークン + */ + public function encode(array $add_payloads): string + { + // アルゴリズム + $algorithm = self::$ALGORITHM; + // 署名文字列 + $secret = self::$SECRET_KEY; + // 現時刻(秒) + $now = time(); + + // 要素 + $elements = []; + + // ヘッダー + $elements[] = self::base64encode(json_encode([ + 'alg' => $algorithm, + 'typ' => 'JWT', + ])); + + // ペイロード + $payloads = Collection::stream([ + // 発行者識別子 + 'iss' => 'CitrusIssue3', + // JWTの有効期限 (現在時刻 + 有効期限) + 'exp' => $this->generateExpiredAt($now), + // JWTが有効となる開始日時 + 'ndf' => $now, + // JWTの発行日時 + 'iat' => $now, + ])->betterMerge($add_payloads)->toList(); + $elements[] = self::base64encode(json_encode($payloads)); + + // 署名 + $elements[] = self::base64encode( + self::signing(implode('.', $elements), $algorithm, $secret) + ); + + return implode('.', $elements); + } + + + + /** + * JWTトークンをデコードしてペイロードを得る + * + * @param string $jwt_token JWTトークン + * @return array ペイロード配列 + * @throws JWTException + */ + public function decode(string $jwt_token): array + { + // アルゴリズム + $algorithm = self::$ALGORITHM; + // 署名文字列 + $secret = self::$SECRET_KEY; + // 現時刻(秒) + $now = time(); + + // トークン配列の分割 + $tokens = explode('.', $jwt_token); + if (3 != count($tokens)) + { + throw new JWTException('トークン要素数が不足しています'); + } + + // ヘッダーチェック + $header = json_decode(self::base64decode($tokens[0]), true); + // 認証アルゴリズムが指定したものではない + if ($algorithm !== $header['alg']) + { + throw new JWTException('認証アルゴリズムが一致しません'); + } + // 認証アルゴリズムが指定したものではない + if ('JWT' !== $header['typ']) + { + throw new JWTException('認証タイプが一致しません'); + } + + // ペイロードチェック + $payload = json_decode(self::base64decode($tokens[1]), true); + // 有効期限設定が無い、もしくは現在時刻より以前に設定されている + if (false === isset($payload['exp']) or $payload['exp'] < $now) + { + throw new JWTException('有効期限切れの認証トークンです'); + } + + // 署名チェック + $signature = self::base64decode($tokens[2]); + $verifying_token = sprintf('%s.%s', $tokens[0], $tokens[1]); + // 署名が有効ではない + if (false === self::verifySignature($verifying_token, $signature, $secret, $algorithm)) + { + throw new JWTException('署名が有効ではありません'); + } + + return $payload; + } + + + + /** + * BASE64エンコード + * + * @param string $message 対象文字列 + * @return string + */ + public static function base64encode(string $message): string + { + return str_replace('=', '', strtr(base64_encode($message), '+/', '-_')); + } + + + + /** + * BASE64デコード + * + * @param string $message 対象文字列 + * @return string + */ + public static function base64decode(string $message): string + { + // 字詰めの必要はあるか + $remainder = strlen($message) % 4; + if (0 < $remainder) + { + $message .= str_repeat('=', (4 - $remainder)); + } + return base64_decode(strtr($message, '-_', '+/')); + } + + + + /** + * 有効期限を取得 + * + * @param int $timestamp 起点になるUNIXタイムスタンプ + * @return int 有効期限のUNIXタイムスタンプの取得 + */ + public function generateExpiredAt(int $timestamp): int + { + return ($timestamp + self::$EXPIRE_SEC); + } + + + + /** + * {@inheritdoc} + * @throws DatabaseException + */ + public function authorize(AuthItem $item): bool + { + // ログインID、パスワード のどちらかが null もしくは 空文字 だった場合は認証失敗 + if (true === Strings::isEmpty($item->user_id) or true === Strings::isEmpty($item->password)) + { + return false; + } + + // 対象テーブル + $table_name = Authentication::$AUTHORIZE_TABLE_NAME; + + // 対象ユーザーがいるか? + $condition = new AuthItem(); + $condition->user_id = $item->user_id; + /** @var AuthItem $result */ + $result = (new Builder($this->connection))->select($table_name, $condition)->execute(AuthItem::class)->one(); + + // いなければ認証失敗 + if (true === is_null($result)) + { + return false; + } + + // パスワード照合 + if (false === password_verify($item->password, $result->password)) + { + return false; + } + + // 認証情報の保存 + $item->token = $this->encode(['user_id' => $item->user_id]); + $item->expired_at = date('Y-m-d H:i:s', $this->generateExpiredAt(time())); + $item->password = null; + // データベースに現在のトークンと保持期間の保存 + $condition = new AuthItem(); + $condition->rowid = $result->rowid; + $condition->rev = $result->rev; + (new Builder($this->connection))->update($table_name, $item, $condition)->execute(); + Session::$session->add(Authentication::SESSION_KEY, $item); + Session::commit(); + + return true; + } + + + + /** + * {@inheritdoc} + */ + public function deAuthorize(): bool + { + Session::$session->remove(Authentication::SESSION_KEY); + Session::commit(); + + return true; + } + + + + /** + * 認証のチェック + * 認証できていれば期間の延長 + * + * @param AuthItem|null $item + * @return bool true:チェック成功, false:チェック失敗 + * @throws DatabaseException + */ + public function isAuthenticated(AuthItem $item = null): bool + { + // 指定されない場合はsessionから取得 + if (true === is_null($item)) + { + $item = Session::$session->call(Authentication::SESSION_KEY); + } + // 認証itemが無い + if (true === is_null($item)) + { + Logger::debug('ログアウト:認証Itemが無い'); + Logger::debug(Session::$session); + return false; + } + // ユーザーIDとトークン、認証期間があるか + if (true === is_null($item->user_id) or true === is_null($item->token) or true === is_null($item->expired_at)) + { + Logger::debug('ログアウト:ユーザIDが無い(user_id=%s)、もしくはトークンが無い(token=%s)、もしくはタイムアウト(expired_at=%s)', + $item->user_id, + $item->token, + $item->expired_at + ); + return false; + } + + // すでに認証期間が切れている + $expired_ts = strtotime($item->expired_at); + $now_ts = time(); + if ($expired_ts < $now_ts) + { + Logger::debug('ログアウト:タイムアウト(%s) < 現在時間(%s)', + $expired_ts, + $now_ts + ); + return false; + } + + // 対象テーブル + $table_name = Authentication::$AUTHORIZE_TABLE_NAME; + + // まだ認証済みなので、認証期間の延長 + $authentic = new AuthItem(); + $authentic->expired_at = date('Y-m-d H:i:s', $this->generateExpiredAt(time())); + $condition = new AuthItem(); + $condition->user_id = $item->user_id; + $condition->token = $item->token; + // 更新 + $result = (new Builder($this->connection))->update($table_name, $authentic, $condition)->execute(); + + // 時間を延長 + /** @var AuthItem $item */ + $item = (new Builder($this->connection))->select($table_name, $condition)->execute(AuthItem::class)->one(); + Session::$session->add(Authentication::SESSION_KEY, $item); + Session::commit(); + + return ($result > 0); + } + + + + /** + * 署名の生成 + * + * @param string $unsigned_token 未署名トークン + * @param string $algorithm アルゴリズム + * @param string $secret 署名文字列 + * @return string + */ + private static function signing(string $unsigned_token, string $algorithm, string $secret): string + { + // メソッド + $method = self::$ALGORITHM_METHODS[$algorithm]['method']; + // ハッシュ + $hash = self::$ALGORITHM_METHODS[$algorithm]['hash']; + + /** @var string $signature 署名 */ + $signature = Intersection::fetch($method, [ + // HMAC + self::METHOD_HMAC => function () use ($hash, $unsigned_token, $secret) { + return hash_hmac($hash, $unsigned_token, $secret, true); + }, + // RSA + self::METHOD_RSA => function () use ($hash, $unsigned_token, $secret) { + $signature = ''; + $success = openssl_sign($unsigned_token, $signature, $secret, $hash); + if (false === $success) + { + throw new CitrusException('OpenSSL signing Error'); + } + return $signature; + }, + ], true); + + return ($signature ?: ''); + } + + + + /** + * 署名の確認 + * + * @param string $verifying_token 確認したいトークン + * @param string $signature 署名 + * @param string $secret シークレットキー + * @param string $algorithm アルゴリズム + * @return bool true:確認OK,false:確認NG + */ + private static function verifySignature(string $verifying_token, string $signature, string $secret, string $algorithm): bool + { + // メソッド + $method = self::$ALGORITHM_METHODS[$algorithm]['method']; + // ハッシュ + $hash = self::$ALGORITHM_METHODS[$algorithm]['hash']; + + // 署名の確認ができたかどうかを返却 + return Intersection::fetch($method, [ + // HMAC + self::METHOD_HMAC => function () use ($verifying_token, $signature, $secret, $hash) { + return (true === hash_equals($signature, hash_hmac($hash, $verifying_token, $secret, true))); + }, + // RSA + self::METHOD_RSA => function () use ($verifying_token, $signature, $secret, $hash) { + return (1 === openssl_verify($verifying_token, $signature, $secret, $hash)); + }, + ], true); + } +} diff --git a/src/Authentication/JWTException.php b/src/Authentication/JWTException.php new file mode 100644 index 0000000..c4f94f9 --- /dev/null +++ b/src/Authentication/JWTException.php @@ -0,0 +1,20 @@ + + * @license http://www.citrus.tk/ + */ + +namespace Citrus\Authentication; + +use Citrus\CitrusException; + +/** + * JWT認証用例外 + */ +class JWTException extends CitrusException +{ +} diff --git a/src/Authentication/Protocol.php b/src/Authentication/Protocol.php index cdd3c3a..548cd21 100644 --- a/src/Authentication/Protocol.php +++ b/src/Authentication/Protocol.php @@ -18,10 +18,10 @@ abstract class Protocol /** * 認証処理 * - * @param Item $item + * @param AuthItem $item * @return bool true:認証成功, false:認証失敗 */ - abstract public function authorize(Item $item): bool; + abstract public function authorize(AuthItem $item): bool; /** @@ -37,8 +37,8 @@ abstract public function deAuthorize(): bool; * 認証のチェック * 認証できていれば期間の延長 * - * @param Item|null $item + * @param AuthItem|null $item * @return bool true:チェック成功, false:チェック失敗 */ - abstract public function isAuthenticated(Item $item = null): bool; + abstract public function isAuthenticated(AuthItem $item = null): bool; } diff --git a/src/Controller/AuthController.php b/src/Controller/AuthController.php new file mode 100644 index 0000000..f39ac9f --- /dev/null +++ b/src/Controller/AuthController.php @@ -0,0 +1,105 @@ + + * @license http://www.besidesplus.net/ + */ + +namespace Citrus\Controller; + +use Citrus\Authentication; +use Citrus\Authentication\AuthItem; +use Citrus\Authentication\JWT; +use Citrus\Authentication\JWTException; +use Citrus\Contract; +use Citrus\Database\Connection\ConnectionPool; +use Citrus\Http\Server\Request; +use Citrus\Http\Server\Response; +use Citrus\Session; + +/** + * 認証処理 + */ +class AuthController extends ApiController +{ + /** + * サインイン + * + * @param Request $request + * @return Response + */ + public function signin(Request $request): Response + { + /** @var AuthItem $user */ + $user = Contract::sharedInstance()->autoParse(); + // 認証処理 + $is_authenticated = (new JWT(ConnectionPool::callDefault()))->authorize($user); + + // 認証失敗 + if (false === $is_authenticated) + { + header('HTTP/1.0 401 Unauthorized'); + exit; + } + + /** @var AuthItem $item 成功したらトークン取得 */ + $item = Session::$session->call(Authentication::SESSION_KEY); + return AuthResponse::withToken($item->token); + } + + + + /** + * ユーザー情報 + * + * @param Request $request + * @return Response + */ + public function user(Request $request): Response + { + $jwt = new JWT(ConnectionPool::callDefault()); + + // Bearer 文字列の取得 + $headers = getallheaders(); + $authorization = explode(' ', $headers['Authorization'])[1]; + $payload = $jwt->decode($authorization); + + $item = new AuthItem(); + $item->user_id = $payload['user_id']; + $item->expired_at = date('Y-m-d H:i:s', $payload['exp']); + $item->token = $authorization; + $jwt->isAuthenticated($item); + + /** @var AuthItem $item 成功したらトークン取得 */ + $item = Session::$session->call(Authentication::SESSION_KEY); + $item->remove([ + 'password', + ]); + return AuthResponse::withItem($item); + } + + + /** + * 認証チェック + */ + public function verify(): void + { + try + { + // Bearer 文字列の取得 + $headers = getallheaders(); + $authorization = explode(' ', $headers['Authorization'])[1]; + // decodeすることでExceptionチェックする + (new JWT(ConnectionPool::callDefault()))->decode($authorization); + } + catch (JWTException $e) + { + // 有効期限が切れたらException + header('HTTP/1.0 401 Unauthorized'); + exit; + } + } +} diff --git a/src/Controller/AuthResponse.php b/src/Controller/AuthResponse.php new file mode 100644 index 0000000..6e7c388 --- /dev/null +++ b/src/Controller/AuthResponse.php @@ -0,0 +1,73 @@ + + * @license http://www.besidesplus.net/ + */ + +namespace Citrus\Controller; + +use Citrus\Authentication\AuthItem; +use Citrus\Http\Server\Response; +use Citrus\Variable\Binders; + +/** + * 認証用レスポンス + */ +class AuthResponse extends Response +{ + use Binders; + + /** @var String 認証用トークン */ + public $token; + + /** @var array 認証用アイテム */ + public $user; + + + + /** + * token返却用レスポンスの生成 + * + * @param string $token 認証トークン + * @return $this + */ + public static function withToken(string $token): self + { + $self = new self(); + $self->token = $token; + $self->remove([ + 'result', + 'items', + 'messages', + 'user', + ]); + return $self; + } + + + + /** + * user返却用レスポンスの生成 + * + * @param AuthItem $item 認証アイテム + * @return $this + */ + public static function withItem(AuthItem $item): self + { + $self = new self(); + $self->user = [ + 'user_id' => $item->user_id, + ]; + $self->remove([ + 'result', + 'items', + 'messages', + 'token', + ]); + return $self; + } +} diff --git a/tests/AuthenticationTest.php b/tests/AuthenticationTest.php index d51345f..9010192 100644 --- a/tests/AuthenticationTest.php +++ b/tests/AuthenticationTest.php @@ -12,7 +12,7 @@ use Citrus\Authentication; use Citrus\Authentication\Database; -use Citrus\Authentication\Item; +use Citrus\Authentication\AuthItem; use Citrus\Configure\ConfigureException; use Citrus\Database\Connection\Connection; use Citrus\Database\DSN; @@ -74,7 +74,7 @@ public function setUp(): void // データ生成 $pdo = new \PDO(sprintf('sqlite:%s', $this->sqlite_file)); - $pdo->query('CREATE TABLE users (user_id INT, password TEXT, token TEXT, keep_at TEXT, status INT, created_at TEXT, updated_at TEXT, rowid INT, rev INT);'); + $pdo->query('CREATE TABLE users (user_id INT, password TEXT, token TEXT, expired_at TEXT, status INT, created_at TEXT, updated_at TEXT, rowid INT, rev INT);'); $pdo->query('INSERT INTO users VALUES (1, "'. password_hash('hogehoge', PASSWORD_DEFAULT) .'", "", "", 0, "2019-01-01", "2019-01-01", 1, 1);'); $dsn = DSN::getInstance()->loadConfigures($this->configures); @@ -121,8 +121,8 @@ public function authorize_認証を通す() $authentication = Authentication::sharedInstance()->loadConfigures($this->configures); // 認証処理 - $authItem = new Item(); - $authItem->user_id = 1; + $authItem = new AuthItem(); + $authItem->user_id = '1'; $authItem->password = 'hogehoge'; $is_auth = $authentication->authorize($authItem); $this->assertTrue($is_auth); diff --git a/tests/Sample/Business/Formmap/Login.php b/tests/Sample/Business/Formmap/Login.php index 14bc776..bbc8d82 100644 --- a/tests/Sample/Business/Formmap/Login.php +++ b/tests/Sample/Business/Formmap/Login.php @@ -8,13 +8,13 @@ * @license http://www.besidesplus.net/ */ -use Citrus\Authentication\Item; +use Citrus\Authentication\AuthItem; use Citrus\Formmap\ElementType; return [ 'Login' => [ 'login' => [ - 'class' => Item::class, + 'class' => AuthItem::class, 'elements' => [ 'user_id' => [ 'form_type' => ElementType::FORM_TYPE_TEXT,