I have taken advice from people here and given Laravel a try, I have been trying to create a user authentication system. I am having trouble translating what I know works in PHP to Laravel using Eloquent.
What I am trying to do here is identify a user, their roles, if the user has a role of admin they can access the route /admin
I know I can use a package such as Entrust but that is not really helping me learn.
I have created Models for both User and Role. I also have a lookup table called role_user with a user_id and role_id.
In User.php I have
public function roles(){
return $this->belongsToMany('Role', 'users_roles');
}
In Role.php I have
public function users()
{
return $this->belongsToMany('User', 'users_roles');
}
I know if I used
$roles = user::find(1)->roles;
return ($roles);
It will and does return the correct user id (1) and the roles assigned to that user. Now what I am struggling with is how to pick out the admin role and only if the user has this will it allow access to /admin
The route should essentially be
Route::get('admin', function()
{
return View::make('admin.index');
})->before('auth');
What I can't figure how/where/should I check for the admin role first and how to then apply that to the auth check to only permit an admin access to the route.
Any help appreciated.
Lee
For Laravel 5, use Middleware:
Create new middleware
# php artisan make:middleware RoleMiddleware
Check the user role - redirect if invalid role
// app/Http/Middleware/RoleMiddleware.php
class RoleMiddleware
{
public function handle($request, Closure $next, $role)
{
if (! $request->user()->hasRole($role)) {
// Redirect...
}
return $next($request);
}
}
Add key in order to assign to routes - can also make global
// app/Http/Kernel.php
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'role' => \App\Http\Middleware\RoleMiddleware::class, // new
];
Protect the routes
// app/Http/routes.php
Route::put('post/{id}', ['middleware' => 'role:editor', function ($id) {
// routes for editor
}]);
You have used auth filter so you should check in the auth filter in app/filters.php file:
Route::filter('auth', function($route, $request)
{
// Login check (Default)
if (Auth::guest()) return Redirect::guest('login');
// Admin check
if(!in_array('admin', Auth::user()->roles->toArray())) {
return Redirect::to('/'); // Redirect home page
}
});
You may use a different filter, for example:
Route::get('admin', function()
{
return View::make('admin.index');
})->before('isAdmin');
Declare the custom isAdmin filter in app/filters.php:
Route::filter('isAdmin', function($route, $request)
{
if(!Auth::check()) return Redirect::guest('login');
if( !in_array('admin', Auth::user()->roles->toArray()) ) {
return Redirect::to('/'); // Redirect home page
}
});
Related
Description
I am trying to automatically route the user to the "Games.vue" component if they are already logged in. For authentication I am using Firebase and I check if they are logged in using:
var user = firebase.auth().currentUser;
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
What I want to have happen is for the user to not see the Login page if they are already signed in. So they are taken directly to the Games page. I don't know how to accomplish this using Vue. I need something to run before the Login-component that redirects if logged in.
Attempt at solution
The only way I know how to solve this is to show the Login page, check if the Firebase user is logged in and then go to the Games page. This can work, but it isn't the behavior I am looking for. I am using the Vue router. Thank you for your help.
I would suggest to use a VueRouter global guard like so:
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
if (!user) {
next('login');
} else {
next();
}
})
That being said, you then need a way to specify which route requires authentication. I would suggest to use route meta fields like so:
routes = [
{
name: 'login',
path: '/login',
meta: {
requiresAuth: false
}
},
{
name: 'games',
path: '/games',
meta: {
requiresAuth: true
}
}
]
Now your guards becomes:
if (!user && to.meta.requiresAuth) {
next('login');
} else {
next();
}
Vue router provides an example for this use case, take a look at the documentation.
TIP: Make sure to subscribe to auth changes using Firebase onAuthStateChanged method.
let user = firebase.auth().currentUser;
firebase.auth().onAuthStateChanged(function(user) {
user = user;
});
EDIT: To redirect once logged in, just watch for auth changes and redirect using router.push.
auth.onAuthStateChanged(newUserState => {
user = newUserState;
if (user) {
router.push("/games");
}
});
I have read in Loopback3 docs that getCurrentContext() has been deprecated. What I'd like to do is grab the access token and use that to find the associated user in the db, so I can get a company_id that the user belongs to and alter the query to include that in the where clause. I am using MySQL and a custom UserAccount model which extends from User.
I am new to Loopback so struggling to figure this out especially as most of the online help seems to point to getCurrentContext();.
I've set up some middleware to run on the parse phase:
middleware.json
"parse": {
"./modifyrequest": {
"enabled": true
}
}
modifyrequest.js
var loopback = require('loopback');
module.exports = function(app) {
return function tracker(req, res, next) {
console.log('Middleware triggered on %s', req.url);
console.log('-------------------------------------------------------------------');
console.log(req.accessToken);
}
};
However req.accessToken is always undefined. I have added to server.js:
app.use(loopback.token());
Any ideas? Is this the wrong approach ?
SOLUTION
As per Kamal's comment below...
Try setting "loopback#token": {} in middleware.json under "initial:before"
This populates req.accessToken
First, try setting "loopback#token": {} in middleware.json under "initial:before".
Then, if you are accessing accessToken from request object, you can find the userId within that accessToken object. Try to log req.accessToken, you will find the userId therein.
You can use that user id to search for corresponding user in the database.
User.findById(req.accessToken.userId, function(err, user){
if(err) {
//handle error
}
else {
//access user object here
}
});
I have a controller with a particular method to login:
public function login() {
if ($this->request->is('post')){
$user = $this->Auth->identify();
if ($user) {
$this->Auth->setUser($user);
return $this->redirect($this->Auth->redirectUrl());
}
// not logged
$this->Flash->error('Your username or password is incorrect');
}
}
and default route looks like
Router::scope('/', function (RouteBuilder $routes) {
$routes->fallbacks(DashedRoute::class);
});
after user is logged in CakePHP throws an error
Error: A route matching "/" could not be found.
None of the currently connected routes match the provided parameters.
Add a matching route to config/routes.php
when IMO it should to redirect to the page (based on a related controller) from where login method was executed.
Login code is based on that tutorial.
Any thoughts?
To solve this issue:
Please update the below lines in routes.php file
Router::defaultRouteClass('DashedRoute');
Router::scope('/', function (RouteBuilder $routes) {
$routes->connect('/', ['controller' => 'users', 'action' => 'index']);
$routes->fallbacks('DashedRoute');
});
Plugin::routes();
Please do create index() in users controller.
Let me know if any issue.
in my project I need to protect some views.
I create a router group:
Route::group(['middleware' => ['auth']], function (){
//Spot
Route::get('administrator/spot-new', 'SpotController#create');
Route::post('administrator/spot-new', 'SpotController#store');
}
in my Spot Controller:
public function __construct()
{
$this->middleware('auth');
}
but when I try to access to spot view I can't see the login page.
I have this error:
Sorry, the page you are looking for could not be found.
Laravel 5.2 have added Middleware Groups.
https://laravel.com/docs/5.2/middleware#middleware-groups
Web middleware group is responsible for Start Session / Encrypt Cookies / Verify CSRF Token etc.. see below
protected $middlewareGroups = [
'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,
],
You're required to add when working with sessions and any other stuff
in that group.
So to solve your problem add 'web' to your middleware
Route::group(['middleware' => ['web', 'auth']], function (){
Route::get('administrator/spot-new', 'SpotController#create');
Route::post('administrator/spot-new', 'SpotController#store');
}
And in your controller constructor
public function __construct()
{
//$this->middleware('auth'); (No need for this one)
}
I'm implementing a banning system. I have an admin view where the admin can ban users. I want to log out a user if the admin bans him in that moment. Something like Auth::logout($user). Is that possible?? Or do I have to add a filter to all my routes to check if the logged user is banned.
Filters are the way to go. It's easy and clean to solve this problem, see my example below.
if user is banned at any point it will logout user at his/her next request, you can redirect user with Session flash message, your login code works as it is.
Route::filter('auth', function()
{
if (Auth::guest())
{
if (Request::ajax())
{
return Response::make('Unauthorized', 401);
}
else
{
return Redirect::guest('login');
}
}
else
{
// If the user is banned, immediately log out.
if(Auth::check() && !Auth::user()->bannedFlag)
{
Auth::logout();
Session::flash('message','Your account is banned, please contact your administrator to active your account');
// redirect to login page
return Redirect::to('/');
}
}
});
and for your routes use group routes
Route::group(array('before' => 'auth'), function()
{
//use your routes
});