From 6142939ec84e99383ad460d315d1dea3ce272d6b Mon Sep 17 00:00:00 2001 From: mostafa Date: Thu, 5 Dec 2019 03:00:19 +0600 Subject: [PATCH] daktari --- composer.json | 44 +++ config/kauth.php | 68 ++++ .../2019_02_04_082555_create_kauth_table.php | 43 +++ src/Auth/Auth.php | 295 ++++++++++++++++++ src/Facades/Auth.php | 25 ++ src/KauthServiceProvider.php | 48 +++ src/Model/KauthModel.php | 22 ++ src/Token/Token.php | 84 +++++ test/.gitkeep | 0 9 files changed, 629 insertions(+) create mode 100644 composer.json create mode 100644 config/kauth.php create mode 100644 migrations/2019_02_04_082555_create_kauth_table.php create mode 100644 src/Auth/Auth.php create mode 100644 src/Facades/Auth.php create mode 100644 src/KauthServiceProvider.php create mode 100644 src/Model/KauthModel.php create mode 100644 src/Token/Token.php create mode 100644 test/.gitkeep diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..dadb514 --- /dev/null +++ b/composer.json @@ -0,0 +1,44 @@ +{ + "name": "code4mk/kauth", + "description": "kauth is JWT API Authentication ( jwt-auth ) for laravel", + "keywords": [ + "jwt", + "jwt-auth", + "laravel", + "laravel-jwt", + "auth", + "code4mk", + "0devco", + "api" + ], + "homepage": "https://github.com/code4mk/kauth", + "support": { + "issues": "https://github.com/code4mk/kauth/issues", + "source": "https://github.com/code4mk/kauth" + }, + "license": "MIT", + "authors": [ + { + "name": "code4mk", + "email": "hiremostafa@gmail.com", + "website": "https://code4mk.org" + } + ], + "require": { + "firebase/php-jwt": "^5.0" + }, + "autoload": { + "psr-4": { + "Kauth\\": "src/" + } + }, + "extra": { + "laravel": { + "providers": [ + "Kauth\\KauthServiceProvider" + ] + } + }, + "prefer-stable": true, + "minimum-stability": "dev" +} diff --git a/config/kauth.php b/config/kauth.php new file mode 100644 index 0000000..69916e4 --- /dev/null +++ b/config/kauth.php @@ -0,0 +1,68 @@ + "", + + /* + |-------------------------------------------------------------------------- + | Kauth token expired duration + |-------------------------------------------------------------------------- + | + | You can set duration of your token + | pattern will be follow P7Y5M4DT4H3M2S + | http://php.net/manual/en/datetime.gettimestamp.php + */ + + "token_exp" => "", + + /* + |-------------------------------------------------------------------------- + | Kauth jwt payload iss and aud + |-------------------------------------------------------------------------- + | + | You can set jwt iss + | + | your url host name + */ + "payload" => [ + "iss" => "" + ], + + /* + |-------------------------------------------------------------------------- + | Kauth cookie auth + |-------------------------------------------------------------------------- + | + | You can use for socialite system + | + | + */ + + "cookie_auth" => false, + + /* + |-------------------------------------------------------------------------- + | Kauth guard setup + |-------------------------------------------------------------------------- + | + | You can set guard + | set table name + | + */ + + "guard" => [ + "users" => [ + "table" => "users", + ], + ], +]; diff --git a/migrations/2019_02_04_082555_create_kauth_table.php b/migrations/2019_02_04_082555_create_kauth_table.php new file mode 100644 index 0000000..085cd55 --- /dev/null +++ b/migrations/2019_02_04_082555_create_kauth_table.php @@ -0,0 +1,43 @@ +increments('id'); + $table->text('tokon')->nullable(); + $table->integer('user_id')->nullable(); + $table->integer('iat')->nullable(); + $table->integer('exp')->nullable(); + $table->string('ip')->nullable(); + $table->string('browser')->nullable(); + $table->string('device')->nullable(); + $table->string('os')->nullable(); + $table->string('login')->nullable(); + $table->string('guard')->nullable(); + $table->string('user_type')->nullable(); + $table->boolean('active')->default(true); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('kauth'); + } +} diff --git a/src/Auth/Auth.php b/src/Auth/Auth.php new file mode 100644 index 0000000..6d33849 --- /dev/null +++ b/src/Auth/Auth.php @@ -0,0 +1,295 @@ + + * @author @0devco + * @since 2019 + * @copyright 0dev.co (https://0dev.co) + */ + +use Illuminate\Http\Request; +use Kauth\Model\KauthModel; +use Kauth\Token\Token; +use DateTime; +use Schema; +use Config; +use Hash; +use DB; +use Parrotx\Dakapi\App\Http\Controllers\Controller; +class Auth extends Controller +{ + + protected $guard; + + protected $socialite; + + protected $user_type = ''; + + protected $daktariApp = false; + + public function __construct() + { + $this->guard(); + $this->socialite(false); + } + + public function daktariui() + { + $this->daktariApp = true; + return $this; + } + + + /** + * + * set gaurd name + * + *@return string guard + */ + public function guard($guard ='users') + { + $this->guard = $guard; + return $this; + } + + /** + * + * socialite system + * + *@return boolean + */ + public function socialite($status = true) + { + $this->socialite = $status; + return $this; + } + + + /** + * + * attempt credentials + * + *@return string jwt + */ + public function attempt($credentials) + { + $credential = []; + $getTokennames = $credentials['usernames'] ?? []; + $getTokenname = $credentials['username'] ?? ''; + + // store credentials without password & username + + foreach ($credentials as $key => $value){ + if($key === 'password' || !empty($key === 'usernames') || !empty($key === 'username')){ + // nothing + } else { + $credential[$key] = $value; + } + } + + // fetch user by credentials + + $getToken = DB::table(Config::get('kauth.guard.' . $this->guard . '.table')) + // multiple username accept (id||username||email >> etc) + ->where(function ($query) use ($getTokennames,$getTokenname){ + foreach ($getTokennames as $key => $value) { + $query->orWhere($value,$getTokenname) + ->orWhere($value,$getTokenname); + } + }) + ->where(function ($query) use ($credential) { + foreach ($credential as $key => $value) { + $query->where($key,$value); + } + }) + ->first(); + + + // check has user and socialite + + if(!empty($getToken) && !($this->socialite)){ + $getTokenPassword = Hash::check($credentials['password'],$getToken->password); + } elseif (!empty($getToken) && $this->socialite) { + $getTokenPassword = true; + } else { + $getTokenPassword = false; + } + + // check user and password then store jwt token + + if (!empty($getToken) && $getTokenPassword ) { + $jwt = new KauthModel; + if($this->daktariApp && $getToken->type == 'doctor'){ + $jwt->user_id = $getToken->doctor_id; + $jwt->user_type = $getToken->type; + }elseif ($this->daktariApp && $getToken->type == 'patient') { + $jwt->user_id = $getToken->patient_id; + $jwt->user_type = $getToken->type; + }else{ + $jwt->user_id = $getToken->id; + } + + $jwt->browser = \Request::get('browser'); + $jwt->os = \Request::get('os'); + $jwt->device = \Request::get('device'); + $jwt->ip = \Request::get('ip'); + $jwt->active = true; + $jwt->guard = $this->guard; + $jwt->save(); + + $secret = new Token(); + if (Schema::hasColumn(Config::get('kauth.guard.' . $this->guard . '.table'), 'user_type')) { + $this->user_type = $getToken->user_type; + } + $tokon = $secret->create($jwt->id,$this->user_type); + $payloader = $secret->payloader($tokon); + $jwt->tokon = $tokon; + $jwt->iat = $payloader['iat']; + $jwt->exp = $payloader['expM']; + + + if (Schema::hasColumn($this->guard, 'user_type')) { + $jwt->user_type = $getToken->user_type; + } + $jwt->save(); + return [ + 'token' => $jwt->tokon, + 'type' => $getToken->type, + 'did' => $getToken->doctor_id, + 'pid' => $getToken->patient_id + ]; + } + return "wrong credentials"; + } + + /** + * + * auth check + * + *@return boolean + */ + public function check() + { + try { + $token = new Token(); + $getToken = KauthModel::where('tokon',$token->tokon())->first(); + $instanceTime = new DateTime(); + if(!empty($getToken) && ($instanceTime->getTimestamp() <= $getToken->exp)){ + return true; + } + return false; + } catch (\Exception $e) { + return "jwt-error"; + } + + } + + /** + * + * auth user id + * + *@return integer id + */ + public function id() + { + try { + $token = new Token(); + $getToken = KauthModel::where('tokon',$token->tokon())->first(); + $instanceTime = new DateTime(); + if(!empty($getToken) && ($instanceTime->getTimestamp() <= $getToken->exp)){ + if($this->daktariApp){ + $attribute = [ + "id" => $getToken->user_id, + "type" => $getToken->user_type + ]; + }else{ + $attribute = $getToken->user_id; + } + + return $attribute; + } + return 0; + } catch (\Exception $e) { + return "jwt-error"; + } + + } + + public function auths() + { + $auths = KauthModel::where('user_id',$this->id()) + ->orderBy('id','desc') + ->get(); + return $auths; + } + + /** + * + * auth logout + * + * delete auth credentials + */ + public function logout() + { + try { + $token = new Token(); + $getToken = KauthModel::where('tokon',$token->tokon())->first(); + $getToken->delete(); + } catch (\Exception $e) { + return "jwt-error"; + } + + + } + + /** + * + * logout all devices + * + * delete auth user's all token + * without current token id + */ + public function logoutOtherDevices() + { + try { + $token = new Token(); + $getToken = KauthModel::where('tokon',$token->tokon())->first(); + + // fetch all token without current token + + KauthModel::where('user_id',$getToken->user_id) + -> where(function ($query) use ($getToken){ + $query->whereNotIn('id',[$getToken->id]); + }) + ->delete(); + } catch (\Exception $e) { + return "jwt-error"; + } + + } + + /** + * + * refresh token + * + * edit existing token + * + */ + public function refreshToken() + { + try { + $token = new Token(); + $getToken = KauthModel::where('tokon',$token->tokon())->first(); + $getToken->tokon = $token->create($getToken->id); + $payloader = $token->payloader($token->create($getToken->id)); + $getToken->iat = $payloader['iat']; + $getToken->exp = $payloader['expM']; + $getToken->save(); + return $getToken->tokon; + } catch (\Exception $e) { + return "jwt-error"; + } + } +} diff --git a/src/Facades/Auth.php b/src/Facades/Auth.php new file mode 100644 index 0000000..20fe398 --- /dev/null +++ b/src/Facades/Auth.php @@ -0,0 +1,25 @@ + + * @author @0devco + * @since 2019 + * @copyright 0dev.co (https://0dev.co) + */ + +use Illuminate\Support\Facades\Facade; + +class Auth extends Facade +{ + /** + * Get the registered name of the component. + * + * @return string + */ + protected static function getFacadeAccessor() + { + return 'kauth'; + } +} diff --git a/src/KauthServiceProvider.php b/src/KauthServiceProvider.php new file mode 100644 index 0000000..acd2260 --- /dev/null +++ b/src/KauthServiceProvider.php @@ -0,0 +1,48 @@ + +* @author @0devco +* @since 2019 +* @copyright 0dev.co (https://0dev.co) +*/ + +use Illuminate\Support\ServiceProvider; +use Illuminate\Foundation\AliasLoader; +use Kauth\Auth\Auth; + +class KauthServiceProvider extends ServiceProvider +{ + /** + * Bootstrap any application services. + * + * @return void + */ + public function boot() + { + // publish database + $this->publishes([ + __DIR__ . '/../migrations/' => base_path('/database/migrations'), + ], 'migrations'); + // publish config + $this->publishes([ + __DIR__ . '/../config/kauth.php' => config_path('kauth.php'), + ], 'config'); + //load alias + AliasLoader::getInstance()->alias('Kauth', 'Kauth\Facades\Auth'); + } + + /** + * Register any application services. + * + * @return void + */ + public function register() + { + $this->app->bind('kauth', function () { + return new Auth; + }); + } +} diff --git a/src/Model/KauthModel.php b/src/Model/KauthModel.php new file mode 100644 index 0000000..ee6c4ae --- /dev/null +++ b/src/Model/KauthModel.php @@ -0,0 +1,22 @@ + + * @author @0devco + * @since 2019 + * @copyright 0dev.co (https://0dev.co) + */ + +use Illuminate\Database\Eloquent\Model; + +class KauthModel extends Model +{ + /** + * The table associated with the model. + * + * @var string + */ + protected $table = 'kauth'; +} diff --git a/src/Token/Token.php b/src/Token/Token.php new file mode 100644 index 0000000..1bf1034 --- /dev/null +++ b/src/Token/Token.php @@ -0,0 +1,84 @@ + +* @author @0devco +* @since 2019 +* @copyright 0dev.co (https://0dev.co) +*/ + +use \Firebase\JWT\JWT; +use Illuminate\Http\Request; +use DateTime; +use DateInterval; +use Config; +use Cookie; + +class Token +{ + public function create($tokenID,$userType){ + $issueDate = new DateTime(); + $expiredDate = new DateTime(); + $tokenDuration = Config::get('kauth.token_exp') ? Config::get('kauth.token_exp') : 'P32D'; + $jwtIss = Config::get('kauth.payload.iss') ? Config::get('kauth.payload.iss') : 'https://code4mk.org'; + $jwtAud = Config::get('kauth.payload.aud') ? Config::get('kauth.payload.aud') : 'https://code4mk.org'; + $expiredDate->add(new DateInterval($tokenDuration)); + $key = "example_key"; + $token = array( + "iss" => $jwtIss, + "ut" => $userType, + "iat" => $issueDate->getTimestamp(), + "expM" => $expiredDate->getTimestamp(), + "tid" => $tokenID, + ); + $jwt = JWT::encode($token,$key); + + return $jwt; + } + + public function tokon(){ + $token_header = Config::get('kauth.token_header_name') ? Config::get('kauth.token_header_name') : 'tokon'; + $tokon = \Request::header($token_header); + + if($tokon === null && (Config::get('kauth.cookie_auth')) ){ + try { + //return $_COOKIE['kauth_token']; + return $_COOKIE['authtoken']; + } catch (\Exception $e) { + return $e; + } + + + } + return $tokon; + } + + public function payload(){ + $key = "example_key"; + $tokon = $this->tokon(); + $jwt = JWT::decode($tokon, $key, array('HS256')); + $payload = (array) $jwt; + return $payload; + } + + public function payloader($tokon){ + $key = "example_key"; + $jwt = JWT::decode($tokon, $key, array('HS256')); + $payload = (array) $jwt; + return $payload; + } + + public function isExpired(){ + try { + $instanceTime = new DateTime(); + if($instanceTime->getTimestamp() > $this->payload()["expM"] ){ + return true; + } + return false; + } catch (\Exception $e) { + return "jwt token is error"; + } + } +} diff --git a/test/.gitkeep b/test/.gitkeep new file mode 100644 index 0000000..e69de29