laravel 5: "Session store not set on request." in api.php - laravel

I get user data via this link:
https://www.example.com/api/v1/user?api_token=e0220d90-e6e4-11a2-bddd-c6a491dff8e7mb
and in api.php
Route::group(['prefix' => 'v1', 'namespace' => 'API\v1','middleware' => 'auth:api'], function () {
Route::get('/user' , 'AuthController#user');
});
when api_token is true, it return me user data.
but when api_token is false, it return me an error:
"Session store not set on request."
I try add this code in end of api.php to handle wrong api_token
Route::fallback(function () {
return response(['status' => 403]);
});
But again,I get same error
what is my problem?

Related

Laravel "Unauthenticated" error in specific route

In my Laravel 7 backend I have some api url like:
Route::group(['namespace' => 'Api', 'middleware' => ['auth:sanctum']], function(){
Route::post('logout/all', 'Auth\LoginController#logoutAll');
Route::post('logout', 'Auth\LoginController#logout');
Route::put('profile/{profile}', 'ProfileController#update');
});
The route /logout and /profile/1 work fine, while the route /logout/all gives an error:
{
"error": "Unauthenticated"
}
The token I use is correct because I can use it for others route and it works.
Of course I didn't call the /logout before trying the /logout/all.
I tried to change the controller function of logoutAll, setting it to "logout":
Route::group(['namespace' => 'Api', 'middleware' => ['auth:sanctum']], function(){
Route::post('logout/all', 'Auth\LoginController#logout');
Route::post('logout', 'Auth\LoginController#logout');
Route::put('profile/{profile}', 'ProfileController#update');
});
In this way it works, but this invoke the same function.
That's the code of the function:
public function logout(Request $request)
{
Auth::user()->tokens()->where('id', Auth::user()->currentAccessToken()->id)->delete();
return response()->json(['data' => 'User logged out.'], 200);
}
public function logoutAll(Request $request)
{
//do nothing
return response()->json(['data' => 'User loggedAll out.'], 200);
}
Help me please.
UPDATE
If I use CURL command this is the output:
Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException: The POST method is not supported for this route. Supported methods: GET, HEAD. in file /Applications/MAMP/htdocs/test-server/vendor/laravel/framework/src/Illuminate/Routing/AbstractRouteCollection.php on line 117
#0 /Applications/MAMP/htdocs/test-server/vendor/laravel/framework/src/Illuminate/Routing/AbstractRouteCollection.php(103): Illuminate\Routing\AbstractRouteCollection->methodNotAllowed(Array, 'POST')
#1 /Applications/MAMP/htdocs/test-server/vendor/laravel/framework/src/Illuminate/Routing/AbstractRouteCollection.php(40): Illuminate\Routing\AbstractRouteCollection->getRouteForMethods(Object(Illuminate\Http\Request), Array)
#2 /Applications/MAMP/htdocs/test-server/vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.php(162): Illuminate\Routing\AbstractRouteCollection->handleMatchedRoute(Object(Illuminate\Http\Request), NULL)
...
The problem was in the __constructor() method
$this->middleware('guest')->except('logout');
I change it to:
$this->middleware('guest')->except(['logout', 'logoutAll']);
Now it works fine.

Laravel API call goes through even with session expired

