Logging out with HTTP Basic Auth in Laravel - php

I have one user class which consists of two types of users and want to allow different users to go to different pages.
I have created a filter as follows
Route::filter('isExpert', function()
{
$userIsExpert = 0;
$userIsLoggedIn = Auth::check();
if ($userIsLoggedIn && Auth::user()->role == 'expert') {
$userIsExpert = 1;
}
Log::info('Logged in: ' . $userIsLoggedIn . ' && Expert: ' . $userIsExpert);
if ($userIsExpert == 0)
{
Log::info('should be logging out now.');
Auth::logout();
return Auth::basic();
}
});
And routing like so
Route::get('/winners', array('before' => 'isExpert', function()
{
$winners = DB::select('select * from winners');
return View::make('winners.index')->with('winners',$winners);
}));
The thought is this: If it's not an expert, it will logout and redirect to login page. If it is, it will simply continue.
However, Auth::logout(); doesn't ever log out the user.
Question
Why is not Auth::logout() working? I've tried placing it anywhere in the app to no avail.
cheers

I had the same problem, I really couldn't logout the current user... And the answer is simple: Laravel doesn't support logout() with Auth::basic().
There are ways to fix it, but it's not very clean; https://www.google.nl/search?q=logout+basic

This is not a limitation to Laravel, HTTP Basic Authorization is not designed to handle logging out. The client will remain logged in until the browser is closed.
HTTP Basic Authorization really shouldn't be used in any public production environment. Here are some reasons why:
No way to give users a "remember me"-option on the login form.
Password managers have no or lacking support for HTTP Basic Auth, as it is not rendered HTML but a native popup.
Terrible user experience. Putting together a proper login form is well worth the little time it takes.
The only valid case I can think of is to protect public development-subdomains like dev.example.com, but there are better ways to solve that as well.

The easiest way that I've found for that is to redirect to invalid username/password on logout route. Example:
Route::get('admin/logout', function() {
return Redirect::to(preg_replace("/:\/\//", "://log-me-out:fake-pwd#", url('admin/logout')));
});

If you implemented these methods in User.php
/**
* Get the e-mail address where password reminders are sent.
*
* #return string
*/
public function getReminderEmail()
{
return $this->email;
}
public function getRememberToken()
{
return $this->remember_token;
}
public function setRememberToken($value)
{
$this->remember_token = $value;
}
public function getRememberTokenName()
{
return 'remember_token';
}
add new column with name 'remember_token' to your table 'users' in mysql database, and then log out, finally it solved successfully.
to alternate you table use this SQL Command:
ALTER TABLE users ADD remember_token TEXT;
and then press 'Go' button.

Related

Add Admin role in laravel 5.4

I have a database that in this: Admin has True isAdmin property, but other users have false isAdmin property.
I want to check if the user who logged in is an Admin or not by redirecting them to different pages in my app. My code in Controller is:
public function store(User $user)
{
if (auth()->attempt(request(['email', 'password']))) {
if ($user->isAdmin == 1) {
return redirect('/ShowUser');
}
{
return redirect('/lo');
}
}
return back()->withErrors(
[
'message' => 'Error'
]
);
}
But this code doesn't work; it sends the users to '/lo' all the time. How can I fix it?
You're missing an else keyword.
Right here:
if ($user->isAdmin == 1) {
return redirect('/ShowUser');
}
{ // <-- right here
return redirect('/lo');
}
add the else keyword.
if ($user->isAdmin == 1) {
return redirect('/ShowUser');
}
else { // <-- right here
return redirect('/lo');
}
anyway, your code will still run fine even after the edit above. But I have questions for you:
Is the user assumed to be in the database already?
What is the default value of isAdmin in the database?
Are you passing the isAdmin attribute as an input from a form or something?
And why is it a store request when you're just trying to log a user in?
It's a bit confusing. I can tell from your code that you're trying to log a user in, but you're doing it in a store method (nothing wrong with that, just convention), the store method is usually used in storing data (how coincidental!)

Laravel allow route to be accessible only from another route

