Laravel Login Controller - Direct to Admin or User Routes - laravel

I have a Laravel8 Project where I am doing everything from scratch so i can learn the system (newbie) - I have a LoginController with the code
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class LoginController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
// Show Login Page
return view('auth.login');
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
$this->validate($request, [
'email'=> 'required|email',
'password' => 'required',
]);
if (!auth()->attempt($request->only('email', 'password'), $request->remember)) {
return back()->with('status', 'Invalid Login Details' );
}
return redirect()->route('admin.dashboard');
}
I have the roles tables and pivot table set up but not sure how to amend the return redirect()->route('admin.dashboard'); to the correct code so depending if the user is an admin or a standard user it uses the correct route

You can give simple condition after login attempt success like below.
if (auth()->user()->role == 'admin') {
return redirect()->route('admin.dashboard');
}
return redirect()->route('user.dashboard');
As per your described question, you have a different table for assign roles to the user. So you have to create relation with roles table to identifies the role of the user.

You'll need to make sure to import the Auth facade at the top of the class. Next, let's check out the attempt method:
use Illuminate\Support\Facades\Auth;
...
public function store(Request $request) {
// ...
if (!auth()->attempt($request->only('email', 'password'), $request->remember)) {
return back()->with('status', 'Invalid Login Details' );
}
// Redirect to admin dashboard
return redirect()->intended('route.dashboard');
}
For more details read the Docs Manually Authenticating Users

Related

ReCaptcha on Laravel

I have ReCaptcha in Register controller and I wanted to put it in the login controller here like
<?php
namespace App\Http\Middleware;
use App\Rules\Captcha;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
use App\Rules\Captcha;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* #param \Illuminate\Http\Request $request
* #return string|null
*/
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
return route('login');
}
}
protected function validateLogin(Request $request)
{
$this->validate($request, [
'g-recaptcha-response' => new Captcha(),
]);
}
}
But Im getting an error Cannot use App\Rules\Captcha as Captcha because the name is already in use
Is there other ways to put ReCaptcha in the reg and log?
You have the following line twice at the start of your file:
use App\Rules\Captcha;

Applying Passport scopes conditionally on api resource methods

