I have tried to implement JWT based authentication in my CakePHP 4 application. Token is successfully generated and I have verified it on jwt.io as well. But while doing request for the route which should validate token it's giving following error "Authentication is required to continue".
While investigation the issue I the dd($this->Authentication); in the Controller's initialize function I see following reason In the object. "Signature verification failed" response.
Any help in this case?
Thanks,
Following is my code
routes.php
web related routes....
here are API related routes.
$routes->prefix('api', ['path' => '/api'], function ($routes) {
$routes->setExtensions(['json']);
// $routes->resources('register');
$routes->post('/user/add', ['controller' => 'User', 'action' => 'add']);
$routes->post('/user/login', ['controller' => 'User', 'action' => 'login']);
$routes->post('/user/index', ['controller' => 'User', 'action' => 'index']);
$routes->get('/user/logout', ['controller' => 'User', 'action' => 'logout']);
$routes->fallbacks(DashedRoute::class);
});
src/Application.php code
<?php
declare(strict_types=1);
/**
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* #copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
* #link https://cakephp.org CakePHP(tm) Project
* #since 3.3.0
* #license https://opensource.org/licenses/mit-license.php MIT License
*/
namespace App;
use Cake\Core\Configure;
use Cake\Core\ContainerInterface;
use Cake\Core\Exception\MissingPluginException;
use Cake\Datasource\FactoryLocator;
use Cake\Error\Middleware\ErrorHandlerMiddleware;
use Cake\Http\BaseApplication;
use Cake\Http\Middleware\BodyParserMiddleware;
use Cake\Http\Middleware\CsrfProtectionMiddleware;
use Cake\Http\MiddlewareQueue;
use Cake\ORM\Locator\TableLocator;
use Cake\Routing\Middleware\AssetMiddleware;
use Cake\Routing\Middleware\RoutingMiddleware;
use Authentication\AuthenticationService;
use Authentication\AuthenticationServiceInterface;
use Authentication\AuthenticationServiceProviderInterface;
use Authentication\Identifier\IdentifierInterface;
use Authentication\Middleware\AuthenticationMiddleware;
// use Cake\Http\MiddlewareQueue;
use Cake\Routing\Router;
use Psr\Http\Message\ServerRequestInterface;
/**
* Application setup class.
*
* This defines the bootstrapping logic and middleware layers you
* want to use in your application.
*/
class Application extends BaseApplication implements AuthenticationServiceProviderInterface
{
/**
* Load all the application configuration and bootstrap logic.
*
* #return void
*/
public function bootstrap(): void
{
$this->addPlugin('Migrations');
// Call parent to load bootstrap from files.
parent::bootstrap();
if (PHP_SAPI === 'cli') {
$this->bootstrapCli();
} else {
FactoryLocator::add(
'Table',
(new TableLocator())->allowFallbackClass(false)
);
}
/*
* Only try to load DebugKit in development mode
* Debug Kit should not be installed on a production system
*/
if (\Cake\Core\Configure::read('debug')) {
$this->addPlugin('DebugKit');
}
$this->addPlugin('Authentication');
// Load more plugins here
}
/**
* Setup the middleware queue your application will use.
*
* #param \Cake\Http\MiddlewareQueue $middlewareQueue The middleware queue to setup.
* #return \Cake\Http\MiddlewareQueue The updated middleware queue.
*/
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
$csrf = new CsrfProtectionMiddleware(['httponly' => true]);
// Token check will be skipped when callback returns `true`.
$csrf->skipCheckCallback(function ($request) {
// Skip token check for API URLs.
// return $request->getPath() == '/dwolla_webhook';
return $request->getPath() == '/dwolla_webhook' || $request->getParam('prefix') == 'Api';
});
$middlewareQueue
// Catch any exceptions in the lower layers,
// and make an error page/response
->add(new ErrorHandlerMiddleware(\Cake\Core\Configure::read('Error')))
// Handle plugin/theme assets like CakePHP normally does.
->add(new AssetMiddleware([
'cacheTime' => \Cake\Core\Configure::read('Asset.cacheTime'),
]))
// ->add(function (
// \Psr\Http\Message\ServerRequestInterface $request,
// \Psr\Http\Server\RequestHandlerInterface $handler
// ) {
// try {
// // continue with the next middleware
// return $handler->handle($request);
// } catch (\Cake\Http\Exception\InvalidCsrfTokenException $exception) {
// // handle the catched exception
// $response = new \Cake\Http\Response();
// return $response->withStringBody('Oh noes, CSRF error!');
// }
// })
// Add routing middleware.
// If you have a large number of routes connected, turning on routes
// caching in production could improve performance. For that when
// creating the middleware instance specify the cache config name by
// using it's second constructor argument:
// `new RoutingMiddleware($this, '_cake_routes_')`
->add(new RoutingMiddleware($this))
// Parse various types of encoded request bodies so that they are
// available as array through $request->getData()
// https://book.cakephp.org/4/en/controllers/middleware.html#body-parser-middleware
->add(new BodyParserMiddleware())
// Cross Site Request Forgery (CSRF) Protection Middleware
// https://book.cakephp.org/4/en/controllers/middleware.html#cross-site-request-forgery-csrf-middleware
// ->add(new CsrfProtectionMiddleware([
// 'httponly' => true,
// ]));
->add($csrf)
->add(new AuthenticationMiddleware($this));
return $middlewareQueue;
}
/**
* Returns a service provider instance.
*
* #param \Psr\Http\Message\ServerRequestInterface $request Request
* #return \Authentication\AuthenticationServiceInterface
*/
public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
$service = new AuthenticationService();
// Load identifiers
$service->loadIdentifier('Authentication.Password', [
'fields' => [
'username' => 'username',
'password' => 'password',
],
// 'algorithm' => 'HS256',
'resolver' => [
'className' => 'Authentication.Orm',
// 'finder' => 'active',
'userModel' => 'User',
],
]);
// Load the authenticators
$service->loadAuthenticator('Authentication.Form', [
'fields' => [
'username' => 'username',
'password' => 'password',
],
'returnPayload' => false,
// 'loginUrl' => '/users/token.json'
]);
$service->loadAuthenticator('Authentication.Jwt', [
'secretKey' => file_get_contents(CONFIG . '/jwt.pem'),
'header' => 'Authorization',
// 'queryParam' => 'token',
'tokenPrefix' => 'Bearer',
'algorithm' => 'HS256',
'returnPayload' => false,
]);
$service->loadIdentifier('Authentication.JwtSubject', [
// 'tokenField' => 'id',
// 'dataField' => 'id',
'algorithm' => 'HS256',
]);
// Configure the service. (see below for more details)
return $service;
}
/**
* Register application container services.
*
* #param \Cake\Core\ContainerInterface $container The Container to update.
* #return void
* #link https://book.cakephp.org/4/en/development/dependency-injection.html#dependency-injection
*/
public function services(ContainerInterface $container): void
{
}
/**
* Bootstrapping for CLI application.
*
* That is when running commands.
*
* #return void
*/
protected function bootstrapCli(): void
{
try {
$this->addPlugin('Bake');
} catch (MissingPluginException $e) {
// Do not halt if the plugin is missing
}
$this->addPlugin('Migrations');
// Load more plugins here
}
}
APIController code
<?php
namespace App\Controller;
use Cake\Controller\Controller;
use Cake\Event\EventInterface;
class ApiController extends Controller
{
public function initialize(): void
{
parent::initialize();
$this->loadComponent('RequestHandler');
$this->loadComponent('Authentication.Authentication');
}
private function setCorsHeaders()
{
$this->response = $this->response->cors($this->request)
->allowOrigin(['*'])
->allowMethods(['*'])
->allowHeaders(['x-xsrf-token', 'Origin', 'Content-Type', 'X-Auth-Token', 'Access-Control-Allow-Headers', 'Authorization', 'HTTP_Authorization', 'X-Requested-With'])
->allowCredentials(['true'])
->exposeHeaders(['Link'])
->maxAge(300)
->build();
}
public function beforeRender(EventInterface $event)
{
// .......
$this->setCorsHeaders();
}
public function beforeFilter(EventInterface $event)
{
// ......
if ($this->request->is('OPTIONS')) {
$this->setCorsHeaders();
return $this->response;
}
}
}
UserController code
<?php
namespace App\Controller\Api;
use Cake\View\JsonView;
use Firebase\JWT\JWT;
use App\Controller\ApiController;
use Lib\PpState\PpState;
class UserController extends ApiController
{
// public function viewClasses(): array
// {
// return [JsonView::class];
// }
public function initialize(): void
{
parent::initialize();
$this->loadModel('User');
// var_dump(debug_backtrace());
// dd($_SERVER['HTTP_AUTHORIZATION']);
dd($this->Authentication);
$this->Authentication->allowUnauthenticated(['login', 'add']);
// dd('hhesssssheh');
}
public function index()
{
// dd('ashsh');
$this->Authentication->logout();
// dd($this->Authentication->getResult());
// dd($this->Authentication);
$json = [
'success' => true,
'message' => 'welcome',
];
$this->set(compact('json'));
$this->viewBuilder()->setOption('serialize', 'json');
}
public function logout()
{
// JWT::destroy();
// $decoded = JWT::decode($jwt, new Key($key, 'HS256'));
// dd($decoded);
// dd($this->request);
//
// $result = $this->Authentication->getResult();
// dd($result);
// $json = ['route' => 'logout'];
// if ($result->isValid()) {
// $this->Authentication->logout();
// // $this->set('user', [
// // 'message' => 'You are successfully logout'
// // ]);
// $json = ['message' => 'You are successfully logout'];
// }
$json = [
'success' => true,
'message' => 'You are successfully logout',
];
$this->set(compact('json'));
$this->viewBuilder()->setOption('serialize', 'json');
// $this->viewBuilder->setOption('serialize', 'user');
// $this->set(compact('json'));
// $this->viewBuilder()->setOption('serialize', 'json');
// If the user is logged in send them away.
// if ($result->isValid()) {
// $target = $this->Authentication->getLoginRedirect() ?? '/home';
// return $this->redirect($target);
// }
// if ($this->request->is('post')) {
// $this->Flash->error('Invalid username or password');
// }
}
public function add()
{
if ($this->User->emailInUse($this->request->getData('username'))) {
$json = [
'success' => false,
'message' => 'User email already exists, Please choose different email',
];
} else {
$user = $this->User->newEntity($this->request->getData());
$newUser = $this->User->save($user);
if (!empty($newUser->id)) {
$privateKey = file_get_contents(CONFIG . '/jwt.key');
$payload = [
'iss' => 'myapp',
'sub' => $newUser->id,
'iat' => time(),
'exp' => time() + 300,
];
if (!in_array($this->request->getData('st'), PpState::getActiveStateAbbreviations())) {
$json = [
'success' => false,
'message' => 'Oh, bother! Poppins Payroll does not yet operate in your state. We’ve made note of your location, so we know where we’re needed. We look forward to being able to serve you soon.',
];
} else {
$json = [
'success' => true,
'token' => JWT::encode($payload, $privateKey, 'HS256'),
];
}
} else {
$json = [
'success' => false,
'message' => 'Issue in user registration',
];
}
}
$this->set(compact('json'));
$this->viewBuilder()->setOption('serialize', 'json');
}
public function login()
{
$result = $this->Authentication->getResult();
if ($result->isValid()) {
$privateKey = file_get_contents(CONFIG . '/jwt.key');
$user = $result->getData();
$payload = [
'iss' => 'myapp',
'sub' => $user->id,
'iat' => time(),
'exp' => time() + 60,
];
$json = [
'success' => true,
'token' => JWT::encode($payload, $privateKey, 'HS256'),
];
} else {
$this->response = $this->response->withStatus(401);
$json = [];
}
$this->set(compact('json'));
$this->viewBuilder()->setOption('serialize', 'json');
}
}
Postman API calls
I am looking for CakePHP 4 Authorization issue to solve while implementing JWT token bases APIs
The problem is the order in which you load the authenticator in your Application.php.
You should load your Jwt first and then the Form authenticator.
$service->loadAuthenticator('Authentication.Jwt', [
'secretKey' => Security::getSalt(),
'returnPayload' => false
]);
$service->loadAuthenticator('Authentication.Form', [
'fields' => $fields,
'loginUrl' => '/users/login'
]);
Related
I have lumen + jwt restapi with custom users table (ex : pengguna) with nomor as primary key and tgl_lahir as password..there is no problem with api/login and it's generate a token but when i try with other route such as api/buku, the return always 401 unauthorized although the authorization header contains valid token after login
my models like
<?php
namespace App;
use Illuminate\Auth\Authenticatable;
use Laravel\Lumen\Auth\Authorizable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Model implements AuthenticatableContract, AuthorizableContract, JWTSubject
{
use Authenticatable, Authorizable;
protected $primaryKey = 'nomor';
protected $table = 'pengguna';
public $timestamps = false;
protected $fillable = [
'nomor','nama','alamat'
];
protected $hidden = [
'tgl_lahir ',
];
public function getJWTIdentifier()
{
return $this->getKey();
}
public function getJWTCustomClaims()
{
return [];
}
}
my BukuController
<?php
namespace App\Http\Controllers;
use App\Buku;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class BukuController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function showAllBuku()
{
return response()->json(Buku::all());
}
}
my routes
$router->group(['prefix' => 'api'], function () use ($router) {
$router->post('login', 'AuthController#login');
$router->get('buku', ['uses' => 'BukuController#showAllBuku']);
});
config/auth.php
<?php
return [
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => \App\User::class
]
],
];
the existing pengguna table don't allowed created ID field like lumen/laravel auth, if i commented code in Middleware\Authenticate like :
public function handle($request, Closure $next, $guard = null)
{
//if this block commented is working
if ($this->auth->guard($guard)->guest()) {
return response('Unauthorized.', 401);
}
return $next($request);
}
it's working..is there another way for my case?thanks for your help
sorry my mistake, my problem solved by add this in user model
public function getAuthIdentifierName(){
return $this->nomor;
}
public function getAuthIdentifier(){
return $this->{$this->getAuthIdentifierName()};
}
Below is my code for AuthController
<?php
namespace App\Http\Controllers\Auth;
use App\User;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
//use App\Http\Requests\Request;
use Request;
use View;
use Hash;
use DB;
use Auth;
class AuthController extends Controller
{
/*
|--------------------------------------------------------------------------
| Registration & Login Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users, as well as the
| authentication of existing users. By default, this controller uses
| a simple trait to add these behaviors. Why don't you explore it?
|
*/
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
/**
* Where to redirect users after login / registration.
*
* #var string
*/
protected $redirectTo = '/home';
protected $redirectAfterLogout = '/login';
protected $username = 'user_name';
/**
* Create a new authentication controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware($this->guestMiddleware(), ['except' => 'logout']);
}
/**
* Get a validator for an incoming registration request.
*
* #param array $data
* #return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|min:6|confirmed',
]);
}
/**
* Create a new user instance after a valid registration.
*
* #param array $data
* #return User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
public function showLogin()
{
if (Auth::check())
{
return redirect('/home');
}
else
{
return View::make('index');
}
}
public function doLogin()
{
//echo 'test';
$input = Request::all();
$pass = Hash::make($input['password']);
//print_r($input);exit;
//echo $input['username'];exit;
/*DB::table('admin_user')->insert(
['user_name' => $input['username'], 'password' => $pass]
);*/
if (Auth::attempt(['user_name' => $input['username'], 'password' => $input['password']])) {
return redirect('/home');
//return View::make('home');
}
else
{
return redirect('/');
}
}
public function doLogout()
{
Auth::logout();
return redirect('/');
}
}
Below is my Route Code
Route::get('/',array('uses'=>'Auth\AuthController#showLogin') );
Route::post('/login',array('uses'=>'Auth\AuthController#doLogin'));
//Route::get('/login',array('uses'=>'Login#showLogin') );
Route::group(['middleware' => ['web', 'auth.basic']], function(){
Route::get('/home',['uses'=>'Home#getHome']);
Route::get('/logout',array('uses'=>'Auth\AuthController#doLogout') );
});
i am using user name instead of email id for Auth but below error is shown
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'email' in
'where clause' (SQL: select * from admin_user where email = admin
limit 1)
below is my kernal.php code
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* #var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
];
/**
* The application's route middleware groups.
*
* #var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:60,1',
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* #var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'can' => \Illuminate\Foundation\Http\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];
}
please help me how can i do login with username .
Thanks in advance.
Update:
Add the auth middleware to specific route
Route::group(['middleware' => ['web']], function(){
Route::get('/',array('uses'=>'Auth\AuthController#showLogin') );
Route::post('/login',array('uses'=>'Auth\AuthController#doLogin'));
Route::get('/home',['uses'=>'Home#getHome'])->middleware('auth');//update
Route::get('/logout',array('uses'=>'Auth\AuthController#doLogout') );
});
To redirect to intended page after login replace your doLogin() function with following:
public function doLogin()
{
$input = Request::all();
$pass = Hash::make($input['password']);
if (Auth::attempt(['user_name' => $input['username'], 'password' => $input['password']])) {
return redirect()->intended('/home');//This line is changed
}
else
{
return redirect('/');
}
}
Explaination:
intended() method redirects the user to the previous page, from where the user is redirected to login page. It expects a default route as a parameter, where user will be sent if he has came here directly.
Update 2:
add doLogout in your AuthController's constructor:
public function __construct()
{
$this->middleware($this->guestMiddleware(), ['except' => 'doLogout']);
}
You can simply override $username in AuthController by writing protected $username = 'username'.
i have a code in Yii2 advanced template, i want to make a link when i log in from frontend then connecting in backend and when i logout from backend it back to frontend,how can i make that?
and this is my comon/config/main.php file
<?php
return [
'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
'components' => [
'cache' => [
'class' => 'yii\caching\FileCache',
],
'urlManager' => [
//'class' => 'yii\web\urlManager',
'enablePrettyUrl' => false,
'showScriptName' => true,
'baseUrl' => '/backend/web',
],
'urlManagerFrontEnd' => [
'class' => 'yii\web\urlManager',
'baseUrl' => '/frontend/web',
'enablePrettyUrl' => false,
'showScriptName' => true,
]
],
];
and this is my siteController in frontend
<?php
namespace frontend\controllers;
use Yii;
use common\models\LoginForm;
use frontend\models\PasswordResetRequestForm;
use frontend\models\ResetPasswordForm;
use frontend\models\SignupForm;
use frontend\models\ContactForm;
use yii\base\InvalidParamException;
use yii\web\BadRequestHttpException;
use yii\web\Controller;
use yii\filters\VerbFilter;
use yii\filters\AccessControl;
use yii\helpers\Url;
use backend;
/**
* Site controller
*/
class SiteController extends Controller
{
/**
* #inheritdoc
*/
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['logout', 'signup'],
'rules' => [
[
'actions' => ['signup'],
'allow' => true,
'roles' => ['?'],
],
[
'actions' => ['logout'],
'allow' => true,
'roles' => ['#'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post'],
],
],
];
}
/**
* #inheritdoc
*/
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction',
],
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
],
];
}
/**
* Displays homepage.
*
* #return mixed
*/
public function actionIndex()
{
return $this->render('index');
}
/**
* Logs in a user.
*
* #return mixed
*/
public function actionLogin()
{
if (!\Yii::$app->user->isGuest) {
return $this->goHome();
}
$model = new LoginForm();
if ($model->load(Yii::$app->request->post()) && $model->login()) {
return $this->goBack();
} else {
return $this->render('login', [
'model' => $model,
]);
}
}
/**
* Logs out the current user.
*
* #return mixed
*/
public function actionLogout()
{
Yii::$app->user->logout();
return $this->goHome();
}
/**
* Displays contact page.
*
* #return mixed
*/
public function actionContact()
{
$model = new ContactForm();
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
if ($model->sendEmail(Yii::$app->params['adminEmail'])) {
Yii::$app->session->setFlash('success', 'Thank you for contacting us. We will respond to you as soon as possible.');
} else {
Yii::$app->session->setFlash('error', 'There was an error sending email.');
}
return $this->refresh();
} else {
return $this->render('contact', [
'model' => $model,
]);
}
}
/**
* Displays about page.
*
* #return mixed
*/
public function actionAbout()
{
return $this->render('about');
}
/**
* Signs user up.
*
* #return mixed
*/
public function actionSignup()
{
$model = new SignupForm();
if ($model->load(Yii::$app->request->post())) {
if ($user = $model->signup()) {
if (Yii::$app->getUser()->login($user)) {
return $this->goHome();
}
}
}
return $this->render('signup', [
'model' => $model,
]);
}
/**
* Requests password reset.
*
* #return mixed
*/
public function actionRequestPasswordReset()
{
$model = new PasswordResetRequestForm();
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
if ($model->sendEmail()) {
Yii::$app->session->setFlash('success', 'Check your email for further instructions.');
return $this->goHome();
} else {
Yii::$app->session->setFlash('error', 'Sorry, we are unable to reset password for email provided.');
}
}
return $this->render('requestPasswordResetToken', [
'model' => $model,
]);
}
/**
* Resets password.
*
* #param string $token
* #return mixed
* #throws BadRequestHttpException
*/
public function actionResetPassword($token)
{
try {
$model = new ResetPasswordForm($token);
} catch (InvalidParamException $e) {
throw new BadRequestHttpException($e->getMessage());
}
if ($model->load(Yii::$app->request->post()) && $model->validate() && $model->resetPassword()) {
Yii::$app->session->setFlash('success', 'New password was saved.');
return $this->goHome();
}
return $this->render('resetPassword', [
'model' => $model,
]);
}
/*public function goBack($defaultUrl = null)
{
if(is_null($defaultUrl)) {
$defaultUrl = Yii::$app->request->baseUrl; // ganti dibagian ini ndu
}
return Yii::$app->getResponse()->redirect(Yii::$app->getUser()->getReturnUrl($defaultUrl));
}*/
}
and the same with siteController in backend
I try to protect my restAPI with credentials and reading about basic-auth laravel I try to implement a basic authentication sytem
User tabel already exists and populated with data
in filter.php I set
Route::filter('auth.basic', function() {
return Auth::basic(); });
than in api Route
// =============================================
// API ROUTES ==================================
// =============================================
Route::group(array('prefix' => 'api', 'before' => 'auth.basic'), function() {
Route::resource('products', 'ProductController', array('only' => array('index', 'store', 'destroy', 'update', 'show', 'edit')));
Route::get('products/{id}', 'ProductController#get', array('only' => array('show')));
});
the controller is quite simple
<?php
use App\Models\Product;
class ProductController extends \BaseController {
private $model;
function __construct() {
$this->model = new Product();
}
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index() {
$model = new Product();
$page = Input::get('pageNumber');
$limit = Input::get('pageNumber');
$ram = Input::get('limit');
$cpu = Input::get('cpu');
$price_range = Input::get('price_range');
$keyword = Input::get('keyword');
return Response::json($model->getProducts($page));
}
/**
* Store a newly created resource in storage.
*
* #return Response
*/
public function store() {
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return Response
*/
public function destroy($id) {
}
public function get($id) {
$model = new Product();
return Response::json($model->getProduct($id));
}
public function show($id) {
return Response::json($this->model->getProduct($id));
}
public function update($id) {
return Response::json($this->model->getProduct($id));
}
public function pause($id) {
var_dump('pause');
}
public function create(){
}
public function edit(){
var_dump('test_edit');
}
}
calling domain.com/api/products pop up login window. populating fields and submit datas can't log in
How do I check Users credentials?
For backend I use Sentry and it's working
filter.php
Route::filter('auth.admin', function() {
if (!Sentry::check()) {
return Redirect::route('admin.login');
}
});
Route
Route::get('admin/login', array('as' => 'admin.login', 'uses'
=> 'App\Controllers\Admin\AuthController#getLogin'));
Controller
<?php namespace App\Controllers\Admin;
use Auth, BaseController, Form, Input, Redirect, Sentry, View;
class AuthController extends BaseController {
/**
* Display the login page
* #return View
*/
public function getLogin()
{
return View::make('admin.auth.login');
}
/**
* Login action
* #return Redirect
*/
public function postLogin()
{
$credentials = array(
'email' => Input::get('email'),
'password' => Input::get('password')
);
try
{
$user = Sentry::authenticate($credentials, false);
if ($user)
{
return Redirect::route('admin.pages.index');
}
}
catch(\Exception $e)
{
return Redirect::route('admin.login')->withErrors(array('login' => $e->getMessage()));
}
}
/**
* Logout action
* #return Redirect
*/
public function getLogout()
{
Sentry::logout();
return Redirect::route('admin.login');
}
}
It seems that you don't have a login function defined.
by the way, you should change:
Route::group(array('prefix' => 'api', 'before' => 'auth.basic'), function() {
Route::resource('products', 'ProductController', array('only' => array('index', 'store', 'destroy', 'update', 'show', 'edit')));
Route::get('products/{id}', 'ProductController#get', array('only' => array('show')));
});
to:
Route::group(array('prefix' => 'api', 'before' => 'auth.basic'), function(){
Route::get('products/{id}', 'ProductController#get'));
Route::resource('products', 'ProductController', array('except' => array('show')));
});
I've changed the auth.php file in order to authenticate my users according to authors table. But I keep getting No account for you when I'm running test route.
auth.php
<?php
return array(
'driver' => 'eloquent',
'model' => 'Author',
'table' => 'authors',
'reminder' => array(
'email' => 'emails.auth.reminder', 'table' => 'password_reminders',
),
);
routes.php
Route::get('test', function() {
$credentials = array('username' => 'giannis',
'password' => Hash::make('giannis'));
if (Auth::attempt($credentials)) {
return "You are a user.";
}
return "No account for you";
});
AuthorsTableSeeder.php
<?php
class AuthorsTableSeeder extends Seeder {
public function run()
{
// Uncomment the below to wipe the table clean before populating
DB::table('authors')->delete();
$authors = array(
[
'username' => 'giannis',
'password' => Hash::make('giannis'),
'name' => 'giannis',
'lastname' => 'christofakis'],
[
'username' => 'antonis',
'password' => Hash::make('antonis'),
'name' => 'antonis',
'lastname' => 'antonopoulos']
);
// Uncomment the below to run the seeder
DB::table('authors')->insert($authors);
}
}
Addendum
I saw in another post that you have to implement the UserInterface RemindableInterface interfaces. But the result was the same.
Author.php
<?php
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
class Author extends Eloquent implements UserInterface, RemindableInterface {
protected $guarded = array();
public static $rules = array();
public function posts() {
return $this->hasMany('Post');
}
/**
* Get the unique identifier for the user.
*
* #return mixed
*/
public function getAuthIdentifier()
{
return $this->getKey();
}
/**
* Get the password for the user.
*
* #return string
*/
public function getAuthPassword()
{
return $this->password;
}
/**
* Get the e-mail address where password reminders are sent.
*
* #return string
*/
public function getReminderEmail()
{
return "giannis#hotmail.com";
}
}
You don't need to Hash your password when you are using Auth::attempt(); so remove Hash::make from routes
Route::get('test', function() {
$credentials = array('username' => 'giannis',
'password' => 'giannis');
if (Auth::attempt($credentials)) {
return "You are a user.";
}
return "No account for you";
});
and it will work like a charm!