I have a SPA based on Laravel 5.8 and Vue 2.0.
Everything is working fine, a little bit too much to be honest, because if I delete the session and I try to save the content afterward or keep navigating the private pages, every ajax call that I'm doing with Axios is going through without returning any error. Only if I forcefully refresh the page I get the error page I setup but if I don't, I can keep doing everything even if the session no longer exist.
This is my setup.
web.php is where I have the only php route that points to a singlePageController:
Auth::routes();
Route::get('/{any}', 'SinglePageController#index')->where('any', '.*');
Then in the singlePageController I return the view:
class SinglePageController extends Controller
{
public function index() {
return view('app', ['loggedUser' => auth()->user()]);
}
}
Then I have the api.php where I have the API routes. As you can see at the end I have the middleware to make it private. Just to make an example this is the one I use for updating the content:
Route::put('event/update/{slug}', 'EventController#update')->middleware('auth:api');
Then the related controller of that API route:
public function update(Request $request, $slug)
{
$event = Event::where('slug', $slug)->first();
$event->title = $request->input('title');
return new EventResource($event);
}
And in the end this is the Resource I use to define what and how the API data is going to be displayed:
public function toArray($request)
{
// return parent::toArray($request);
return [
'id' => $this->id,
'title' => $this->title,
'slug' => $this->slug,
'curator' => $this->curator,
'featured_image' => $this->featured_image,
'body' => $this->body,
'date' => $this->date
];
}
So this above is the flow I have. Then when I do an axios call to update the content, I'm doing something like:
axios({
method: 'PUT',
url: '/api/event/update/' + this.$route.params.slug + '?api_token=' + this.isLogged.apiToken,
data: dataToSave,
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
})
.then((response) => {
this.getNotification('Success: The Event has been saved');
})
.catch((error) => {
this.getNotification('Error: Impossible saving the event');
console.log(error);
})
Thanks in advance for the help
In Laravel routes in api.php ignore the session data.
If you want to authenticate with session data you could move your api routes to web.php and you should see the results you expect.

LARAVEL & VUE: How can I get the API_TOKEN of the logged in user with an API request?

I have a SPA using VUE and LARAVEL 5.8
I have setup an API_TOKEN associated to the logged in user. Everything works fine right after the login. I get the API_TOKEN, I save it into a var and I send it together with the Axios request. In Laravel I have a middleware that is taking care of the token and comparing it with the one setup on the logged in user.
the problem though occur when session expires. Because I still can navigate the private pages and make API requests to save and delete content. This is possible I think because I still have the same API_TOKEN saved in the var and the middleware apparently doesn't get that the session is expired.
So I want to obtain the API_TOKEN every time I'm doing an Ajax, request so when the session expires, I won't get the token and therefore, I won't be able to complete the request.
This is my setup.
web.php is where I have the only php route that points to a singlePageController:
Auth::routes();
Route::get('/{any}', 'SinglePageController#index')->where('any', '.*');
Then in the singlePageController I return the view:
class SinglePageController extends Controller
{
public function index() {
return view('app', ['loggedUser' => auth()->user()]);
}
}
Then I have the api.php where I have the API routes. As you can see at the end I have the middleware to make it private. Just to make an example this is the one I use for updating the content:
Route::put('event/update/{slug}', 'EventController#update')->middleware('auth:api');
Then the related controller of that API route:
public function update(Request $request, $slug)
{
$event = Event::where('slug', $slug)->first();
$event->title = $request->input('title');
return new EventResource($event);
}
And in the end this is the Resource I use to define what and how the API data is going to be displayed:
public function toArray($request)
{
// return parent::toArray($request);
return [
'id' => $this->id,
'title' => $this->title,
'slug' => $this->slug,
'curator' => $this->curator,
'featured_image' => $this->featured_image,
'body' => $this->body,
'date' => $this->date
];
}
So this above is the flow I have. Then when I do an axios call to update the content, I'm doing something like:
axios({
method: 'PUT',
url: '/api/event/update/' + this.$route.params.slug + '?api_token=' + this.isLogged.apiToken,
data: dataToSave,
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
})
.then((response) => {
this.getNotification('Success: The Event has been saved');
})
.catch((error) => {
this.getNotification('Error: Impossible saving the event');
console.log(error);
})
Do you know how to make it? or if there is a better way to accomplish that?
you and do like, your login method should like this.
public function login(Request $request)
{
if (Auth::attempt(['email' => $request['email'], 'password' => $request['password']])) {
$user = Auth::user();
$success = $user->createToken(config('app.name'))->accessToken;
return response()->json(["token" => $success, 'status' => 200]);
} else {
return response()->json(['message' => "Email or Password do not match"], 401);
}
}

How to access Role-based Controller and view using entrust

