I'm new to laravel. I am trying to test that authentication works for my website and I want to test the authentication process in a test case. I create a in-memory sqlite database, I create a new User and use ->save() method of eloquent to store it in the database. I have setup an authentication filter which checks for the username in the database and depending on that it either allows the user to login or returns "invalid credentials"
// my UserTest.php file :
class UserTest extends TestCase {
public function testUsernameIsNotRequired()
{
// Create a new User
$user = new User;
$user->username = "phil#ipbrown.com";
$user->password = "123456";
//$user->password_confirmation = "password";
// User should save
$this->assertTrue($user->save());
// Save the errors
$password = $user->getAuthPassword();
// There should be 0 error
$this->assertEquals("123456",$password);
$this->seed();
$this->be($user);
$this->assertTrue(Redirect::route('authFilter'));
}
}
just to let you know that the in-memory db is lost once the test is complete as all the connections to it are lost so I want to check that the user that I saved to my db is properly inserted and second I want to check if I can login to my website using the information of this new user.
// my filters.php file :
Route::filter('auth', function()
{
if (Auth::guest()) return Redirect::guest('login');
});
Route::filter('auth.basic', function()
{
return Auth::basic('username');
});
Route::filter('guest', function()
{
if (Auth::check()) return Redirect::to('/');
});
Route::filter('csrf', function()
{
if (Session::token() != Input::get('_token'))
{
throw new Illuminate\Session\TokenMismatchException;
}
});
I was trying to attach a filter to a route so that I can redirect to the route during my test and which calls the auth.basic filter so I can test my filter, I know Im doing a lot of things wrong so please feel free to correct any mistakes that you come accross
my routes.php file :>
Route::get('/', function()
{
return View::make('hello');
});
Route::get('/authtest', array('as'=>'/authtest','before' => 'auth.basic', function()
{
return View::make('hello');
}));
Route::group(array('prefix' => 'api/v1', 'before' => 'auth.basic'), function()
{
Route::resource('url', 'UrlController');
});
Route::get('authFilter', array('as'=>'authFilter','before' => 'auth.basic', function()
{
return Auth::basic('username');
}));
I also have a uri controller which has all the pages for my website
this is what I followed to create my uri controller for the moment
I need a test case that creates a user stores it into the in-memory database and then authenticates using that users information. If any one knows laravel testing for filters please let me know I looked up the documentation for testing filters but I guess it is not well documented.
thank you
Filters are disabled in tests on Laravel 4.
You can use Route::enableFilters() in your test to force the filters on.
You can read up on the various discussions about why/why not to test filters;
https://github.com/laravel/framework/issues/344
https://github.com/laravel/framework/issues/766
http://forums.laravel.io/viewtopic.php?id=7404
https://github.com/laravel/framework/issues/682
You can keep most of this in the unit test.
public function testMyFilter() {
// Set up route with filter.
Route::get('testFilter', ['before' => 'myfilter', function()
{
return 'Hello World';
}]);
// Enable filters.
Route::enableFilters();
// Be a user.
$this->be($this->user);
// Make a request that will use the filter.
$response = $this->client->request('GET', 'testFilter');
// Check the response.
$this->assertResponseOk();
}
Related
I´m trying to return another route because in my case login it´s a modal page, and when the session has expired, return to this route but it does not exist. I don´t know how I would do this.
I can see this in web: if(Auth::check()){ return route('/')} but i don´t know where i´m putting this code.
Also i can see this: in 'App\Exception\Handler' put this:
if ($exception instanceof AuthenticationException) {
return redirect('/');
}
How I would can to do this?
Thanks for helping me
You can create a route to check sessions, every minute it will check session exists or not.
You can use like this:
Blade part:
#if (Auth::user())
<script>
$(function() {
setInterval(function checkSession() {
$.get('/is-logged-in', function(data) {
// if session was expired
if (!data.isLoggedIn) {
// redirect to login page
// or, may be better, just reload page
location.reload();
}
});
}, 60000); // You can change it
});
</script>
#endif
Route:
Route::get('is-logged-in', 'Auth\AuthController#checkSession');
Controller:
public function checkSession()
{
return Response::json(['isLoggedIn' => Auth::check()]);
}
Laravel probably already has what you need. Take a look at the App\Http\Middleware\Authenticate class. This is a middleware that will redirect user to 'login' named route (by default), if the session has expired.
By default none of the routes you put in routes/web.php are protected by this middleware, but you can change this.
Method 1: Add a auth middleware in your controller's constructor:
public function __construct()
{
$this->middleware('auth');
}
Method 2: Add a auth middleware for one of your routes:
Route::get('profile', function () {
// Only authenticated users may enter...
})->middleware('auth');
Method 3: Adding all protected routes into group:
Route::group(['middleware' => ['auth']], function () {
// All your protected routes go here
});
Then you can easily change the URL which will be used for redirecting users with expired session (not authenticated). Just edit the App\Http\Middleware\Authenticate::redirectTo() method and return your URL, for example:
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
return route('yourLoginRouteName');
}
}
I want to protect my routes with authorization levels in laravel - client users have access to one group while admin gets access to a separate group. However, the laravel API I'm creating runs concurrent to the existing legacy app which uses its own Users class, rather than the pre rolled eloquent Users model that all the docs use.
So far I haven't been able to determine how best to create this custom authorization middleware.
Basically I'd like to do something like this:
Route::group(['middleware' => 'custom_auth', function() {
Route::get('/' function() {
return "Hello World";
}
}];
//where 'custom_auth' points to something like
function isAdmin() {
if (Core\User->check_is_admin()) {
return true;
} else {
return false;
}
}
Kind of an open-ended question, I know, so any links to blogs/docs/videos would be appreciated. Thanks!
Solved:
I added custom middleware to App\Http\Middleware that copied the structure of the prebuilt Middleware\Authenticate.php file and uses the custom isAdmin() method.
Make sure to include in HTTP\Kernel.php
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth_admin' => \App\Http\Middleware\AuthenticateAdmin::class, // <- New Middleware
...]
Then in my Routes\admin_api
Route::group(['middleware' => 'auth_admin'], function () {
Route::get('/', function () {
return "Hello World";
});
This all works!
I've started learning Laravel 5.1 and so far I'm liking it! But there is one thing I don't get yet..
In my previous project I had 2 specific controllers (eg: "normal", "extended") which , after a successfull login, were called based on the Users user_group from the database.
If "Foo.Bar" enters his valid credentials and has the group normal he is redirected to NormalControler. Since I wasn't using any framework I restricted access to the other group by setting a $_SESSION with the group and checking it. So if another group tried to access that controller he got redirected.
How would this be achievable in Laravel 5? So far I have a controller which is callable without an Authentication and one restricted by this code in routes.php :
// All routes in the group are protected, only authed user are allowed to access them
Route::group(array('before' => 'auth'), function() {
// TO-DO : Seperate Controller access
});
And the login looks like this :
public function performLogin()
{
$logindata = array(
'username' => Input::get('user_name'),
'password' => Input::get('user_pass')
);
if( Auth::attempt( $logindata ) ){
// return \Redirect::to( check group and access this controller based on it);
}
else {
// TO-DO : Redirect back and show error message
dd('Login failed!');
}
}
----- EDIT -----
I've run the artisan command and made this middleware as you suggested :
namespace App\Http\Middleware;
use Closure;
use Request;
class GroupPermissions
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next, $group)
{
// Check User Group Permissions
if( $request->user()->group === $group ){
// Continue the request
return $next($request);
}
// Redirect
return redirect('restricted');
}
}
and edited this line into Kernel.php into $routeMiddleware :
'group.perm' => \App\Http\Middleware\GroupPermissions::class
I think this is done right so far, correct me if I'm wrong! Could I then do something like this to restrict the controllers?
Route::group(array('before' => 'auth'), function() {
Route::group( ['middleware' => 'group.perm', 'group' => 'normal'], function(){
Route::get('/normal/index', 'DummyNormalController#index');
});
Route::group( ['middleware' => 'group.perm', 'group' => 'extended'], function(){
Route::get('/extended/index', 'DummyExtendedController#index');
});
});
Ok, here is what you might do. Once user is logged in, you would check his credentials, get his user_group and decide what controller he should be redirected to.
if( Auth::attempt( $logindata ) ){
$user = Auth::user();
if ($user->inGroup('normal')) {
return redirect()->route('normal_controllers_named_route');
}
return redirect()->route('extended_controllers_named_route');
}
return redirect()->back()->withFlashMessage('don\'t get me wrong');
This will handle right routing after logging in.
The next portion where you need to protect you routes from unwanted user groups may be achieved with middlewares.
do an artisan command php artisan make:middleware ShouldBeInGroup
go to app/http/Kernel.php and add your new middleware to the routeMiddleware array. Key of the item might be anything you like. Let's call in inGroup. So: 'inGroup' => 'App\Http\Middleware\ShouldBeInGroup'
Now, in your controller, in constructor, you are able to call this middleware
$this->middleware('inGroup:extended'); //we also passing the name of the group
at lastly, work on the our middleware. Open newly created ShouldBeInGroup class and edit the handle method.
public function handle($request, Closure $next, $groupName)
{
if (Auth::check() && Auth::user()->inGroup($groupName)) {
return $next($request);
}
return redirect('/');
}
And finally you should work on inGroup method, that should return true of false. I assume that you have user_group field your users table. Then in your User eloquent model add the method
public function inGroup($groupName) {
return $this->user_group == $groupName;
}
Edit
if you want to use this middleware in your routes, you can do the following
Route::group(array('before' => 'auth'), function() {
Route::get('/normal/index', ['middleware' => 'group.perm:normal', 'uses' =>'DummyNormalController#index']);
}
But generally it's better to put all your middlewares into your Controller's constructor
public function __construct(){
$this->middleware('group.perm:normal'); // you can also pass in second argument to limit the methods this middleware is applied to : ['only' => ['store', 'update']];
}
And also on this note, Laravel provides built in auth middleware that you can use
public function __construct(){
$this->middleware('auth');
$this->middleware('group.perm:normal');
}
so then your routes would become much cleaner, just:
Route::get('normal/index', 'DummyNormalController#index');
I think the best way to do that is using middlewares. See the doc here
You can easily create a middleware using the following artisan command:
php artisan make:middleware ExtendedMiddleware
If you can't or don't want to use artisan, you need to create a class in The App/Http/Middleware folder.
In this class you'll need the following method to handle the request. In the method you can check for the user group.
public function handle($request, Closure $next)
{
// check user group
if( user_group_ok )
return $next($request); // Continue the request
return redirect('restricted'); // Redidrect
}
You can then use this middleware in your route.php file:
Route::group(['middleware' => 'auth'], function()
{
// Logged-in user with the extended group
Route::group(['middleware' => 'extended'], function()
{
// Restricted routes here
});
// Normal routes here
});
You can create a Middleware called : PermissionFilter
In PermissionFilter, you check if requesting user is in the group or not.
I can't provide a demo for now, but if you want I can make a demo later.
L5 middleware: http://laravel.com/docs/5.1/middleware
I am working on a Laravel project which is only intended to be used by backend admin staff. So, there is no separation of "standard user" and "admin user". So, I want to implement some sort of global auth filter on the entire project.
What I have so far is this on by app/routes.php
<?php
// Home route with login required
Route::get('/', array('as' => 'home', function () {
return View::make('hello');
}))->before('auth');
/*
* Global Auth Filter - All Guests Go To Login
*/
Route::filter('auth', function($route, $request) {
if (Auth::guest())
return Redirect::guest('login')
->with('login_error', 'Login required!');
});
/*
* Login Route Handler
*/
Route::get('login', array('as' => 'login', function () {
if (Auth::check())
return Redirect::route('home');
return View::make('login');
}))->before('guest');
/*
* Login Post Event Handler
*/
Route::post('login', function ()
{
// Parse form data
$user = array(
'username' => Input::get('username'),
'password' => Input::get('password')
);
// Try to login user
if (Auth::attempt($user))
{
// login success
return Redirect::route('home');
}
else
{
// Login error
return Redirect::route('login')
->withInput()
->with('login_error', 'Invalid username and/or password!');
}
});
/*
* Logout Route Handler
*/
Route::get('logout', array('as' => 'logout', function () {
Session::flush();
return Redirect::route('home');
}))->before('auth');
This works fine. If I got to the / page, it redirects me to /login route and from there I can login. Once logged in, I have a /logout link on the hello view and that also works (i.e. logging out).
This code above is my test code. In the real application I am working on (taking over the project from previous developer), the routes app/routes.php are setup like this:
<?php
Route::controller('dev', 'DevController');
Route::controller('orders', 'OrdersController');
Route::controller('customers', 'CustomersController');
Route::controller('picking', 'PickingController');
Route::controller('stock', 'StockController');
Route::controller('suppliers', 'SuppliersController');
Route::controller('warehouse', 'WarehouseController');
Route::controller('upload', 'UploadController');
Route::controller('apixero', 'XeroController');
Route::controller('api/orders', 'OrdersAPIController');
Route::controller('api/picking', 'PickingAPIController');
Route::controller('api/po', 'PurchaseOrdersAPIController');
Route::controller('api/products', 'ProductsAPIController');
Route::controller('api/customer', 'CustomerAPIController');
Route::controller('api/suppliers', 'SuppliersAPIController');
Route::controller('api/currency', 'CurrencyAPIController');
Route::controller('api/notes', 'NotesAPIController');
Route::get('/', function() {
return View::make('dashboard');
});
My question #1 is, how do I apply a "global" auth on requests with this app/routes.php? As the real application routes code seems to be different from what I have worked out in my test code..
Question #2 - Looking at my test code, can someone tell me at which point this filter gets executed:
Route::filter('auth', function($route, $request) { ... });
This code concept was taken out of a tutorial I was reading, but I noticed that my test code continues to work fine - even if I remove this code block. So, I am not entirely sure in which scenario the above code block is being executed.
Route filters are disabled when in the testing environment. To enable them, add Route::enableFilters() to your test.
To add a global auth filter - you could do this:
Route::get('/login')... //rest of code here
Route::get('logout')... //rest of code here
Route::group(array('before' => 'auth'), function()
{
Route::controller('dev', 'DevController');
Route::controller('orders', 'OrdersController');
...
Route::controller('api/notes', 'NotesAPIController');
Route::get('/', function() {
return View::make('dashboard');
});
});
Please tell me how to restrict the page using laravel,
i have 3 users.
1. admin, 2. client, 3. partner
i want if admin is logged in then open only- admin.index page
and if client logged in then open only- client.index page
i used in route.php following code-
Route::group(array('before' => 'role'), function(){
Route::resource('admin','AdminController#index');
Route::resource('client','clientController#index');
Route::resource('partner','partnerController#index');
});
using above code this if no any user login then it's coming properly,
and suppose if admin logged in, then page redirect to AdminController but,
if i hard coded (url) hit clientController or partnerController like http://localhost/laravel-login/public/client then client page is coming.
so please tell me how to avoid these
sorry for my english..
thanks
You may use different route filters for each route and create individual filters, for example:
Route::group(array('before' => 'auth'), function() {
Route::resource('admin','AdminController#index');
Route::resource('client','clientController#index');
Route::resource('partner','partnerController#index');
});
In each controller create a __construct method and add filter like:
public function __construct()
{
// In your AdminController
$this->beforeFilter(function() {
if(Auth::user()->role->name != 'admin') return redirect::to('/'); // home
});
}
Same way declare other filters in other controllers:
public function __construct()
{
// In your clientController
$this->beforeFilter(function() {
if(Auth::user()->role->name != 'client') return redirect::to('/'); // home
});
}
And so on. Check more on Laravel website about controller filtering.
The best way to restrict controllers to make new middleware , where you can define rules before the request. example :
I have a admin controller only register users with admin role can access it .
to do so when you define the route include the middleware .
// namespace = indicate where my controller is (sub folder )
// middleware = indicate what restriction i want for my controller you can pass one middleware or array of midlewares
Route::group([ 'namespace' => 'Admin','middleware' => ['auth' , 'IsAdmin'] ], function()
{
Route::resource('admin/posts', 'PostsController');
});
to create the middle ware and register it follow the documentation
look this is my middleware after
<?php
namespace App\Http\Middleware;
use Closure;
class IsAdmin
{
public function handle($request, Closure $next)
{
if($request->user()->is_admin == false ){
return redirect('/');
}
return $next($request);
}
}