I am using passport personal access token to secure my API. Here are some of the code snippets.
// api.php
Route::apiResource('categories', 'CategoryController');
AuthServiceProvider.php
public function boot()
{
$this->registerPolicies();
//scopes
Passport::tokensCan([
'admin' => 'Perform every action',
'user' => 'Perform only normal user actions',
]);
// passport routes
Passport::routes();
//
}
CategoryController.php
class CategoryController extends Controller
{
function __construct()
{
$this->middleware('api:auth', ['scopes: admin']);
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
return CategoryResource::collection(Category::all());
}
...
As you can see I have used the admin scope which is only accessible to admin users. But the problem is category model can only be edited or updated by the admin scope and can be accessed by both admin and user scopes. What could be the best approach to address this issue?
One solution that worked for me is I have used middleware two times with different scopes.
class CategoryController extends Controller
{
function __construct()
{
$this->middleware('api:auth', ['scopes: admin'])->except(['index']);
$this->middleware('api:auth', ['scopes: user'])->only(['index']);
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
return CategoryResource::collection(Category::all());
}
...

After login getting too many redirects error

Whenever I try to add a product to a wishlist I am redirected to a login page where I enter my credentials and after that it keeps reloading and this error appears.
Thereafter, when I return to home page and refresh I am logged in. But when I try to access a page directly which requires login, it works perfectly fine. This error has been appearing for sometime now, it was previously working fine.
routes:
Auth::routes();
Route::group(['middleware'=>'auth'],function (){
Route::get('/checkout','PageController#checkout')->name('checkout');
Route::post('/coupon','PageController#coupon')->name('coupon.check');
Route::post('/order', 'OrderController#store')->name('order.store');
Route::post('/orderinfo', 'OrderInfoController#store')->name('orderinfo.store');
Route::get('/invoice/{order}','PageController#invoice')->name('invoice');
Route::resource('/profile', 'ProfileController');
Route::get('/wishlist', 'WishlistController#index')->name('wishlist.index');
Route::get('/wishlist/{product_id}/remove', 'WishlistController#remove')->name('wishlist.remove');
Route::get('/wishlist/{product_id}', 'WishlistController#quick')->name('wishlist.quick');
Route::resource('/review', 'ReviewController');
Route::get('/orders', 'PageController#order')->name('orders');
Route::group(['middleware'=>'admin'],function () {
Route::resource('/admin/products', 'ProductController');
Route::resource('/admin/categories', 'CategoryController');
Route::resource('/admin/subcategories', 'SubcategoryController');
Route::resource('/admin/coupons', 'CouponController');
Route::resource('/admin/taxes', 'TaxController');
Route::resource('/admin/discounts', 'DiscountController');
Route::get('/admin/index', 'PageController#admin')->name('admin.index');
Route::post('/admin/ajax/category', 'PageController#ajax')->name('ajax.category');
Route::resource('/admin/users', 'UserController');
Route::resource('/admin/tracks', 'TrackController');
Route::get('/order', 'OrderController#index')->name('order.index');
Route::get('/order/{order}', 'OrderController#show')->name('order.show');
});
});
Route::get('/product/{product}','PageController#product')->name('product.view');
Route::get('/','PageController#index')->name('index');
Route::get('/about-us','PageController#about_us')->name('about_us');
Route::resource('/contact-us','ContactController');
Route::get('/shop','PageController#shop')->name('shop');
Route::get('/home', 'HomeController#index')->name('home');
Route::post('/cart', 'CartController#add')->name('cart.add');
Route::get('/cart{product}', 'CartController#quick')->name('cart.quick');
Route::get('/cart/show', 'CartController#show')->name('cart.show');
Route::patch('/cart/{product_id}', 'CartController#update')->name('cart.update');
Route::get('/cart/{product}/remove', 'CartController#remove')->name('cart.remove');
Route::get('/shop/filter/{subcategory_id}','PageController#filter')->name('filter.product');
Route::get('/shop/category/{category}','PageController#shop_2')->name('filter.categories');
Login Controller:
<?php
namespace App\Http\Controllers\Auth;
use App\Category;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo;
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function redirectTo()
{
}
public function showLoginForm()
{
$categories = Category::all();
$cart_items = session()->get('cart');
$sub_total = 0;
if (!empty($cart_items)) {
foreach ($cart_items as $item) {
$sub_total = ($item['price'] * $item['quantity']) + $sub_total;
}
}
return view('login', ['cart_items' => $cart_items, 'sub_total' => $sub_total,'categories'=>$categories]);
}
}
This is how I am sending get request and which gives error after login:
<a class="add-wishlist" title="wishlist" href="{{route('wishlist.quick',$product->id)}}"><i class="fa fa-heart"></i></a>
Wishlist Controller:
<?php
namespace App\Http\Controllers;
use App\Category;
use App\Helpers\helper;
use App\Product;
use App\Wishlist;
use Illuminate\Http\Request;
class WishlistController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
//
$categories= Category::all();
$cart_items = helper::cart_data();
$sub_total = helper::sub_total($cart_items);
$user_id = auth()->user()->id;
$wishlist = Wishlist::all()->where('user_id', '=', $user_id);
$products = [];
foreach ($wishlist as $list) {
$products[] = Product::find($list->product_id);
}
return view('wishlist', ['wishlist' => $wishlist, 'products' => $products,'sub_total'=>$sub_total,'categories'=>$categories,'cart_items'=>$cart_items]);
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
$user_id = auth()->user()->id;
$check = Wishlist::all()->where('user_id', $user_id)->where('product_id', $request['product_id']);
if ($check->isEmpty()) {
Wishlist::create([
'user_id' => $user_id,
'product_id' => $request['product_id']
]);
}
return redirect()->back();
}
/**
* Display the specified resource.
*
* #param \App\Wishlist $wishlist
* #return \Illuminate\Http\Response
*/
public function show(Wishlist $wishlist)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param \App\Wishlist $wishlist
* #return \Illuminate\Http\Response
*/
public function edit(Wishlist $wishlist)
{
//
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param \App\Wishlist $wishlist
* #return \Illuminate\Http\Response
*/
public function update(Request $request, Wishlist $wishlist)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param \App\Wishlist $wishlist
* #return \Illuminate\Http\Response
*/
public function remove(Request $request)
{
//
$user_id = auth()->user()->id;
Wishlist::where('user_id', $user_id)->where('product_id', $request['product_id'])->delete();
return redirect()->back();
}
public function quick($product_id)
{
//
$user_id = auth()->user()->id;
$check = Wishlist::all()->where('user_id', $user_id)->where('product_id', $product_id);
if ($check->isEmpty()) {
Wishlist::create([
'user_id' => $user_id,
'product_id' => $product_id
]);
}
return redirect()->back();
}
}
Firstly, 419 error indicate an expired session. I notice you are using the session helper method session() inside showLoginForm(). You should be aware that if a user is logged out or his/her session expires then that user cannot access the data stored in that session as it will be wiped clean. Trying to access session data this way through showLoginForm is counter-intuitive as the user will most likely have been logged out or had an expired session before accessing the login form - except for the case where the user is accessing the login form for the first time. This could be a possible cause of the 419 errors.
You can remove the piece of code where you are trying to access the session data to any of your several controllers that require authentication. Then, you are sure that the user has a valid session before accessing session data.
However, to redirect users after a successful login Laravel uses either the $redirectTo variable or redirectTo() method of the LoginController. If the method is defined, it overrides the variable and if not, the variable is used.
From your LoginController, none of them is defined. Usually, the variable is set to redirect to the homepage - $redirectTo = '/home'. However, to meet your requirement of redirecting to the page that required the login, you must use the redirectTo() method.
You can achieve this by using the helper method url()->previous() within LoginController.php like this:
public static $previous;
public function showLoginForm() {
self::$previous = url()->previous();
// continue with your code.
}
public function redirectTo()
{
return self::$previous;
}
notice that I store the previous url when i first show the login form. after a successful login, this url should be available for me to redirect to.
UPDATE 1:
The problem route
Route::get('/cart{product}', 'CartController#quick')->name('cart.quick');
has a problem. You are missing a forward slash after /cart. You should notice this issue when you look at the generated url in the link. The correct form should be
Route::get('/cart/{product}', 'CartController#quick')->name('cart.quick');
UPDATE 2:
Since the route wishlist.quick is going through the auth middleware, do not use redirect()->back() for going back to the same page after user action with that route.
This is because, with the auth middleware in place, redirect()->back() is not always pointing to same location.
For instance, an unauthenticated user accessing the wishlist.quick route will be redirected to the login page. If login is successful the request continues to wishlist.quick route. Now, try to guess where the redirect()->back() inside WishlistController#quick is pointing to. Right! Surprisingly, it is pointing to the login page. So now the authenticated user completes his/her request with WishlistController#quick and is directed to the login page again. The login controller detects the user is authenticated and redirects the user to wherever he/she is coming from - WishlistController#quick. Again, there is redirect()->back() sending the user back again to the login page. You see the infinite redirect loop clearly in this funny scenario.
SOLUTION:
Change the line
return redirect()->back();
to
return $this->index();
Since WishlistController#quick doesn't return a view of its own, WishlistController#index is the best place to return to. Infact, you have to make this change for all routes that pass through a middleware and redirects the user back.
In other words, do not use redirect()->back() in a route that goes through middleware, if you really mean to go back to the same page.
A common issue with Laravel throwing a 419 error is because of a missing #csrf inside the form.
<form method="post" action="<some route>" >
#csrf
<input ...... />
</form>
If you are sending any data in a form, please ensure you have the above CSRF token.
If you do have this token, can you add the form in the main question?

