| Current Path : /var/www/html/ebookingdbkl/frontend/controllers/ |
| Current File : /var/www/html/ebookingdbkl/frontend/controllers/AuthController.php |
<?php
namespace frontend\controllers;
use Yii;
use common\models\FrontendUser;
use yii\filters\VerbFilter;
use yii\web\Response;
use common\models\Notification;
class AuthController extends \yii\web\Controller
{
public function beforeAction($action)
{
\Yii::$app->response->format = Response::FORMAT_JSON;
return parent::beforeAction($action);
}
public function behaviors() {
return [
'authenticator' => [
'class' => \sizeg\jwt\JwtHttpBearerAuth::class,
'except' => [
'login',
'refresh-token',
'options',
'forget-password'
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'refresh-token' => ['post'],
'login' => ['post'],
'change-password' => ['post'],
],
],
];
}
public $enableCsrfValidation = false;
public function actionChangePassword() {
try {
$user = FrontendUser::findOne(Yii::$app->user->id);
$pass = isset($_POST['password']) ? $_POST['password'] : null;
if(empty($user)) {
throw new \Exception('User does not exist');
}
if(empty($pass)) {
throw new \Exception('password is required.');
}
$user->password_hash = Yii::$app->getSecurity()->generatePasswordHash($pass);
if(!$user->save()) {
throw new \Exception('Model Error :-' . json_encode($user->errors));
}
return [
'success' => true,
'user_id' => Yii::$app->user->id
];
} catch (\Throwable $t) {
Yii::$app->response->statusCode = 500;
return [
'success' => false,
'message' => $t->getMessage(),
];
}
}
public function actionForgetPassword() {
try {
$empno = isset($_POST['emp_no']) ? $_POST['emp_no'] : null;
if(empty($empno)) {
throw new \Exception('emp_no / ic number is required.');
}
$user = FrontendUser::find()->where(['emp_no' => $empno])->one();
if(empty($user)) {
$user = FrontendUser::find()->where(['ic_number' => $empno])->one();
}
if(empty($user)) {
throw new \Exception('User does not exist');
}
if(empty($user->email)) {
throw new \Exception('User does not have an email.');
}
$pass = Yii::$app->security->generateRandomString(8);
$user->password_hash = Yii::$app->getSecurity()->generatePasswordHash($pass);
if(!$user->save()) {
throw new \Exception('Model Error :-' . json_encode($user->errors));
}
//email
Notification::email(0000, 'F_PASS',
[
'subject' => 'Lupa kata laluan',
'content' => 'Salam Sejahtera '. $user->fullname .', Kata laluan telah di tukar kepada:- '. $pass . ' , Sila tukar kata laluan anda setelah anda berjaya log masuk.'
],
$user->email
);
return [
'success' => true,
'user_id' => $user->id,
'email' => $user->email
];
} catch (\Throwable $t) {
Yii::$app->response->statusCode = 500;
return [
'success' => false,
'message' => $t->getMessage(),
];
}
}
private function generateJwt(\common\models\FrontendUser $user) {
$jwt = Yii::$app->jwt;
$signer = $jwt->getSigner('HS256');
$key = $jwt->getKey();
$time = time();
$jwtParams = Yii::$app->params['jwt'];
return $jwt->getBuilder()
->issuedBy($jwtParams['issuer'])
->permittedFor($jwtParams['audience'])
->identifiedBy($jwtParams['id'], true)
->issuedAt($time)
->expiresAt($time + $jwtParams['expire'])
->withClaim('uid', $user->id)
->getToken($signer, $key);
}
/**
* @throws yii\base\Exception
*/
private function generateRefreshToken(\common\models\FrontendUser $user, \common\models\FrontendUser $impersonator = null): \frontend\models\UserRefreshToken {
$refreshToken = Yii::$app->security->generateRandomString(200);
// TODO: Don't always regenerate - you could reuse existing one if user already has one with same IP and user agent
$userRefreshToken = new \frontend\models\UserRefreshToken([
'urf_userID' => $user->id,
'urf_token' => $refreshToken,
'urf_ip' => Yii::$app->request->userIP,
'urf_user_agent' => Yii::$app->request->userAgent,
'urf_created' => gmdate('Y-m-d H:i:s'),
]);
if (!$userRefreshToken->save()) {
throw new \yii\web\ServerErrorHttpException('Failed to save the refresh token: '. $userRefreshToken->getErrorSummary(true));
}
// Send the refresh-token to the user in a HttpOnly cookie that Javascript can never read and that's limited by path
Yii::$app->response->cookies->add(new \yii\web\Cookie([
'name' => 'refresh-token',
'value' => $refreshToken,
'httpOnly' => true,
'sameSite' => 'none',
'secure' => true,
'path' => '/auth/refresh-token', //endpoint URI for renewing the JWT token using this refresh-token, or deleting refresh-token
]));
return $userRefreshToken;
}
public function actionLogin() {
if(isset($_POST) && !empty($_POST)) {
$_POST = filter_var_array($_POST, FILTER_SANITIZE_STRING);
$model = new \common\models\FrontendLoginForm();
$model->username = $_POST['username'];
$model->password = $_POST['password'];
if (!$model->login()) {
Yii::$app->response->statusCode = 401; // forbiden
return $this->asJson([
'success' => false,
'message' => 'Invalid Login / Password.'
]);
}
$user = Yii::$app->user->identity;
$token = $this->generateJwt($user);
$this->generateRefreshToken($user);
return $this->asJson([
'success' => true,
'user' => $user,
'token' => (string) $token,
]);
} else {
return $this->asJson($model->getFirstErrors());
}
}
public function actionRefreshToken() {
$refreshToken = Yii::$app->request->cookies->getValue('refresh-token', false);
if (!$refreshToken) {
return new \yii\web\UnauthorizedHttpException('No refresh token found.');
}
$userRefreshToken = \frontend\models\UserRefreshToken::findOne(['urf_token' => $refreshToken]);
if (Yii::$app->request->getMethod() == 'POST') {
// Getting new JWT after it has expired
if (!$userRefreshToken) {
return new \yii\web\UnauthorizedHttpException('The refresh token no longer exists.');
}
$user = \common\models\FrontendUser::find() //adapt this to your needs
->where(['id' => $userRefreshToken->urf_userID])
->andWhere(['not', ['status' => 'inactive']]) // change to proper status after the development
->one();
if (!$user) {
$userRefreshToken->delete();
return new \yii\web\UnauthorizedHttpException('The user is inactive.');
}
$token = $this->generateJwt($user);
$this->asJson([
'success' => true,
'token' => (string) $token,
]);
} elseif (Yii::$app->request->getMethod() == 'DELETE') {
// Logging out
if ($userRefreshToken && !$userRefreshToken->delete()) {
return new \yii\web\ServerErrorHttpException('Failed to delete the refresh token.');
}
return $this->asJson([
'success' => true
]);
} else {
return $this->asJson([
'success' => false,
'message' => 'The user is inactive.'
]);
}
}
public function afterSave($isInsert, $changedOldAttributes) {
// Purge the user tokens when the password is changed
if (array_key_exists('usr_password', $changedOldAttributes)) {
\frontend\models\UserRefreshToken::deleteAll(['urf_userID' => $this->userID]);
}
return parent::afterSave($isInsert, $changedOldAttributes);
}
}