REST api authenication with laravel - php

I am building a RESTful api with laravel using the RESTful controller property. So far i've been able to get most of it working. The issue am having now is authenication, am trying to use Amazon approach using a "user_id" and "signature".
Am creating the signature using php's 'hash_hmac()'.
this an example api controller
class Api_Tasks_Controller extends Api_Controller {
public $restful = true;
public function get_index($id = null) {
$this->verfiy_request();
if(!is_null($id))
{
return Response::json(array("tasks"=>"just one"),200);
}
else
{
return Response::json(array("tasks"=>"everthing"),200);
}
}
}
and this the api controller class
class Api_Controller extends Controller {
public function verify_request() {
//user id
$user_id = (int) Input::get('user_id');
//signature
$sig = Input::get('sig');
//Lookup user
$user = Sentry::user($user_id);
if($user) {
//user email
$email = $user->email;
//user api key
$api_key = $user->metadata['api_key'];
//recreate signature
$_sig = hash_hmac("sha256",$email.$user_id,$api_key);
if($_sig === $sig) {
return Response::json(array("message"=>"Request Ok"),200);
}
else {
return Response::json(array("message"=>"Request Bad"),400);
}
}
else {
return Response::json(array("message"=>"Request not authorized"),401);
}
}
Making a get request http://api.xyz.com/v1/tasks/1?user_id=1&sig=41295da38eadfa56189b041a022c6ae0fdcbcd5e65c83f0e9aa0e6fbae666cd8 always returns a successful message even when i alter the value of the user_id parameter which should void the signature an make the request invalid.
It seems my verfiy_request method is not executing.
Please help me out

I have also been researching this recently and would also recommend going with filters. It could work something like this:
class Api_Tasks_Controller extends Base_Controller {
public $restful = true;
function __construct() {
// Check if user is authorized
$this->filter('before', 'api_checkauth');
}
// rest of the class ....
}
And in your routes.php file:
Route::filter('api_checkauth', function()
{
//user id
$user_id = (int) Input::get('user_id');
//signature
$sig = Input::get('sig');
try {
//Lookup user
$user = Sentry::user($user_id);
if($user) {
//user email
$email = $user->email;
//user api key
$api_key = $user->metadata['api_key'];
//recreate signature
$_sig = hash_hmac("sha256",$email.$user_id,$api_key);
if($_sig === $sig) {
return Response::json(array("message"=>"Request Ok"),200);
}
else {
return Response::json(array("message"=>"Request Bad"),400);
}
}
else {
return Response::json(array("message"=>"Request not authorized"),401);
}
}
catch (Sentry\SentryException $e) {
$errors = $e->getMessage(); // catch errors such as user not existing or bad fields
return Response::json(array("message"=>$errors),404);
}
});
Also, thanks for introducing me to Sentry :-)

It's a quick guess, I didn't try but maybe you might want to try to add a return statement before calling verify_request.
And you should look into filters which will allow you to separate more your api logic and
api authentication ;-)

Related

Is there a way to reference the User Model before the user is Authenticated from the LoginController, in Laravel

I am trying to overwrite the attemptLogin function in the LoginController, so that I can accept an old password then force a password reset using middlewear after the login authentication.
I have functionality in the "User" Model that pulls their old password so I can check it and Authenticate it if their main/new password fails or they don't have a main/new password. My only problem is trying to reference the user from within the function, because one isn't instantiated, yet.
Is there a way to call to the model's functionality without passing an Authenticated guard response first using the given Username.
class LoginController extends Controller
{
// Standard LoginController Stuff...
protected function attemptLogin(Request $request)
{
if (!$this->guard()->attempt(
$this->credentials($request), $request->filled('remember'))) {
$user = Auth::user(); //<--- This doesn't work, the User hasn't been Authenticated yet.
$md5Hash = md5($this->credentials($request)['password']);
if ($md5Hash === $user->getOldPass())
return true;
} else {
return true;
}
return false;
}
}
The easiest way to do this would be to load the User model yourself.
protected function attemptLogin(Request $request)
{
if ($this->guard()->attempt($this->credentials($request), $request->filled('remember'))) {
return true;
}
if (!$user = User::where($this->username(), $request->input($this->username()))->first()) {
return false;
}
if (md5($request->input('password')) === $user->getOldPass()) {
$this->guard()->login($user, $request->filled('remember'));
return true;
}
return false;
}