Restricting not logged users access to admin panel in Laravel - routing issue

I've started creating my own very simple blog application, which would consist of main page with posts and admin panel accesible only for me. I don't want viewers to have access to login page, it should be just for one user - admin.
I already have admin panel from which I can create, edit, view and delete posts stored in mySQL database, also posts are displayed on main page. My problem is that I am strugling with securing the admin panel from not logged users.
How should I do this, idea is: if you are logged in - you are admin, you can access admin panel which views are stored in views/admin, if you are not - you can only see posts beeing displayed on main page in views folder.
publicHomePageTemplate.blade.php (piece responsible for displaying posts)
#foreach($articles as $article)
<div class="well well-lg">
<h3>{{$article->title}}</h3>
<p>{{$article->body}}</p>
</div>
#endforeach
Article Controller
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Article;
class ArticleController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function publicHomePage()
{
$articles = Article::paginate(4);
return view('articles/publicHomePageTemplate', ['articles'=>$articles]);
}
public function index()
{
$articles = Article::latest()->paginate(5);
return view('admin.index',compact('articles'))
->with('i', (request()->input('page', 1) - 1) * 5);
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
return view('admin.create');
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
request()->validate([
'title' => 'required',
'body' => 'required',
]);
Article::create($request->all());
return redirect()->route('admin.index')
->with('success','Article created successfully');
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
$article = Article::find($id);
return view('admin.show',compact('article'));
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
$article = Article::find($id);
return view('admin.edit',compact('article'));
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
request()->validate([
'title' => 'required',
'body' => 'required',
]);
Article::find($id)->update($request->all());
return redirect()->route('admin.index')
->with('success','Article updated successfully');
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
Article::find($id)->delete();
return redirect()->route('admin.index')
->with('success','Article deleted successfully');
}
}
So far I've started realising authentication system with php artisan:make auth
Any ideas how to solve this
Create a middleware that blocks users that should not access admin
This goes in the Http Kernel in $middlewareGroups
'admin' => [
'web',
\App\Http\Middleware\Permissions\AdminChecker::class,
],
then you create a middleware that checks the current user
public function handle($request, Closure $next)
{
$user = $request->user();
if (!$user || !$user->isAdmin()) {
throw new AuthenticationException;
}
return $next($request);
}
Then make sure that your admin routes are using the admin group
In the RouteServiceProvider
Route::group([
'middleware' => 'admin',
'namespace' => $this->namespace.'\Admin',
'prefix' => 'admin',
], function ($router) {
require base_path('routes/admin.php');
});
then you put your admin routes in 'routes/admin.php
if you add the field "role" in your table then try if(Auth::user()->role == 'admin'){}else{}. you can also use this code in your blade file like #if().

