How to assert unauthenticated? - php

In my controller constructor I have middleware auth. How do I assert that somebody is not authenticated in tests? Right now I'm getting Illuminate\Auth\AuthenticationException and the only way to make test positive is to add
$this->expectException('Illuminate\Auth\AuthenticationException')
in the beginning. I saw solutions like using withoutExceptionHandling() in the beginning of test or using assertUnauthorized() but that doesn't change anything.
Is there a better way?
I'm using Laravel 7.2.2 and PHPUnit 8.5.

$this->get('/routeThatRequiresAuthentication');
$this->assertGuest();

/** #test */
public function unauthenticated_user_cannot_access_protected_routes()
{
$this->withoutExceptionHandling();
$this->expectException('Illuminate\Auth\AuthenticationException');
$this->getJson('/api/user'); //This route is protected with auth:api
}

Try $this->deleteJson('replies/' . $reply->id);. It will return json response instead of throwing an exception. You can then call ->assertStatus(401); on it

In Laravel, you can use the auth() helper method to get the currently authenticated user as below. If no authenticated user is found, it will return null. And this is what you can assert to check for unauthenticated.
$this->assertNull(auth()->user());
I believe this will also work:
$this->assertFalse(auth()->check());

Related

How do I remove or delete all user JWT token [duplicate]