Yii2 - Return Response during beforeAction

I am building a test API. I have created a Controller Page which extends from yii\rest\Controller. Actions needs to send a response.
To access actions in this controller, a service_id value needs to be posted. If present I need to evaluate if that service_id exists, if it is active and belongs to the user logged in. If validation fails, I need to send a response.
I am trying to do it using beforeAction(), but the problem is that return data is used to validate if action should continue or not.
So my temporary solution is saving service object in a Class attribute to evaluate it in the action and return response.
class PageController extends Controller
{
public $service;
public function beforeAction($action)
{
parent::beforeAction($action);
if (Yii::$app->request->isPost) {
$data = Yii::$app->request->post();
$userAccess = new UserAccess();
$userAccess->load($data);
$service = $userAccess->getService();
$this->service = $service;
}
return true;
}
public function actionConnect()
{
$response = null;
if (empty($this->service)) {
$response['code'] = 'ERROR';
$response['message'] = 'Service does not exist';
return $response;
}
}
}
But I can potentially have 20 actions which require this validation, is there a way to return the response from the beforeAction method to avoid repeating code?
You can setup response in beforeAction() and return false to avoid action call:
public function beforeAction($action) {
if (Yii::$app->request->isPost) {
$userAccess = new UserAccess();
$userAccess->load(Yii::$app->request->post());
$this->service = $userAccess->getService();
if (empty($this->service)) {
$this->asJson([
'code' => 'ERROR',
'message' => 'Service does not exist',
]);
return false;
}
}
return parent::beforeAction($action);
}
maybe paste in beforeAction after $this->service = $service;
if (empty($this->service)) {
echo json_encode(['code' => 'ERROR', 'message' => 'Service does not exist']);
exit;
}

Laravel - Callable returning blank screen

I'm trying to create a callback to return my views based on data from my current logged-in user. If I do something basic like echoing 'hi' it works, is there any way accomplish this?
function checkUser($type,$callback){
if( is_callable($callback) ){
call_user_func($callback);
}
}
class FichaController extends Controller
{
public function contarFichas()
{
checkUser('particular',function(){
$currentUser = Auth::user();
$countFichas = Ficha::where('user_id',$currentUser->id)->count();
return view('particular.index', array('countFichas' => $countFichas));
});
}
}
Return the result from checkUser
if( is_callable($callback) ){
return $callback();
}
public function contarFichas()
{
return checkUser('particular',function(){
$currentUser = Auth::user();
$countFichas = Ficha::where('user_id',$currentUser->id)->count();
return view('particular.index', array('countFichas' => $countFichas));
});
}

how to remember a user who is login

I have created a sign in form with a remember me checkbox. I want to know how can i allow user to keep sign in when the browser is closed or sign out person when they close the browser. A sample code would be nice thank you.
here is my code
class HomeController extends BaseController {
public function getIndex()
{
if(Auth::check())
{
return Redirect::to('profile');
}
return View::make('index');
}
public function postRegister()
{
//gets array of the register form input values
$value = Input::all();
// create a new instance of the User model
$user = new User;
$validate = $user->userValidate($value);
//checks if the validation for the field fails
if($validate->fails())
{
/* $message = $validation->messages();
return $message; */
return Redirect::back()->withInput()->withErrors($validate);
}
//adds the users input to speicific field in the users table
$user->user_name = $value['username'];
$user->email = $value['email'];
$user->password = Hash::make($value['password']);
//save the inputs to the users table
$user->save();
return 'information has been stored';
}
public function getRegister()
{
$title = 'Register';
return View::make('register')->with('title',$title);
}
public function getSignIn()
{
$title = 'Signup';
return View::make('signup')->with('title',$title);
}
public function postSignIn()
{
//user's information
$credentials = array('email' => Input::get('email'),'password'=>Input::get('password'));
//logs this user in and checked if they are registered already in
if(Auth::attempt($credentials,false))
{
return Redirect::to('profile');
}
return Redirect::back()->withInput();
}
}
You just have to turn it on in your login method:
if (Auth::attempt(array('email' => $email, 'password' => $password), true))
{
// The user will now be logged in and remembered
}
else
{
// Raise a login error
}
This "true" parameter is to remember your user.
Here is the Laravel Auth::attempt() method declaration:
public function attempt(array $credentials = array(), $remember = false, $login = true)
{
...
}
You could set a cookie on the users browser (make sure you tell them if you are) to identify them. But beware that this could be modified by a malicious user.
PHP Cookies Documentation

