Laravel 5.3 Auth block user - laravel

I have a question, I'm currently developing a little site with Laravel 5.3 and I'm using the Basic Auth from them for users to register and login.
Now I want the following: Everybody can register and login, but if I click on a button (as an admin), I can "block" one specific user (for example if he did something not allowed), I don't completely delete the row in the database, but somehow make sure that if the user tries to login he get's a message saying something like "you can't login any more, your account is blocked, contact admin for more info" or something similar. The question is: Whats the best way to do this? I didn't find something built in, correct me if I'm wrong...
Ofcourse, I could just alter the users table and add a column called "blocked", set to false normally, then with the button, set it to true and then when logging in somehow checking for this value and (if it's true) showing this message and not allowing log in. Is this the best way to do this? If yes, where would I have to check for this value and how can I show the message then? If not, whats the better way?

I would do what you're suggesting - use a blocked or active column to indicate if the user should be able to log in. When I've done something similar in the past, to check this value upon login, I moved the out-of-the-box login function into my LoginController and added to it a bit. My login method now looks like this:
/**
* Handle a login request to the application.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function login(Request $request)
{
$this->validateLogin($request);
$user = User::where('email', $request->email)->firstOrFail();
if ( $user && !$user->active ) {
return $this->sendLockedAccountResponse($request);
}
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if ($this->attemptLogin($request)) {
return $this->sendLoginResponse($request);
}
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
I also added these functions to handle users who weren't active:
/**
* Get the locked account response instance.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
protected function sendLockedAccountResponse(Request $request)
{
return redirect()->back()
->withInput($request->only($this->loginUsername(), 'remember'))
->withErrors([
$this->loginUsername() => $this->getLockedAccountMessage(),
]);
}
/**
* Get the locked account message.
*
* #return string
*/
protected function getLockedAccountMessage()
{
return Lang::has('auth.locked')
? Lang::get('auth.locked')
: 'Your account is inactive. Please contact the Support Desk for help.';
}

You can use soft deleting feature.
In addition to actually removing records from your database, Eloquent can also "soft delete" models. When models are soft deleted, they are not actually removed from your database. Instead, a deleted_at attribute is set on the model and inserted into the database. If a model has a non-null deleted_at value, the model has been soft deleted.

step1:
add new field to the User table called ‘status’ (1:enabled, 0:disabed)
step2:
to block the web login , in app/Http/Controllers/Auth/LoginController.php add the follwoing function:
/**
* Get the needed authorization credentials from the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
protected function credentials(\Illuminate\Http\Request $request)
{
$credentials = $request->only($this->username(), ‘password’);
return array_add($credentials, ‘status’, ‘1’);
}
Step3:
to block the user when using passport authentication ( token ) , in the User.php model add the following function :
public function findForPassport($identifier) {
return User::orWhere(‘email’, $identifier)->where(‘status’, 1)->first();
}
refer to this link ( tutorial) will help you : https://medium.com/#mshanak/solved-tutorial-laravel-5-3-disable-enable-block-user-login-web-passport-oauth-4bfb74b0c810

There is a package which not only blocks users but also lets you to monitor them before making a decision to block them or not.
Laravel Surveillance : https://github.com/neelkanthk/laravel-surveillance

Solved: this link ( tutorial) will help you : https://medium.com/#mshanak/solved-tutorial-laravel-5-3-disable-enable-block-user-login-web-passport-oauth-4bfb74b0c810
step1:
add new field to the User table called ‘status’ (1:enabled, 0:disabed)
step2:
to block the web login , in app/Http/Controllers/Auth/LoginController.php add the follwoing function:
/**
* Get the needed authorization credentials from the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
protected function credentials(\Illuminate\Http\Request $request)
{
$credentials = $request->only($this->username(), ‘password’);
return array_add($credentials, ‘status’, ‘1’);
}
Step3:
to block the user when using passport authentication ( token ) , in the User.php model add the following function :
public function findForPassport($identifier) {
return User::orWhere(‘email’, $identifier)->where(‘status’, 1)->first();
}
Done :)

Related

how to set up and authentication system allowing admin to go the dashboard, and regular user to his profile?

I want to create a system login, that direct the regular users to their profiles, and direct the admin to the dashboard, using the same logging form is that possible in laravel??
i was looking for a solution for that problem, if any one have any idea how to do it??
Assuming you have used Laravel's default auth scaffolding, you can customize how the user is redirected after logging in by modifying the authenticated method in your LoginController :
/**
* The user has been authenticated.
*
* #param \Illuminate\Http\Request $request
* #param mixed $user
* #return mixed
*/
protected function authenticated(Request $request, $user)
{
if ($user->hasRole('admin')) { // If using spatie/laravel-permissions
return redirect()->route('dashboard');
}
return redirect()->route('profile', ['user' => $user]);
}

Getting the number of login attempts in the GET or while rendering the view in Laravel

I am developing a web application using Laravel. What I am trying to do now is I am trying to get the number of login attempts in the GET or render view. I can get the number of login attempt in the post request (validateLogin method) of LoginController as follow.
$this->limiter()->attempts($this->throttleKey($request))
The thing is that the validateLogin method takes one parameter, Request $request. What I like to do is that I like to get the number of failed login attempts or number of attempts in the showLoginForm method of LoginController. I am overriding the showLoginForm method. I tried this.
$this->limiter()->attempts($this->throttleKey(request()))
But it always returns zero. So how can I get the number of login attempts in the GET or showLoginForm method of the LoginController?
When login fails, increment the number, when login was successful, clear the attempts. This can be done using sessions. With sessions, you can use it in blade files and in your controllers.
In your app/Http/Controllers/Auth/LoginController.php file:
use Illuminate\Http\Request;
/**
* Get the failed login response instance.
*
* #param \Illuminate\Http\Request $request
* #return \Symfony\Component\HttpFoundation\Response
*
* #throws \Illuminate\Validation\ValidationException
*/
protected function sendFailedLoginResponse(Request $request)
{
$attempts = session()->get('login.attempts', 0); // get attempts, default: 0
session()->put('login.attempts', $attempts + 1); // increase attempts
throw ValidationException::withMessages([
$this->username() => [trans('auth.failed')],
]);
}
/**
* The user has been authenticated.
*
* #param \Illuminate\Http\Request $request
* #param mixed $user
* #return mixed
*/
protected function authenticated(Request $request, $user)
{
session()->forget('login.attempts'); // clear attempts
}
Then in your views or controllers you can just get the number from session:
{{ session()->get('login.attempts', 0) }}
When we have a look at the throttleKey method, we see that it creates a key out of the email address the user used tried to log in with and the IP address of the user. The IP address should already be in the $request object if you add it as a parameter to the showLoginForm method, but the email address wouldn't be there. You could add it using the old helper function.
public function showLoginForm(Request $request)
{
$request->merge(['email' => old('email')]);
Log::info($this->limiter()->attempts($this->throttleKey($request)));
return view('auth.login');
}
Edit:
Another way to do this would be to overwrite the sendFailedLoginResponse method and add the number attempts to the error bag. For example, in your LoginController:
protected function sendFailedLoginResponse(Request $request)
{
throw ValidationException::withMessages([
$this->username() => [trans('auth.failed')],
'attempts' => $this->limiter()->attempts($this->throttleKey($request)),
]);
}
Then you could get the number of attempts in your template with <strong>{{ $errors->first('attempts') }}</strong>

Laravel only retrieve Model Records if they belong to authenticated user

I'm using Laravel 5.4 and have a Model called Order.
To test things I've created two users and two Orders, each user having one Order.
I've just seen that I'm able to retrieve the order of someone who is not my current user. I'm retrieving a list of user's own orders using Auth::user()->orders. But in order to show the details of a specific order I do this:
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
$order = CustomerOrder::findOrFail($id)->with('products')->get();
return view('order.show')
->with('order', $order);
}
What am I missing out here? Is there a middleware or something to tell the application to only allow access to orders associated with the authenticated user?
Edit: So I've tried to do it using a Policy OrderPolicy (CRUD).
The view() fucntion of the Policy:
/**
* Determine whether the user can view the customerOrder.
*
* #param \App\User $user
* #param \App\CustomerOrder $customerOrder
* #return mixed
*/
public function view(User $user, CustomerOrder $customerOrder)
{
return $user->id === $customerOrder->user_id;
}
And I've registered it in the AuthServiceProvider.php:
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
Adress::class => AdressPolicy::class, //Doesn't work either
Order::class => OrderPolicy::class
];
I can still check the Order for another user.
You have a few options. The best option in my option is the use Policies. The documentation for this can be found here:
https://laravel.com/docs/5.4/authorization
Alternatively do could do something like:
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
$user = request()->user();
$order = $user->orders()->with('products')->find($id)->get();
return view('order.show', compact('order'));
}
With an orders relationship function on your user model.
Updated Reply
With the policy you gave, and with your resource route, you should be able to do:
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show(CustomerOrder $order)
{
$this->authorize('view', $order);
return view('order.show', compact('order'));
}
Another way would be to use the defined relationship and tell it to only retrieve the one with id $id. Like this:
$customerOrder = auth()->user()->orders()->with('products')->find($id);
If you want to get orders which belong to authenticated user, do this:
CustomerOrder::where('user_id', auth()->user()->id)->with('products')->find($id);
Remember,
first you create policy.
second you register it.
third you use something like $this->authorize('view', $order); in your normal controller.
You are missing the third step, you can find the doc here:
[https://laravel.com/docs/5.8/authorization#authorizing-actions-using-policies][1]

Laravel 5.2 Redirecting user based on user column

I have a multiple step form. Every time a user completes one of the forms the currentStep column is updated. If the user does not complete all four forms before logging out, when they log back in they will be redirected to whatever step they left off on. Is overriding the authenticated method in my AuthController the best way to do this?
protected function authenticated($request, $user)
{
if ($user->step === '1') {
return redirect()->intended('reg/step2');
}
return redirect()->intended('/');
}
Yes using authenticated method or overriding redirectPathmethod will be enough.
By the way, In my personal opinion, as suggested in the comment above; creating a middleware to implement a simple functional requirement like:
"The software shall redirect the users to the step which they left off only when they login back to the software."
is over engineering which we should avoid. As you can already see, laravel itself uses a method in a trait to redirect the user after a successful login. Not a middleware.
see the last line (from v.5.1 LTS):
/**
* Send the response after the user was authenticated.
*
* #param \Illuminate\Http\Request $request
* #param bool $throttles
* #return \Illuminate\Http\Response
*/
protected function handleUserWasAuthenticated(Request $request, $throttles)
{
if ($throttles) {
$this->clearLoginAttempts($request);
}
if (method_exists($this, 'authenticated')) {
return $this->authenticated($request, Auth::user());
}
return redirect()->intended($this->redirectPath());
}

Adding information in session when user is logged in Laravel 5.2

I have a scenario where I am putting certain information in session after user is successfully logged in. I am using Laravel 5.2. As in Laravel 5.2 you just redirect user to /login and specify protected $redirectTo variable and the rest is cared by Laravel itself. Now I want whenever user is logged in successfully, I want to put some information in session. Currently what I am doing when user is redirected to my protected $redirectTo url I put information in that like
\Session::put('user.data', $someData);
It works fine in normal scenario. But say user is logged out and tries to access some auth protected url, say example.com/showUsers saved in his browser. Now Laravel will check its a login protected url it will redirect user to login page, user is successfully logged in and Now in this case Laravel redirects the user to previous url. Now the information that I want to put in session isn't in session so I get error.
I have checked Auth/AuthController, Authication.php in middleware but don't find any place.
Currently I am putting it in /app/Http/Middleware/Authenticate.php before the last statement return $next($request); like this
if(empty(\Session::get('user.data'))) {
$someData = getSomeData();
\Session::put('user.agency', $someData);
}
return $next($request);
I don't know its a good approach or not So can any body let me know am I doing good or where do I put my session code that is executed every time user logs in.
As far as I understood, you are using the AuthControllerand AuthenticatesUsers trait to log your users in which is the default of Laravel.
In AuthenticatesUser trait on line 114, you will see a method definition check which was written for the users of the framework to define additional login related work.
/**
* Send the response after the user was authenticated.
*
* #param \Illuminate\Http\Request $request
* #param bool $throttles
* #return \Illuminate\Http\Response
*/
protected function handleUserWasAuthenticated(Request $request, $throttles)
{
if ($throttles) {
$this->clearLoginAttempts($request);
}
if (method_exists($this, 'authenticated')) {
return $this->authenticated($request, Auth::guard($this->getGuard())->user());
}
return redirect()->intended($this->redirectPath());
}
In your AuthController class,
creating a method called authenticated and doing your work there should be a more expected behaviour.
/**
* Return the authenticated response.
*
* #param $request
* #param $user
* #return \Illuminate\Contracts\Routing\ResponseFactory
*/
protected function authenticated(Request $request, $user)
{
// Here.
}

Resources