I'm trying to invalidate (or remove) a token from JWT but I can't achieve that. First I did something like this answer says Logout issue with Laravel JWT-auth authentication:
JWTAuth::invalidate(JWTAuth::getToken())):
But I get this error:
Non-static method Tymon\JWTAuth\JWT::invalidate() should not be called statically, assuming $this from incompatible context
Then I did something like this:
use Illuminate\Http\Request;
use Tymon\JWTAuth\JWTAuth;
class AuthController extends Controller
{
protected $jwt;
public function __construct(JWTAuth $jwt)
{
$this->jwt = $jwt;
}
public function invalidateToken(Request $request)
{
$this->jwt->parseToken()->invalidate();
return response()->json(array('message' => 'log out'));
}
...
}
But I can still use the token for another request and I can't remove or invalidate it.
What am I doing wrong to invalidate the token?
Edit:
I read another questions from here and issues post from the repo of JWT on github (this is the library I'm using) and I followed all the examples to invalidate or remove the token and I can't still remove or invalidate it .
The blacklist feature works if cache_driver in your .env file is set to something other than array.
Changing it to file worked for me. However, in my particular case, I was using Entrust too, which causes issues when cache_driver is set to file or database. So, had to drop the blacklist/invalidate functionality.
Hope this helps someone.
This is how i think it should look like: $this->jwt->setToken($old_token)->invalidate(true);
JWTAuth::invalidate(old token);

Laravel REST API - infinite loop

I am building a REST user-microservice using Laravel 5.5 + Passport.
I am using the standard Passport::routes(), but I have had to modify the Auth::routes in order to make them return JSON responses, and to make them work with Passport.
I have added the following lines to my routes/web.php file:
Route::group(['middleware' => 'auth:api'], function () {
$this->post('logout', 'Auth\LoginController#logout')->name('logout');
});
This allows me to POST https://myapi/logout
If I make the call with the header "Authorization => Bearer TOKEN", I get a successful logout response.
If I provide no header at all, I get a "not authenticated" message (which is good)
However, if I provide the header with a revoked token, I get a recursive deadloop of the function: Illuminate\Auth\RequestGuard->user() (it keeps calling itself recursively until stack-overflow)
This is all done in the auth:api middleware, my logout code is not reached, but my LoginController constructor is called. Constructor code:
public function __construct(Application $app)
{
$this->apiConsumer = $app->make('apiconsumer');
$this->middleware('guest')
->except('logout');
}
I'm struggling to understand if it's my code causing this issue, or some combination of Laravel + passport + auth.
My first thought was that the auth:api middleware fails to authenticate the user, and as a result redirects the user to /home, where for some reason it's triggered again, recursively. But if that was the case, why would it work correctly with no header?
My current thinking is that the token in question does exist in the database, but Laravel is failing to figure out that it's revoked.
Any suggestions appreciated,
I found an answer (if not the answer) after a lot of research. It appears this is a Laravel bug (https://github.com/laravel/passport/issues/440). The solution is to add OAuthServerException to the $dontReport array in app/Exceptions/Handler.php:
class Handler extends ExceptionHandler
{
protected $dontReport = [
...
\League\OAuth2\Server\Exception\OAuthServerException::class,
];
}
This will avoid trying to log user information, thereby avoid the deadloop.
I have faced this in localhost. in my case, I have used xampp server and facing this issue
after creating a virtual host like "testlarave.test" then solve the error

Laravel 5.2 : Do something after user has logged in?

(I'm a beginner of Laravel)
I'm using Laravel 5.2. I have successfully enabled the Authentication; by doing the php artisan make:auth and stuffs.
So my login is working.
Now i need to do something once someone has logged in. For an simple example:
LOGIN:
Once a user has logged in, write a value into Session.
For example: $request->session()->put('UserAgent', $ClientUserAgent);
LOGOUT:
Same thing to do, once a user has logged out, delete the custom Session value.
For example: $request->session()->forget('UserAgent');
I'm not sure whether there are (things like) hooks or Event Listeners, Event Handlers, or something like that.
How can i do it please?
For newer versions of Laravel
If you are only doing something very simple then creating an event handler seems overkill to me. Laravel has an empty method included in the AuthenticatesUsers class for this purpose.
Just place the following method inside app\Http\Controllers\LoginController (overriding it):
protected function authenticated(Request $request, $user)
{
// stuff to do after user logs in
}
For the post login, you can do that by modifying App/Http/Controllers/Auth/AuthController.php
Add authenticated() into that class to override the default one:
use Illuminate\Http\Request;
protected function authenticated(Request $request, User $user) {
// put your thing in here
return redirect()->intended($this->redirectPath());
}
For the logout, add this function into the same class:
use Auth;
protected function getLogout()
{
Auth::logout();
// do something here
return redirect('/');
}
You could try setting up event listeners for the Auth events that are fired.
You can setup a listener that listens for Illuminate\Auth\Events\Login to handle what you need post login and Illuminate\Auth\Events\Logout for post logout.
Laravel Docs - Authentication - Events
Alief's Answer below works fine as expected. But as i googled through, using the Event Handlers is probably the more preferred way. (It works like custom hooks).
So without any less respects to Alief's Answer below, let me choose --> this Event Handers approach i just found out.
Thanks all with regards!
If you are testing, with authenticated(Request $request, User $user) method dont use alert inside this method to test, it will not show any result, so better put some insert query or something like that to test this method.
Why not simple check for
if(Auth::check()){
//your code
}
Make sure you include use Auth;

Laravel get url's route name [duplicate]

In Laravel, we can get route name from current URL via this:
Route::currentRouteName()
But, how can we get the route name from a specific given URL?
Thank you.
A very easy way to do it Laravel 5.2
app('router')->getRoutes()->match(app('request')->create('/qqq/posts/68/u1'))->getName()
It outputs my Route name like this slug.posts.show
Update: For method like POST, PUT or DELETE you can do like this
app('router')->getRoutes()->match(app('request')->create('/qqq/posts/68/u1', 'POST'))->getName()//reference https://github.com/symfony/http-foundation/blob/master/Request.php#L309
Also when you run app('router')->getRoutes()->match(app('request')->create('/qqq/posts/68/u1', 'POST')) this will return Illuminate\Routing\Route instance where you can call multiple useful public methods like getAction, getValidators etc. Check the source https://github.com/illuminate/routing/blob/master/Route.php for more details.
None of the solutions above worked for me.
This is the correct way to match a route with the URI:
$url = 'url-to-match/some-parameter';
$route = collect(\Route::getRoutes())->first(function($route) use($url){
return $route->matches(request()->create($url));
});
The other solutions perform bindings to the container and can screw up your routes...
I don't think this can be done with out-of-the-box Laravel. Also remember that not all routes in Laravel are named, so you probably want to retrieve the route object, not the route name.
One possible solution would be to extend the default \Iluminate\Routing\Router class and add a public method to your custom class that uses the protected Router::findRoute(Request $request) method.
A simplified example:
class MyRouter extends \Illuminate\Routing\Router {
public function resolveRouteFromUrl($url) {
return $this->findRoute(\Illuminate\Http\Request::create($url));
}
}
This should return the route that matches the URL you specified, but I haven't actually tested this.
Note that if you want this new custom router to replace the built-in one, you will likely have to also create a new ServiceProvider to register your new class into the IoC container instead of the default one.
You could adapt the ServiceProvider in the code below to your needs:
https://github.com/jasonlewis/enhanced-router
Otherwise if you just want to manually instantiate your custom router in your code as needed, you'd have to do something like:
$myRouter = new MyRouter(new \Illuminate\Events\Dispatcher());
$route = $myRouter->resolveRouteFromUrl('/your/url/here');
It can be done without extending the default \Iluminate\Routing\Router class.
Route::dispatchToRoute(Request::create('/your/url/here'));
$route = Route::currentRouteName();
If you call Route::currentRouteName() after dispatchToRoute call, it will return current route name of dispatched request.

Laravel get route name from given URL

In Laravel, we can get route name from current URL via this:
Route::currentRouteName()
But, how can we get the route name from a specific given URL?
Thank you.
A very easy way to do it Laravel 5.2
app('router')->getRoutes()->match(app('request')->create('/qqq/posts/68/u1'))->getName()
It outputs my Route name like this slug.posts.show
Update: For method like POST, PUT or DELETE you can do like this
app('router')->getRoutes()->match(app('request')->create('/qqq/posts/68/u1', 'POST'))->getName()//reference https://github.com/symfony/http-foundation/blob/master/Request.php#L309
Also when you run app('router')->getRoutes()->match(app('request')->create('/qqq/posts/68/u1', 'POST')) this will return Illuminate\Routing\Route instance where you can call multiple useful public methods like getAction, getValidators etc. Check the source https://github.com/illuminate/routing/blob/master/Route.php for more details.
None of the solutions above worked for me.
This is the correct way to match a route with the URI:
$url = 'url-to-match/some-parameter';
$route = collect(\Route::getRoutes())->first(function($route) use($url){
return $route->matches(request()->create($url));
});
The other solutions perform bindings to the container and can screw up your routes...
I don't think this can be done with out-of-the-box Laravel. Also remember that not all routes in Laravel are named, so you probably want to retrieve the route object, not the route name.
One possible solution would be to extend the default \Iluminate\Routing\Router class and add a public method to your custom class that uses the protected Router::findRoute(Request $request) method.
A simplified example:
class MyRouter extends \Illuminate\Routing\Router {
public function resolveRouteFromUrl($url) {
return $this->findRoute(\Illuminate\Http\Request::create($url));
}
}
This should return the route that matches the URL you specified, but I haven't actually tested this.
Note that if you want this new custom router to replace the built-in one, you will likely have to also create a new ServiceProvider to register your new class into the IoC container instead of the default one.
You could adapt the ServiceProvider in the code below to your needs:
https://github.com/jasonlewis/enhanced-router
Otherwise if you just want to manually instantiate your custom router in your code as needed, you'd have to do something like:
$myRouter = new MyRouter(new \Illuminate\Events\Dispatcher());
$route = $myRouter->resolveRouteFromUrl('/your/url/here');
It can be done without extending the default \Iluminate\Routing\Router class.
Route::dispatchToRoute(Request::create('/your/url/here'));
$route = Route::currentRouteName();
If you call Route::currentRouteName() after dispatchToRoute call, it will return current route name of dispatched request.

Categories