Yii Authentication error: After login successfull Yii::app()->user->isGuest() always return true

I started creating a difference between the authenticated users and guest user. But always when i identify the user and it get the login successfully, it still returns true when i make use Yii::app()->user->isGuest. Here is the code which i am using:
if (Yii::app()->user->isGuest){
echo 'Welcome back Guest';
} else {
echo 'Welcome back '.Yii::app()->user->name;
}
I always get the 'welcome back guest', whether i have logged in (successfully) or not. And if i have logged in again i got this message. and here is the User Identify code.
class UserIdentity extends CUserIdentity {
/**
* Authenticates a user.
*/
private $_id;
public function authenticate() {
$user = Users::model()->findByAttributes(array('username' => $this->username));
if ($user === null)
$this->errorCode = self::ERROR_USERNAME_INVALID;
else if ($user->password !== $this->password)
$this->errorCode = self::ERROR_PASSWORD_INVALID;
else {
$this->_id = $user->id;
$this->setState('title', $this->username);
$this->setState('id', $user->id);
$this->errorCode = self::ERROR_NONE;
}
return !$this->errorCode;
}
public function getId() {
return $this->_id;
}
}
Please help me to get rid of this problem.
You should fix LoginForm
/**
* Authenticates the password.
* This is the 'authenticate' validator as declared in rules().
*/
public function authenticate($attribute, $params)
{
// we only want to authenticate when no input errors
if (! $this->hasErrors()) {
$identity = new UserIdentity($this->email, $this->password);
$identity->authenticate();
switch ($identity->errorCode) {
case UserIdentity::ERROR_NONE:
$duration = ($this->rememberMe)
? 3600*24*14 // 14 days
: 0; // login till the user closes the browser
Yii::app()->user->login($identity, $duration);
break;
default:
// UserIdentity::ERROR_USERNAME_INVALID
// UserIdentity::ERROR_PASSWORD_INVALID
// UserIdentity::ERROR_MEMBER_NOT_APPOVED
$this->addError('', Yii::t('auth',
'Incorrect username/password combination.'));
break;
}
}
}
class UsersController extends Controller
{
/**
* Displays the login page
*/
public function actionLogin()
{
$model = new LoginForm;
if (isset($_POST['LoginForm'])) {
$model->attributes = $_POST['LoginForm'];
$valid = $model->validate();
if ($valid) {
$this->redirect(Yii::app()->user->returnUrl);
}
}
$this->render('login', array('model' => $model));
}
}
Can you show your config?
Answer can be found here yii authentication error
You can also read more on yii authentication here authentication and authorisation
Try this and see using Not(!) operator
if (!Yii::app()->user->isGuest){
echo 'Welcome back Guest';
} else {
echo 'Welcome back '.Yii::app()->user->name;
}
You should NOT do this :
$this->setState('id', $user[0]->id);
setState should not be used for the 'id'. For returning the 'id' you have already overridden the getId() method.
If you do need to set it, change it something like this :
$this->_id = $user[0]->id;
Hope this helped.
Regards,

Categories