Laravel 8 with Sanctum.
I plan to use the same API routes for SPA and external users. The problem is that Sanctum requires the EnsureFrontendRequestsAreStateful middleware to be added to the "api" middleware group which makes my API "stateful". It's fine for a SPA, but I'd like to keep it "stateless" for external calls with token authentication.
The simplest solution would be to separate SPA and external routes, with different middleware groups. Not so elegant! Please advise something better :)
UPD: Decided to split routes
routes/api.php
Route::middleware('auth:sanctum')->as('api.')->group(function () {
require 'resources.php';
});
routes/spa.php
Route::middleware('auth:sanctum')->as('spa.')->group(function () {
require 'resources.php';
});
routes/resources.php
Route::apiResources([
'products' => 'Api\ProductController',
]);
App\Providers\RouteServiceProvider
public function boot()
{
$this->routes(function () {
....
Route::prefix('spa')
->middleware('spa')
->namespace($this->namespace)
->group(base_path('routes/spa.php'));
});
}
App\Http\Kernel
protected $middlewareGroups = [
....
// Stateless, external calls
'api' => [
'throttle:api',
SubstituteBindings::class,
],
// SPA, stateful, internal use
'spa' => [
EnsureFrontendRequestsAreStateful::class,
'throttle:api',
'SubstituteBindings::class,
],
];
Related
I want take auth middleware on only create, update, delete route ressource. I know how to do with simple route, so, i don't know with ressource route.
Route::resource('cars', CarController::class);
Route::get('/cars/{car}/delete', [CarController::class, 'softdelete'])->name('cars.softdelete')->middleware('auth');
Route::get('/dashboard', function () {
return view('dashboard');
})->middleware(['auth'])->name('dashboard');
You can put the middleware on your controller:
public function __construct()
{
$this->middleware('auth')->except(['index','show']);
// OR
$this->middleware('auth')->only(['store','update','edit','create']);
}
You can do that if you define the resource route with and without middleware separate: (quick example of the idea)
Route::resource('cars', CarController::class, [
'only' => [
'index',
'show'
]
]);
Route::resource('cars', CarController::class, [
'except' => [
'index',
'show'
]
])
->middleware([ 'auth']);
I am trying to code a login function for my api that takes a username and password then give you a password grant token to make api requests. The login route when called gives you
{
"message": "Unauthenticated."
}
I am using passport on laravel to do secure the api. Why am I getting a 401 when the route does not have the auth:api middleware? I tried using a clousure to see if I get could get a response and the closure did not give me an error.
Route::group(['prefix' => '/v1', 'middleware' => ['auth:api'], 'namespace' => 'Api\V1', 'as' => 'api.'], function () {
Route::post('/post/like','PostLikeController#store');
});
Route::group(['prefix' => '/v1', 'namespace' => 'Api\V1', 'as' => 'api.'], function () {
Route::post('login', 'Auth\LoginController#login');
});
Does your login controller have a constructor? sometimes middleware is set in there?
Otherwise I've also had issues with having the middleware routes above the public ones.
Try putting the public routes in the file first and also checking the LoginController.php for a constructor which might be setting a middleware
It possibly due to the same prefixes, as it does not overriding but instead stacking on top of each other.
I suggest for your login route, possibly, you can use this
Route::post('login', 'Auth\LoginController#login')->withoutMiddleware([FooMiddleware::class]);
If it's still does not help try putting your login route above the middlewared route.
I have a question that might sound silly to you so please forgive me.
I am not sure when do I use the routes/api.php file.
If I want to delete a record from a datatable with ajax, do I need to create a separate controller and put the route in api.php or can I use the same controller I use for everything else and put the route in web.php?
I'm not sure if you read the Laravel documentation or how much familiar you are with Laravel, but in Laravel 5.3 you have web routes and api routes in separate files.
You use api routes only for registering your api (ie if you are building a rest api service), and all routes placed there will be prefixed by default with /api. So ie if you define a route /user inside the api file, it will be automatically prefixed with /api, so your end point would be www.yourapplication.com/api/user.
If you are not building a rest api service or anything similar dont use this file at all, use the web file for defining all of your application routes.
Also consider visiting Laracast website, as they have a nice introduction to new changes in Laravel 5.3 including web and api routes. Hope this helps you.
All that routes placed in api.php will be prefixed by /api, which was also mentioned by bernadd, there are other differences:
in this link(https://mattstauffer.co/blog/routing-changes-in-laravel-5-3) you can find the difference between api and web in laravel code:
in App\Providers\RouteServiceProvider:
public function map()
{
$this->mapApiRoutes();
$this->mapWebRoutes();
//
}
protected function mapApiRoutes()
{
Route::group([
'middleware' => ['api', 'auth:api'],
'namespace' => $this->namespace,
'prefix' => 'api',
], function ($router) {
require base_path('routes/api.php');
});
}
protected function mapWebRoutes()
{
Route::group([
'namespace' => $this->namespace, 'middleware' => 'web',
], function ($router) {
require base_path('routes/web.php');
});
}
in App\Http\Kernel.php in "protected $middlewareGroups" you can see this:
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
And:
in config\auth.php : In this file's Comments you can clearly find out the difference between default "auth"('guard' => 'web') vs "auth:api"
I'm looking to filter child routes for admins route, for example:
get('admins/*', ['middleware' => 'auth', function() {}]);
I think in Laravel 4 was Route::when('admins/*', '/'); to redirect user for / if not has auth by Call Pattern Filter from filter.php.
Is there someway to achieve that in Laravel 5.1?
You could set the admins path as a group and set the middleware on the whole group:
Route::group(['prefix' => 'admins', 'middleware' => 'auth'], function () {
Route::get('some_admin_page', function () {
# code...
});
});
Another way to achieve it in case all 'admins' routes are under the same controller you can set in the constructor to call the middleware
public function __construct() {
$this->middleware('auth');
}
Is it possible to add middleware to all or some items of a resourceful route?
For example...
<?php
Route::resource('quotes', 'QuotesController');
Furthermore, if possible, I wanted to make all routes aside from index and show use the auth middleware. Or would this be something that needs to be done within the controller?
In QuotesController constructor you can then use:
$this->middleware('auth', ['except' => ['index','show']]);
Reference: Controller middleware in Laravel 5
You could use Route Group coupled with Middleware concept:
http://laravel.com/docs/master/routing
Route::group(['middleware' => 'auth'], function()
{
Route::resource('todo', 'TodoController', ['only' => ['index']]);
});
In Laravel with PHP 7, it didn't work for me with multi-method exclude until wrote
Route::group(['middleware' => 'auth:api'], function() {
Route::resource('categories', 'CategoryController', ['except' => 'show,index']);
});
maybe that helps someone.
UPDATE FOR LARAVEL 8.x
web.php:
Route::resource('quotes', 'QuotesController');
in your controller:
public function __construct()
{
$this->middleware('auth')->except(['index','show']);
// OR
$this->middleware('auth')->only(['store','update','edit','create']);
}
Reference: Controller Middleware
Been looking for a better solution for Laravel 5.8+.
Here's what i did:
Apply middleware to resource, except those who you do not want the middleware to be applied. (Here index and show)
Route::resource('resource', 'Controller', [
'except' => [
'index',
'show'
]
])
->middleware(['auth']);
Then, create the resource routes that were except in the first one. So index and show.
Route::resource('resource', 'Controller', [
'only' => [
'index',
'show'
]
]);