I have /signup/select-plan which lets the user select a plan, and /signup/tos which displays the terms of services. I want /signup/tos to be only accessible from /signup/select-plan. So if I try to go directly to /signup/tos without selecting a plan, I want it to not allow it. How do I go about this?
In the constructor, or the route (if you are not using contructors), you can check for the previous URL using the global helper url().
public function tos() {
if ( !request()->is('signup/tos') && url()->previous() != url('signup/select-plan') ) {
return redirect()->to('/'); //Send them somewhere else
}
}
In the controller of /signup/tos which returns the tos view just add the following code:
$referer = Request::referer();
// or
// $referer = Request::server('HTTP_REFERER');
if (strpos($referer,'signup/select-plan') !== false) {
//SHOW THE PAGE
}
else
{
dd("YOU ARE NOT ALLOWED")
}
What we are doing here is checking the HTTP referrer and allowing the page access only if user comes from select-plan
You are need of sessions in laravel. You can see the following docs to get more info: Laravel Sessions
First of all you need to configure till how much time you want to have the session variable so you can go to your directory config/sessions.php and you can edit the fields 'lifetime' => 120, also you can set expire_on_close by default it is being set to false.
Now you can have following routes:
Route::get('signup/select-plan', 'SignupController#selectPlan');
Route::post('signup/select-token', 'SignupController#selectToken');
Route::get('signup/tos', 'SignupController#tos');
Route::get('registered', 'SignupController#registered');
Now in your Signupcontroller you can have something like this:
public function selectPlan()
{
// return your views/form...
}
public function selectToken(Request $request)
{
$request->session()->put('select_plan_token', 'value');
return redirect('/signup/tos');
}
Now in signupController tos function you can always check the session value and manipulate the data accordingly
public function tos()
{
$value = $request->session()->get('select_plan_token');
// to your manipulation or show the view.
}
Now if the user is registered and you don't need the session value you can delete by following:
public function registered()
{
$request->session()->forget('select_plan_token');
// Return welcome screen or dashboard..
}
This method will delete the data from session. You can manipulate this. You won't be able to use in tos function as you are refreshing the page and you want data to persist. So its better to have it removed when the final step or the nextstep is carried out. Hope this helps.
Note: This is just the reference please go through the docs for more information and implement accordingly.

How to determine if a session with same variable is already there in laravel

I am using Laravel framework. There is a function in controller that creates session with name store_id
StoreController.php
function initiate($id)
{
//Some queries
session['store_id' => 'some value'];
}
Now if I run this function on one tab then session::get('store_id') is going on. But if I open another tab in the same browser then again run the function that means session('store_id') will be again set. How do I handle this situation that if there is already a session then it should redirect to it's perspective url.
Okay first of all, Bruuuhhhh been there and done that
Alright, lets begin. you want that if there is already a session with store_id going on then you want user to redirect or send back.
In your controller add this
public function initiate()
{
if(session()->has('store_id'))
{
//What ever your logic
}
else
{
redirect()->to('/store')->withErrors(['check' => "You have session activated for here!."]);
}
}
Most probably you would be wondering that user can just go to other url after /store/other-urls Yess he can.
To avoid this. Add a custom middleware
php artisan make:middleware SessionOfStore //You can name it anything.
In that middleware
public function handle($request, Closure $next)
{
if($request->session()->has('store_id'))
{
return $next($request);
}
else
{
return redirect()->back()->withErrors(['privilege_check' => "You are not privileged to go there!."]);
}
return '/home';
}
in your main store page. Add an anchor tag Stop Service
Now in your web.php
Route::group(['middleware' => 'SessionOfStore'], function()
{
//Add your routes here.
Route::get('/stop', 'StoreController#flushSession');
});
Now you have restrict access to urls and has checked the sessions.
Now in
public function flushSession()
{
//empty out the session and
return redirect()->to('/home');
}
The Laravel session helper has the function has to check this.
if (session()->has('store_id'))
{
// Redirect to the store
}
else
{
// Set the store id
}
The documentation contains all of the possible functions that can be used with the session helper.

Laravel , sessions just work for 1 online user

