I have my controller ExampleController:
class ExampleController extends Controller
{
function __construct()
{
$this->middleware('auth:student')->only(['store', 'update', 'destroy']);
}
public function index()
{
if(CheckUser::student()) {
dd("Is student");
}
dd("Isn't student");
}
/**
* Another method's not relevant.
**/
}
I'm trying to add some logic if is student.
But have one problem, I just can access: Auth::user() if I set the middleware. But this specific method can be accessed without has logged in.
My question
Is possible to create a not required middleware for what if logged get user information?
Note: I'm using Laravel passport with multi auth.
If you want to protect specific methods that are in your controller and leave out others in the same controller
You may try to protect your endpoint on the routes files (api.php or web.php) rather than on the Constructor
//protected routes
Route::group(['middleware' => 'auth:api'], function () {
Route::post('customer/picture/add', 'Mobile\AuthController#addProfilePicture');
Route::post('customer/phone/update', 'Mobile\AuthController#updatePhoneNumber');
});
//unprotected routes
Route::get('customer/login', 'Mobile\AuthController#getLoginForm');
Related
I have to setup my authentication for my reservations system in Laravel.
The basic routing methods by Laravel and a lot of tutorials is by writing the function for the route inside the web.php like this Laraval example:
Route::get('/flights', function () {
// Only authenticated users may access this route...
})->middleware('auth');
However, I was told this isn't the best way to set up routing and that I should use a controller to manage routes.
But that means I have to setup authentification methods inside the controller and to be honest, I don't have the vision to do this..
I thought I could do it like this (My Code)
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Providers\RouteServiceProvider;
use Illuminate\Support\Facades\Auth;
class PagesController extends Controller
{
public function home() {
return view('home');
}
public function reservations() {
return view('reservations')
->middleware(['auth']);
}
public function newreservations() {
return view('reservations_new');
}
}
combined with this web.php setup:
Route::get('/reservations.html', [PagesController::class, 'reservations']);
Route::get('/reservations.html/login', [AuthenticatedSessionController::class, 'create']);
Route::post('/reservations.html/login', [AuthenticatedSessionController::class, 'store']);
Route::get('/reservations_new.html', [PagesController::class, 'newReservations']);
but then I got the error:
Method Illuminate\View\View::middleware does not exist.
So any tips/tricks/methods to do it the right way?
There is no right or wrong way as long as you follow the same principal.
I personally do this:
Route::middleware('auth')->group(function () {
// Authenticated routes
});
you can check this extended discussion
also if you want to use middlewares in controller, this is the right way
class UserController extends Controller
{
/**
* Instantiate a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('log')->only('index');
$this->middleware('subscribed')->except('store');
}
}
I have a code in HomeController.php in the Laravel framework, but I could not access the index/homepage it redirects to the login page. what is the blunder I am committing?
<?php
namespace App\Http\Controllers;
use App\User;
use Illuminate\Http\Request;
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$users = User::get();
return view('home', compact('users'));
}
public function user($id){
$user = User::find($id);
return view('user', compact('user'));
}
public function ajax(Request $request){
$user = User::find($request->user_id);
$response = auth()->user()->toggleFollow($user);
return response()->json(['success'=> $response]);
}
}
The answer is simple. In the __construct() method, you specified that every function under this controller must use the auth middleware. This will redirect to login page is the user is not logged in.
There are a number of ways to work around this, the first being to remove the __construct entirely. However, this is not so recommended.
Another would be to add an except() function
public function __construct()
{
$this->middleware('auth')->except('index');
}
This will allow the condition to apply anywhere else other than the index function.
Based on the code you posted, the homepage route is protected by the 'auth' middleware, which means users have to login to access the resource page (Home page), so you should first login and then it will direct you to the intended page. If you don't want the page to be protected, then you could either remove the $this->middleware('auth') in your constructor, or you could put the index() function separately in a different Controller file and leave it unprotected
you can also control it in the routes (routes/web.php).
Or as already mentioned with middleware: Assigning Middleware To Routes
Route Group
Use route grouping in your web.php file
This way you can determine middleware for specific routes, you can also use grouping inside route group also
And don't use middleware in controller, use it in web.php so you can have a proper idea that how many routes are using middleware
I know I can easily create API in laravel, like below.
Http/Controllers/Api/MyApiController.php
use App\Model\MyModel;
class MyApiController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$models = MyModel::all();
return $models;
}
....
routes/api.php
Route::group(['middleware' => ['api']], function(){
Route::resource('myTable', 'Api\MyApiController');
});
But it seems that it has only basic CRUD methods.
Is there a way to add custom method and call it by some Http requests?
I mean, If I added my own method like as follows:
public function myMethod()
{
$models = MyModel::all()->where('id', '>', 100)->get();
return $models;
}
I want to use it by such a request as GET /api/MyMethod/{id}.
Does anyone know any ways without adding route to web.php?
thanks.
You can. You just need to define those routes in your routes/api.php file.
routes/api.php
Route::group(['middleware' => ['api']], function(){
Route::resource('myTable', 'Api\MyApiController');
// Define new routes like this
Route::get('myTable/MyMethod/{id}', 'Api\MyApiController#myMethod');
});
Update
Even though its perfectly fine to define routes with custom method names (other than the basic CRUD ones) in such a way, it can often lead to overpopulated controllers. Check out this interesting talk by Adam Wathan about this issue.
I am using api throttle in my routes/api.php (as you can see in the code) but I am wondering if I can use it in the controller on methods.
Route::resource('/user/{user}/post', 'UserPostController')->middleware(['auth:api', 'throttle:5,1']);
Better to use the routes to specify the middleware for the routes. Still you think to use / specify inside your controller you can define __construct() menthod in your controller like:
public function __construct()
{
$this->middleware('throttle:5,1')->only('index');
}
This will work on the index action of your controller only.
For more details check the documentation Controller Middlewares
you can override route for example
Route::resource('/user/{user}/post', 'UserPostController')->middleware(['auth:api', 'throttle:5,1']);
//add route after resource
Route::get('/user/create', 'UserPostController#create')->middleware(['auth:api', 'throttle:5,1']);
second way add condition in controller
public function __construct()
{
$this->middleware('auth:api');
$this->middleware('throttle:10,1')->only('create');
}
I want an app to use a URL structure something like this:
/account/johnsmith/photos
/account/johnsmith/messages
/account/johnsmith/settings
/account/joebloggs/photos
So users may add multiple accounts and then the route group selects the account automatically.
Route::group(['middleware' => 'auth', 'prefix' => 'account/{username}'], function () {
Route::get('/photos', 'PhotosController#index')->name('photos.index');
});
In the above example I can access the {username} parameter inside of PhotosController#index.
Is there a way to write some middleware that gets the account information automatically and it's accessible to all child routes in the group? Or am is this a bad way to try to build this?
This should be possible with route model binding.
Route::bind('username', function ($username) {
return Account::findByUsername($username);
});
Note: The above code could be put in your route provider or within the route group its self.
When done, you will pass the model Account into your controller methods as the first argument and it will automatically be the one matching that username. Or a 404 if it does not exist.
// If {username} is 'bob', the Account object now references Bob's account.
public function index(Account $account) {}
See Laravel Docs Here
Yes, if you need to perform a operation before all your controller methods get the request o propagate some common data you should use Laravel middlewares. It will not only centralise your logic as well as make your controller code neat.
Even laravel sometimes want you to do that.
In previous versions of Laravel, you could access session variables or the authenticated user in your controller's constructor. This was never intended to be an explicit feature of the framework. In Laravel 5.3, you can't access the session or authenticated user in your controller's constructor because the middleware has not run yet.
As an alternative, you may define a Closure based middleware directly in your controller's constructor. Before using this feature, make sure that your application is running Laravel 5.3.4 or above
So you can either write a middleware to calculate account details and if you are using the laravel version 5.3.4 and above you can directly assign it to the controller properties in constructor using closure based middlewares.
Like this:
class ProjectController extends Controller
{
/**
* All of the current user's account details
*/
protected $accountDetails;
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->accountDetails= Auth::user()->accountDetails;
return $next($request);
});
}
}
Hope this would help.