I am using one laravel 5.7 authentication with custom check and session.
I have 5 type of user types
Session::put('user_type', $user_type);
Session::put('user_id', $user_id);
When I tried to check session data in constructor I am facing one issue,Please hele me to solve this,
ErrorException (E_NOTICE) Trying to get property 'headers' of
non-object
public function __construct()
{
$this->middleware(function ($request, $next) {
$utype=Session::get('user_type');
if($utype != 'ProjectAdmin'){
return redirect()->route('login');
}else{
$this->objShareContract = shareContract::getShareContract(TRUE);
}
});
}
Middleware must return a Response. You are not returning a Response from this custom Closure based middleware. You have 2 logical paths and only one of them is returning a Response of some sort.
There are other middleware before this one that are expecting a Response to come back through the pipeline. That is what the return $next($request); is about.
Related
I use Laravel 9, but it is updated version. I mean, the project was written in laravel 5.4 and updated it to 9 later.
Here's my routes
Route::group(['middleware' => 'locale', 'prefix' => '{locale?}'], function () {
Route::get('/signin', 'Front\UsersController#getSignin');
Route::post('/signin', 'Front\UsersController#postSignin');
});
Here's my tests
public function test_get_signin(){
$response = $this->get('/signin');
$response->assertStatus(302);
}
public function test_post_signin(){
$response = $this->post('am/signin');
$response->assertStatus(302);
}
It works well when I do $this->post('am/signin');
But it is not correct. By the idea it must work when I write $this->post('/signin') without manually adding what should be added automatically. But in fact I get status code 405.
UsersController method for post('/signin) route.
public function postSignin($lang, Request $request){
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if (Auth::validate(['email' => $request['email'],'password' => $request['password']])
|| Auth::validate(['username' => $request['email'],'password' => $request['password']])) {
$verify = User::where(['email'=> $request['email']])->first();
$verify = $verify?$verify:User::where(['username'=> $request['email']])->first();
if($verify->status =='blocked'){
if ($request->expectsJson()) {
return response()->json(array('verify'=> trans('email.profile-block')), 422);
}
}elseif(!$verify->verified){
return response()->json(array('verify'=> trans('validation.active_account').' '
.trans('car.click').' <a class="resend-link" href="/'.$lang.'/resendtoken/'.$verify->email_token
.'">'.trans('car.here1').'</a> '.trans('validation.resend_link')), 422);
}elseif($verify->status =='pending'){
return response()->json(array('verify'=> trans('car.company_napp')), 422);
}elseif($verify->status =='active'){
if(filter_var($request->email, FILTER_VALIDATE_EMAIL)){
$field = 'email';
}else{
$field = 'username';
}
if (Auth::attempt([$field => $request->email, 'password'=>$request->password],$request->remember)) {
UserLoginInfo::create(['user_id'=>Auth::id(),'ip_address'=> $request->ip(),
'info'=>json_encode(self::get_user_info())]);
if ($request->remember) {
User::where('id', Auth::id())->update(array('signed_in_for_remember_me' => Carbon::now()));
}
return Auth::user()->balance;
}
}
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
more short:
$this->get('/signin'); gives status code 302
$this->post('am/signin'); gives status code 302
$this->post('/signin'); gives status code 405
I tried
to use withoutMiddleware() - no positive result.
public function test_get_signin(){
$response = $this->withoutMiddleware('locale')->get('/signin');
$response->assertStatus(302);
}
public function test_post_signin(){
$response = $this->withoutMiddleware('locale')->post('/signin');
$response->assertStatus(302);
}
removed "?" symbol from 'prefix' => '{locale?}' in route group - no use.
commented the : Route::get('/signin', 'Front\UsersController#getSignin'); - no use again.
instead of withoutMiddleware('locale') I also used just a withoutMiddleware() - no use again.
IMPORTANT!
Both routes work well when testing with browser. I mean. User can enter his signin page and also successfully be signed in.
What's going on? How can I force post to work automatically with "/signin"? It's also weird, if I manually have to write "am/" then why it returns 302 instead of 200?
Update
I created a new project and tried to experiment there with route group and get, post methods.
Here's the routes
Route::group(['middleware' => 'locale', 'prefix' => '{locale?}'], function () {
Route::get('/test', function () {
return view('welcome');
});
Route::post('/test', function () {
return view('welcome');
});
});
here's the tests
public function test_1()
{
$response = $this->get('/test');
$response->assertStatus(200);
}
public function test_2()
{
$response = $this->post('/test');
$response->assertStatus(200);
}
test1 and test2, both of them return status 404
And when I use tests like this, I mean, adding a prefix manually
public function test_1()
{
$response = $this->get('/am/test');
$response->assertStatus(200);
}
public function test_2()
{
$response = $this->post('/am/test');
$response->assertStatus(200);
}
both of them return 200
This is good, very good. But why in my situation of my current project I get for get method 200 instead of 404 and for post 405 instead of 404, I don't have an idea. The interesting fact. I commented the whole exceptions Handler.php's code and no use. The get method everytime returns 200 when it must return 404.
Update 2
I've got some new interesting info from my experiments. If in my current project I want to test get method with uri "/signin" without '/am' part with $this->withoutMiddleware(); then I get 500, but without $this->withoutMiddleware(); I get 200
And to know what 500 want to say I used $response->dd(); and got this result
Spatie\LaravelIgnition\Exceptions\ViewException: Undefined variable
$errors in file
C:\xampp\htdocs\dashboard\test\hayvcar\storage\framework\views\7ced869fcb986989ef0f5838d6567d1b5fa4f895.php
on line 1
And if use $this->withoutExceptionHandling(); instead of $response->dd();
We'll get this result
Illuminate\View\ViewException : Undefined variable $errors (View: C:\xampp\htdocs\dashboard\test\hayvcar\resources\views\front\transport\index.blade.php)
C:\xampp\htdocs\dashboard\test\hayvcar\storage\framework\views\7ced869fcb986989ef0f5838d6567d1b5fa4f895.php:1
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\Engines\PhpEngine.php:60
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\Engines\CompilerEngine.php:61
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\View.php:139
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\View.php:122
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\View.php:91
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Http\Response.php:69
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Http\Response.php:35
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:833
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:802
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:725
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php:141
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php:116
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:726
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:703
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:667
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:656
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php:167
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php:141
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php:116
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php:142
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php:111
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\MakesHttpRequests.php:526
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\MakesHttpRequests.php:293
C:\xampp\htdocs\dashboard\test\hayvcar\tests\Feature\RoutesTesting.php:1718
Caused by
ErrorException: Undefined variable $errors
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Bootstrap\HandleExceptions.php:255
C:\xampp\htdocs\dashboard\test\hayvcar\storage\framework\views\7ced869fcb986989ef0f5838d6567d1b5fa4f895.php:1
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Filesystem\Filesystem.php:107
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Filesystem\Filesystem.php:108
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\Engines\PhpEngine.php:58
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\Engines\CompilerEngine.php:61
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\View.php:139
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\View.php:122
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\View\View.php:91
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Http\Response.php:69
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Http\Response.php:35
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:833
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:802
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:725
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php:141
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php:116
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:726
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:703
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:667
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Routing\Router.php:656
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php:167
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php:141
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php:116
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php:142
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php:111
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\MakesHttpRequests.php:526
C:\xampp\htdocs\dashboard\test\hayvcar\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\MakesHttpRequests.php:293
C:\xampp\htdocs\dashboard\test\hayvcar\tests\Feature\RoutesTesting.php:1718
Have you tried delete cached files?
Delete everything in bootstrap\cache and try again on host.
I've explained the whole situation here, for another question, which in this case, it doesn't matter if it's testing or using in browser, when you cache your routes, laravel look for the cached file, instead of defined routes in web.php and api.php.
So if in cached file, you've had route with am/signin then, doesn't matter if you change it to signin or not, in web.php/api.php, it always looking for cached file, which in this case is am/signin.
Temporary questions, answer them by question number :
So you've commented everything in postSignin method, and didn't worked or just a part of it?
You said in browser is working, method is getting $lang from route? because in tests, as far as i can see, you're not passing anything.
Have you tried to change post to patch just for test? (that's because of Patch verb)
You might also try withoutExceptionHandling(); to get more details on error and test output. are you posting full test or just a basic test?
You can add this line to top of your test, $this->withoutExceptionHandling(); and get more details.
Remove $lang from method or just try a new method like below:
public function postSignin(Request $request){
return something or return $this->sendFailedLoginResponse($request); or etc.
}
How did you upgraded your project to Laravel 9? Create a new Laravel project and only test these two routes, get and post.
Is there a way to provide in Laravel 5.5 what 4.2 had with:
Route::when('*-ajax', 'ajax');
I had an option to attach a filter to all ajax routes, and since then I know that filters have been replaced with middleware, but I am getting an error that:
Attribute [when] does not exist.
You can use Request::is(). Few details in the doc
It accept multiple params as well.
[edit] You also have Request::ajax() which returns true when you perform an ajax request
I found a solution in having implemented a global middleware for this:
public function handle($request, Closure $next)
{
$parsedUrl = parse_url($request->url());
if (key_exists('path', $parsedUrl) && strpos($parsedUrl['path'], '-ajax') !== false && !$request->ajax()) {
return response('Bad request', 400);
}
return $next($request);
}
I'm using Woocommerce webhooks to listen out for every time an order is created/updated/deleted.
I've setup the webhook in Woocommerce as follows
In my Laravel routes file I have set up the route as follows:
use Illuminate\Http\Request;
// API routes...
Route::post('api/v1/orders/create', function (Request $request) {
Log::debug($request->all());
return $request->all();
});
However, when I view the logs as well as the return data in POSTMAN, all I get is an empty array.
Any HTTP method other than 'GET' throws a MethodNotAllowedException
I'm not sure of any other way in Laravel to consume data other than with Request $request.
According to my understanding of routing in Laravel, the input that you pass in to the function is meant to actually be variables for your route.
So if you had a route in your API:
api/v1/orders/{id}/create then in the route function you'd pass in id as the method argument. So this would be correct:
Route::post('api/v1/orders/{id}/create', function ($id) {
Log::debug($id);
return $id;
});
It's looking for request in your route definition.
Rather create a controller. Then in your routes.php use this:
Route::post('api/v1/orders/create', 'OrdersController#create')
That tells your routing to redirect all HTTP POST calls to api/v1/orders/create to the OrdersController.php and the create() method within that controller.
In your controller, you'll be able to use the $request variable as an input argument and it should work.
So in OrdersController.php:
class OrdersController extends Controller {
public function create(Request $request) {
Log::debug($request->all());
return $request->all();
}
}
Good Luck!
This worked for me. My route in api.php is as follow.
Route::post('/woocommerce/webhook/', 'Api\WoocommerceController#test');
And my controller action is as follow.
public function test()
{
$payload = #file_get_contents('php://input');
$payload = json_decode( $payload, true);
\Log::info(json_encode( $payload));
return response()->json([ 'data' => $payload, 'status' => \Symfony\Component\HttpFoundation\Response::HTTP_OK]);
}
Laravel Version 5.2
In my project, users with role_id = 4 has the admin role and can manage users.
I have defined the following ability in AuthServiceProvider:
public function boot(GateContract $gate)
{
$this->registerPolicies($gate);
$gate->define('can-manage-users', function ($user)
{
return $user->role_id == 4;
});
}
I have used this ability in the UserController __construct method as follows:
public function __construct()
{
$this->authorize('can-manage-users');
}
In ExampleTest, I have created two tests to check if the defined authorization works.
The first test for admin user who has role_id = 4. This test passes.
public function testAdminCanManageUsers()
{
$user = Auth::loginUsingId(1);
$this->actingAs($user)
->visit('users')
->assertResponseOk();
}
The second test is for another user who does not have role_id = 4. I have tried with response status 401 and 403. But the test is failing:
public function testNonAdminCannotManageUsers()
{
$user = Auth::loginUsingId(4);
$this->actingAs($user)
->visit('users')
->assertResponseStatus(403);
}
First few lines of the failure message is given below:
A request to [http://localhost/users] failed. Received status code [403].
C:\wamp\www\laravel\blog\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\InteractsWithPages.php:196
C:\wamp\www\laravel\blog\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\InteractsWithPages.php:80
C:\wamp\www\laravel\blog\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\InteractsWithPages.php:61
C:\wamp\www\laravel\blog\tests\ExampleTest.php:33
Caused by exception 'Illuminate\Auth\Access\AuthorizationException'
with message 'This action is unauthorized.' in
C:\wamp\www\laravel\blog\vendor\laravel\framework\src\Illuminate\Auth\Access\HandlesAuthorization.php:28
I have also tried to use 'see' method as follows:
public function testNonAdminCannotManageUsers()
{
$user = Auth::loginUsingId(4);
$this->actingAs($user)
->visit('users')
->see('This action is unauthorized.');
}
But it's failing too. What am I doing wrong? How can I make the test pass?
The mistake is calling the visit method. The visit method is in the InteractsWithPages trait. This method calls the makeRequest method which in turn calls assertPageLoaded method. This method gets the status code returned and if it gets code other than 200, it catches a PHPUnitException and throws an HttpException with the message
"A request to [{$uri}] failed. Received status code [{$status}]."
This is why the test was failing with the above message.
The test can be successfully passed by using get method instead of visit method. For example:
public function testNonAdminCannotManageUsers()
{
$user = App\User::where('role_id', '<>', 4)->first();
$this->actingAs($user)
->get('users')
->assertResponseStatus(403);
}
This test will pass and confirm that a non admin user cannot access the url.
Since the Auth middleware redirects to a login route when unauthenticated by default you could also perform the following test:
public function testNonAdminCannotManageUsers()
{
$user = Auth::loginUsingId(4);
$this->actingAs($user)
->visit('users')
->assertRedirect('login');
}
Since at least Laravel 5.4, you'll want to use the assertStatus(403) method.
public function testNonAdminCannotManageUsers()
{
$user = Auth::loginUsingId(4);
$this->actingAs($user)
->visit('users')
->assertStatus(403);
}
I am using Laravel 5.1 and I am trying to test my controllers.
I have several roles for my users and policies defined for different actions. Firstly, each of the requests needs to be made by an authenticated user, so running a test with no user returns a 401 Unauthorized, as expected.
But when I want to test the functionality for authorized users, I still get the 401 Unauthorized status code.
It may be worth mentioning that I use basic stateless HTTP authentication on these controllers.
I have tried the following:
public function testViewAllUsersAsAdmin()
{
$user = UserRepositoryTest::createTestAdmin();
Auth::login($user);
$response = $this->call('GET', route('users.index'));
$this->assertEquals($response->getStatusCode(), Response::HTTP_OK);
}
and
public function testViewAllUsersAsAdmin()
{
$user = UserRepositoryTest::createTestAdmin();
$response = $this->actingAs($user)
->call('GET', route('users.index'));
$this->assertEquals($response->getStatusCode(), Response::HTTP_OK);
}
and also this (in case there was anything wrong with my new user, which there shouldn't be)
public function testViewAllUsersAsAdmin()
{
$user = User::find(1);
$response = $this->actingAs($user)
->call('GET', route('users.index'));
$this->assertEquals($response->getStatusCode(), Response::HTTP_OK);
}
but in every case I get a 401 response code so my tests fail.
I can access the routes fine using postman when logging in as a dummy user.
I am running out of ideas, so any help would be appreciated.
You need to add Session::start() in the setUp function or in the beginning of the function which user need to log in.
public function setUp()
{
parent::setUp();
Session::start();
}
or
public function testViewAllUsersAsAdmin()
{
Session::start();
$user = UserRepositoryTest::createTestAdmin();
Auth::login($user);
$response = $this->call('GET', route('users.index'));
$this->assertEquals(Response::HTTP_OK, $response->getStatusCode());
}
Through some experimentation, I found that the problem lay inside my authentication middleware. Since I want the API to be stateless, the authentication looks like this:
public function handle($request, Closure $next)
{
return Auth::onceBasic() ?: $next($request);
}
And apparently, it's not possible to authenticate a user the way I was doing it.
My solution was simply to disable the middleware, using the WithoutMiddleware trait or $this->withoutMiddleware() at the beginning of each test.