I'm new in laravel
I coded a script that many users may work with
but the problem that I have is this :
when a user like "Helen" signs in she can see her profile
but if next another user like "Maria" logs on , Marias panel will be shown for both of them
I think it means just one session can be active at the same time and the value of session will be for the latest user
and the older users session doesn't expire just the value in the session will be changed , thus she identifies as another user and can see that users profile, and also when a user logs out , because of close of the session , all users will be signed out.
here is my simple code :
public function Login(){
$this->Token();
$pack=Input::all();
try {
$result=DB::table('user')->where('Email','=',$pack['email'])->get();
if (Hash::check($pack['password'], $result[0]->Password)){
session(['there' => $result['0']->Email]);
return redirect('dashboard');
}
return redirect('dashboard')->with('does','wrong password');
}catch(Exception $e){
return redirect('dashboard')->with('does',.$e);
}
}
public function UserType() {
if(!session('there'))
return "Not Logged";
else {
$result = DB::table('user')->where('Email', '=', session('there'))->get();
if($result!=null)
return "User";
}
public function ShowDashboard(){
if($this->UserType()=="Not Logged")
else
return view('pages/dashboard');
}
I am not sure why you are session() to manage user logins... Also, they depend a lot on situations where users are login from the same computer, same browser... cookies... etc etc... and maybe that's why you might be getting 2 different session values at the same time...
In any case.. please try and prefer using Laravel's predefined functions of Auth to handle your login/logout procedures.
public function Login()
{
// What does this do? Check for a CSRF token? If yes, then
// please understand then Laravel automatically checks
// for the CSRF token on POST/PUT requests and therefore
// there is no special need to use the below function...
$this->Token();
$pack = request()->only(['email', 'password']);
// I don't really feel try catch is required here... but completely your choice...
try {
if(auth()->attempt($pack)) {
return redirect('dashboard')
}
return redirect->back()->with('does', 'wrong password');
} catch(Exception $e) {
return redirect->back()->with('does', $e);
}
}
public function ShowDashboard()
{
// You can remove this if/else by adding the 'auth' middleware
// to this route
if(!auth()->check())
return view('pages.dashboard');
else
return redirect(route('login'));
}
I found a lot of problems in your above code...
Please use camelCase for naming functions... (I haven't changed the naming in my code above because I don't really know what rules you are following at your workplace or idk...)
Please don't return strings for a simple true/false situation.
Please try and use Models whenever possible. The raw DB commands are required for very complex and extensive queries

Restrictions Within MVC Service Layer

I have recently dived into OOP & PHP MVC Application Design. At the moment I am learning a lot but I have one thing that is currently bugging me.
I read and now understand why it isn't wise to place http redirects within a service layer. We do not know what the controller will need to do once the service is complete, etc. etc. I also read that the service should not do anything outside of its purpose. Example: User Registration should only create a new user, using input passed by controller, but I am wondering if it is also fine to set flash messages within the service layer.
My application displays a lot of flash messages session based notifications for users. All of them are based on service related input validation checks, and produce alerts similar to the following
The username xxxxxx is already in use
Usernames Should be > 5 Characters
Should/can this be defined/set within the service class or is there something wrong with that? I have a Alert Helper function that handles setting the alerts. I can easily use my dependency injector to make it available I am just wondering if there is an issue with doing that.
I made the mistake of implementing all redirects within the services and I just finished removing all of them and placing them in the controllers, I don't want to make the same time consuming mistake so I am looking for advice here.
Thank you in advance for the help.
EDIT - CODE EXAMPLE
<?php
/**
*-----------------------------------------------------------------
*
* LOGIN CONTROLLER
*
*/
namespace Controller\www;
use \Helper\Controller;
class Login extends Controller {
public $dependencies = ['arena', 'login', 'site'];
/**
* Login
*
* Login Runs Through Various Checks Including If User is Banned, Account is Locked,
* or Forgot Password Request Is Active. Then the Entered Password is Matched & if Valid
* User is Logged In
*/
public function index() {
// Define Default
$username = '';
/**
* User Login
*
* If Successful, Login User, Redirect Home
* Else Set Error Alerts
*/
if ($this->form->post('login')) {
// Define and Sanitize Post Data
$username = $this->input->get('username');
$password = $this->input->get('password');
// Login Service Layer
$login = $this->factory->make('user/login');
// If Successful Redirect Home - Else Set Errors
if ($login->user($username, $password) === true) {
$this->redirect->home();
}
$this->alert->error($login->get('errors'));
}
/**
* Define Site Title & Display Page
*/
$this->view->sitetitle('login');
$this->view->display('www/login', [
'video' => $this->arena->video(),
'username' => $this->input->set($username)
], ['notifications' => 'user/forgotpassword']);
}
}
Service Layer
/**
*-----------------------------------------------------------------
*
* USER LOGIN SERVICE LAYER
*
*/
namespace Service\User;
use \Helper\Service;
class Login extends Service {
public $dependencies = ['login', 'mail', 'time', 'user', 'vars'];
/**
* Handles Entire Login Process For Site Users
*
* #params all User Submitted Form Data
*/
public function user($username = '', $password = '') {
// Validate $_POST Form Data
$this->validateInput($username, $password);
/**
* No Errors Produced - Complete Form Submission
*
* We Are Not Using `elseif` Between Forgot Password & Normal Login
* After a Forgot Password Code is Generated User May Remember Old Passwords
* We Need to Ensure Users Can Still Login Using Account Password As Well
*/
if (!$this->errors()) {
/**
* User Input Password Matches Account Password
*/
if ($this->input->verifyhash($password, $this->user->get('info.password'))) {
$this->login->user();
return true;
}
/**
* If We Have Not Been Redirected Login Was Unsuccessful
*/
$message = $forgotPW ? 'Forgot Password Code Invalid - Login Lost Incorrect' : 'Login Unsuccessful - Incorrect Username or Password';
$this->log->error($message, ['Username' => $username, 'Password' => $password]);
$this->error('Incorrect Username or Password');
}
/**
* If We Have Made It This Far Login Was Unsuccessful - Log Unsuccessful Attempt
*/
$this->login->logAttempt();
return false;
}
/**
* Validate $_POST Data
*
* #params all User Submitted Form Data
*/
private function validateInput($username = '', $password = '') {
// Display Error if Username is Empty
if (!$username) {
$this->error('Please enter a username');
}
// Display Error if Password is Empty
elseif (!$password) {
$this->error('Please enter a password');
}
// Search DB For User With Matching Username - If User Not Found Display/Log Error, Else Set User
else {
$user = $this->user->info($username, 'username', '', '`userid`');
if (!$user) {
$this->error('The username ' . $username . ' does not exist');
$this->log->error('User Not Found When Attempting to Login', ['username' => $username]);
} else {
$this->user->set('user', $user['userid']);
}
}
}
}
In order to answer your question, I think it's best to break down the concept of MVC into a very basic form, and its individual parts. I apologise in advance if this comes across as being somewhat condescending.
View
The view of the application displays anything and everything. If something is going to be displayed, it should be done in this layer
Controller
The controller is a mediator between the view and the model. It takes input from the view, applies logic/rules to it (where required), and interacts with the model to then get data to pass back to the view.
Model
This is where the loading and saving of data are done. The majority of the validation should have been done as part of the rules in the controller, and this should only pass details of any errors during loading or saving back to the controller should the arise. If there are no errors, it should return the relevant data, or a success status back to the controller.
With those points in mind, the model should not set flash messages to the session, that should be done within the controller depending on the result from the model.
Look at redirects and alerts as specific to one particular form of UI, and it should be obvious that there's no place for them in the Model. Simply always try to picture an alternative interface for your application; e.g. a command line interface for administrative tasks or a REST API. Redirects obviously have no place in either of these alternatives. Alerts are debatable... at the very least the form of the alert will be very different. Your Model will need to be able to pass back some status code to your Controller or View, and then it's the job of the Controller to react to "negative" events and the job of the View to visualise any alerts if necessary.
For example, your model may do something like this:
public function registerUser(User $user) {
...
if (!$successful) {
throw new EmailAlreadyRegisteredException;
}
return true;
}
The controller may then look like this:
public function userRegistration(Request $request) {
try {
$user = User::fromRequest($request);
$this->services->get('Users')->registerUser($user);
$this->view->render('registration_successful', $user);
} catch (InvalidUserData $e) {
$this->view->render('registration_form', $request, $e);
} catch (EmailAlreadyRegisteredException $e) {
$this->view->render('registration_failed', $user, $e);
}
}
The "alert" is passed around as an exception. It's just a method for the Model to signal to its callers what happened. It's up to the callers then to react to and visualise those events. You should certainly not expect any particular type of visualisation in the Model. So you don't want to hardcode specific HTML encoded messages or such. You don't even want to touch human languages at all, that's all the job of the View.

Categories