I'm new in laravel.I am using entrust Roles and permission which is working fine, but now I need to add every role like admin has his own controller and view. Superadmin should have his own controller and view.
Can anyone please help me?
How to access permission based controller and view using entrust.
This is how I tried:
Route::group(['middleware' => ['auth']], function() {
if(Entrust::hasRole('superadmin')) {
return View::make('superadmin');
}
else if(Entrust::hasRole('Admin')) {
return View::make('admin');
}
else {
Auth::logout();
return Redirect::to('/login')
->with('flash_notice', 'You don\'t have access!');
}
Route::get('/home', 'HomeController#index');
Route::resource('users','UserController');
Route::get('roles',['as'=>'roles.index','uses'=>'RoleController#index','middleware' => ['permission:role-list|role-create|role-edit|role-delete']]);
Route::get('roles/create',['as'=>'roles.create','uses'=>'RoleController#create','middleware' => ['permission:role-create']]);
Route::post('roles/create',['as'=>'roles.store','uses'=>'RoleController#store','middleware' => ['permission:role-create']]);
Route::get('roles/{id}',['as'=>'roles.show','uses'=>'RoleController#show']);
Route::get('roles/{id}/edit',['as'=>'roles.edit','uses'=>'RoleController#edit','middleware' => ['permission:role-edit']]);
Route::patch('roles/{id}',['as'=>'roles.update','uses'=>'RoleController#update','middleware' => ['permission:role-edit']]);
Route::delete('roles/{id}',['as'=>'roles.destroy','uses'=>'RoleController#destroy','middleware' => ['permission:role-delete']]);
you should use Entrust middlewares in your routes.php. add "superadmin" routes in "superadmin" middleware, "admin" routes in "admin" middleware, etc. and put the "else" case after all these.
Route::group(['middleware' => ['role:superadmin']], function() {
Route::get('/someroute', function(){
return View::make('superadmin');
});
});
Route::group(['middleware' => ['role:admin']], function() {
Route::get('/someroute', function(){
return View::make('admin');
});
});
Route::get('/someroute', function(){
Auth::logout();
return Redirect::to('/login')
->with('flash_notice', 'You don\'t have access!');
});

Route::match() not working in nested groups structure

I'm creating an API that is available only via POST. I'm planning to have more than one version of the API, so the current one uses v1 as part of the URL.
Now, in case an API call is made via GET, PUT or DELETE I would like to return a Fail response. For this I'm using Route::match(), which works perfectly fine in the code below:
Route::group(['namespace'=>'API', 'prefix' => 'api/v1', 'middleware' => 'api.v1'], function() {
Route::match(['get', 'put', 'delete'], '*', function () {
return Response::json(array(
'status' => 'Fail',
'message' => 'Wrong HTTP verb used for the API call. Please use POST.'
));
});
// User
Route::post('user/create', array('uses' => 'APIv1#createUser'));
Route::post('user/read', array('uses' => 'APIv1#readUser'));
// other calls
// University
Route::post('university/create', array('uses' => 'APIv1#createUniversity'));
Route::post('university/read', array('uses' => 'APIv1#readUniversity'));
// other calls...
});
However, I noticed that I could group the routes even more, to separate the API version and calls to specific entities, like user and university:
Route::group(['namespace'=>'API', 'prefix' => 'api'], function() {
Route::match(['get', 'put', 'delete'], '*', function () {
return Response::json(array(
'status' => 'Fail',
'message' => 'Wrong HTTP verb used for the API call. Please use POST.'
));
});
/**
* v.1
*/
Route::group(['prefix' => 'v1', 'middleware' => 'api.v1'], function() {
// User
Route::group(['prefix' => 'user'], function() {
Route::post('create', array('uses' => 'APIv1#createUser'));
Route::post('read', array('uses' => 'APIv1#readUser'));
});
// University
Route::group(['prefix' => 'university'], function() {
Route::post('create', array('uses' => 'APIv1#createUniversity'));
Route::post('read/synonym', array('uses' => 'APIv1#readUniversity'));
});
});
});
The Route::match() in the code above does not work. When I try to access any API call with e.g. GET, the matching is ignored and I get MethodNotAllowedHttpException.
Can I get the second routes structure to work with Route::match() again? I tried to put it literally everywhere in the groups already. Putting the Route::match() outside of the hole structure and setting path to 'api/v1/*' does dot work either.
If you use the post() function you don't need to deny manualy other verb.
What you can do is to create a listener for the MethodNotAllowedHttpException and display what you want. Or you can also use any() function at the end of your route's group to handle all route that is not defined.

Resources