Change login rules at Laravel 5.6

I have a fresh project of Laravel 5.6 installed. I changed create_users_migration, added $table->boolean('is_active'); field. Now, I want when user is trying to login, to check if is_active field is set to true.
I tried to rewrite standard AuthenticatesUsers method :
protected function validateLogin(Request $request)
{
$this->validate($request, [
$this->username() => 'required|string',
'password' => 'required|string',
]);
}
After password I added line 'is_active' => true, , and now, when I press Log In button, it returns me an array_map(): Argument #2 should be an array error.
I tried to just copy-paste this method in LoginController, but it gives me same error. Any ideas, or may be is here another solution?
Full LoginController code :
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = '/';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
/**
* Validate the user login request.
*
* #param \Illuminate\Http\Request $request
* #return void
*/
protected function validateLogin(Request $request)
{
$this->validate($request, [
$this->username() => 'required|string',
'password' => 'required|string',
'is_active' => true,
]);
}
}
You are editing the wrong method. This method validates the request and "true" is not a validation rule, that's why you are getting the error.
Here is a simple solution. Override the credentials method on your LoginController as below.
protected function credentials(Request $request)
{
$data = $request->only($this->username(), 'password');
$data['is_active'] = true;
return $data;
}
So this way only active users can login.
You can also create a middleware and use it to send the users that have not activated their account to activation page.
I did this for one project with a middleware :
<?php
namespace App\Http\Middleware;
use Closure;
class isActiv
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if($request->user()->isActiv()){
return $next($request);
}else{
return redirect()->route('dashboard')->with('errors', 'Votre compte utilisateur n\'est pas activé sur le site. Veuillez contacter un administrateur pour résoudre le problème.');
}
}
}
Then in my route file web.php :
Route::group(['middleware' => ['isActiv'] ], function(){
And in my user model :
public function isActiv(){
if($this->is_activ == 1 || $this->is_admin == 1){
return true;
}
return false;
}

Resources