I am creating a small blog-esque site. This site has basically 3 permission levels: Admin (can edit/remove any post AND create a user), a user (can upload posts and pictures) and a guest (no account needed, can just browse the posts).
I am using Laravel 5.5 to create this site.
When someone logs in, after being authenticated, I store their username and user type (admin/user) in a session and after login, they are redirected to their respective pages, as shown in the below code.
I overrided the 'authenticated' method in the AuthenticatesUsers trait:
LoginController.php
protected function authenticated(Request $request, $user)
{
$type = $user->toArray()['type'];//get user type (admin/user)
$username = $user->toArray()['username'];
$request->session()->put('type', $type);
$request->session()->put('username', $username);
if ( $type == 'admin' ) {
return redirect()->route('admin_home');
}
return redirect()->route('user_home');
}
The above code works and my user is redirected upon successful login.
However, if my user accesses the site home (localhost:8000/) I want the user to see the admin home page or user home page (localhost:8000/ just shows the homepage for a not logged in guest)
I did that using the following codes:
Web.php
Route::get('/', 'ContentController#publicHome');
Route::middleware('auth')->group(function(){
Route::get('/user/home', 'ContentController#userHome')->name('user_home');
Route::get('/admin/home', 'ContentController#adminHome')->name('admin_home');
});
Filtering whether user is logged in or just a guest:
ContentController - publicHome function
public function publicHome(Request $request){
$data = [];
$data['home'] = 1;
if($request->session()->has('type')){
switch ($request->session()->pull('type')){
case 'admin':
return redirect()->route('admin_home');
case 'user':
return redirect()->route('user_home');
}
}
return view('public.home', $data);
}
ContentController - userHome function
public function userHome(Request $request){
$data = [];
$data['username'] = $this->getUsername($request);
$data['type'] = $this->getUserType($request);
// dd($data); explanation for this line below
return view('user.home', $data);
}
ContentController - adminHome function
public function adminHome(Request $request){
$data = [];
$data['username'] = $this->getUsername($request);
$data['type'] = $this->getUserType($request);
//dd($data);
return view('admin.home', $data);
}
ContentController - getUsername & getUserType functions
public function getUsername(Request $request){
return $request->session()->has('username') ? $request->session()->pull('username') : 'username not set';
}
public function getUserType(Request $request){
return $request->session()->has('type') ? $request->session()->pull('type') : 'user type not set';
}
I used the dump and die function to see the $data[] array before loading the view
Right after successful login:
array:2 [▼
"username" => "testAdmin"
"type" => "admin"
] //works correctly, session variables seem to be set
So when I type in localhost:8000/ I expect to be redirected to /admin/home (or /user/home depending on login) but I just get sent to localhost:8000/ as if I am not logged in. So now when I manually type in /admin/home I get the following dump and die output:
array:2 [▼
"username" => "username not set"
"type" => "user type not set"
]
If you are using $request->session()->pull('username') it fetches the data i.e. username from session and deletes it at the same time.
Instead, you can use laravel's helper method session() to get data without deleting it. So now you can use session('username') to get the username.
For more info refer : https://laravel.com/docs/5.5/session
Some Suggestions:
You could have used laravel's internal Auth library to build the login system which already has lot many features you don't need to code again. https://laravel.com/docs/5.5/authentication
You can also have multi-user authentication (admin & regular user). Refer this link if you want to implement so: https://scotch.io/tutorials/user-authorization-in-laravel-54-with-spatie-laravel-permission
Related
I have tried to used easyAdmin3 for making an admin account quickly, but how do you make a proper impersonate user action ?
I have tried a lot of things but the best option are made custom action so this link appear in page but it's don't works properly...
Impersonate works but on only page linked in url (impersonate has stopped if page change) and User don't change in Symfony Toolbar...
My custom Action :
public function configureActions(Actions $actions): Actions
{
$impersonate = Action::new('impersonate', 'Impersonate')
->linkToRoute('web_account_index', function (User $entity) {
return [
'id' => $entity->getId(),
'?_switch_user' => $entity->getEmail()
];
})
;
return parent::configureActions($actions)
->add(Crud::PAGE_INDEX, Action::DETAIL)
->add(Crud::PAGE_INDEX, $impersonate)
;
}
Result :
Dashboard link for each user
After click on impersonate, I have this url :
https://blog-community.wip/account/7?eaContext=37a8719&?_switch_user=user7#user.com
Content are ok (page account for user 7) but Symfony Profiler show User admin instead of impersonated User :
Symfony profiler user logged
Change page exit impersonate...
Real Symfony impersonate keep impersonation even if page changes because profiler user logged are different Symfony profiler user logged with impersonate directly in url
documentation not refer this functionality, EasyAdmin's Github issues too ans this website too.
Thanks for help
I am not a big fan of using hardcoded rules, so injected the UrlGenerator to my CrudController:
$impersonate = Action::new('impersonate', 'Impersonate')
->linkToUrl(function (User $user): string {
return $this->urlGenerator->generate(
Routes::DASHBOARD,
['_switch_user' => $user->getEmail()],
UrlGeneratorInterface::ABSOLUTE_URL
);
});
Solved !
EasyAdmin add automatically some parameters in url so "?" are already here but I added it too in my custom action...
Example :
https://blog-community.wip/account/7?eaContext=37a8719&?_switch_user=user7#user.com
public function configureActions(Actions $actions): Actions
{
$impersonate = Action::new('impersonate', 'Impersonate')
->linkToRoute('web_account_index', function (User $entity) {
return [
'id' => $entity->getId(),
'_switch_user' => $entity->getEmail()
// removed ? before _switch_user
];
})
;
return parent::configureActions($actions)
->add(Crud::PAGE_INDEX, Action::DETAIL)
->add(Crud::PAGE_INDEX, $impersonate)
;
}
For EasyAdmin 3.2.x the prior solution stopped working. This is working for me now:
public function configureActions(Actions $actions): Actions
{
$impersonate = Action::new('impersonate', false, 'fa fa-fw fa-user-lock')
//changed from linkToRoute to linkToUrl. note that linkToUrl has only one parameter.
//"admin/.. can be adjusted to another URL"
->linkToUrl(function (User $entity) {
return 'admin/?_switch_user='.$entity->getUsername();
})
;
$actions = parent::configureActions($actions);
$actions->add(Crud::PAGE_INDEX, $impersonate);
return $actions;
}
I have a login in laravel 5 and I need to register in a table the user information when entering the site (ip address, os, browser and timestamp) i have the code and my model to register this.
I have a middelware for this login but when use the function 'handle' this save a record when refresh the browser
Thanks
This is my code
public function handle($request, Closure $next)
{
if(!Auth::guard('web_admin')->check()){
return redirect('admin/login');
}
if(Auth::guard('web_admin')->user()->delete==='0' && Auth::guard('web_admin')->user()->status==='1'){
$browser_data = get_browser($_SERVER['HTTP_USER_AGENT'],true);
//dd($browser_data);
dd($request);
$model = new Access();
$model->ip = $request->ip();
$model->dir_mac = $this->mac() ;
$model->computer = gethostname()."/".$this->operating_system_detection();
$model->browser= $this->navegador();
$model->admin_id =Auth::guard('web_admin')->user()->id;
$model->save();
return $next($request);
}else{
Auth::guard('web_admin')->logout();
return redirect('admin/login');
}
}
When the user login information will be recorded. As a result, use a function after validation and before moving to the home page to receive and store this information. Because the user will try to log in once.
I have this on my pages controller.
protected $auth = array();
function __construct(){
parent::__construct();
$this->auth['result'] = $this->is_logged_in();
}
and this is my core/base controller located at core folder.
public function is_logged_in(){
$session = $this->session->userdata();
if(isset($session['logged_in'])){
return $session;
}else{ return FALSE; }
}
Is the above codes enough? or am i missing something to do a legitimate authentication?(my first time trying to attempt a user authentication)
Also, would it be okay, if for example.
I added a column 'isLoggedin' on my accounts table.
int(1),NULL.
and whenever my login function is called and someone successfully logs in, i will also add a value to insert as 'isLoggedin' to 1. 1=true, 2=false.
So for example in my pages controller, since everytime it loads, it runs the is_logged_in() function in my base controller and would return the session data from there.
I would compare the returned session data from my base controller to the one in my accounts table with the 'isLoggedin' col set to 1.
OR
since the $auth data would return an 'id' then i would check the 'id' from $auth to any 'id' on the database where 'isLoggedin == 1'. If it matches with the 'id' from $auth.
$this->db->get_where('accounts', array('id' => $auth['id'], 'isLoggedin' => 1));
I am trying to set up Socialite in Laravel for facebook logging. I got user logged in , but now I have a problem storing the details in the database.
Also I would like to know how to notice my app that User is logged in? For normal loggin I used native AuthController and everything goes smooth.
Now if user try to log in again, then Laravel automatically redirect it to the url without logging, with appended code like this ?code=AQBCM-KbFqB-VJepSJ-45nFURnsvPPdpdqOu...
So how can I logout the user completely and how can I store the details for the next logging??
This is what I am using but it is not working:
public function getSocialAuth($provider=null)
{
if(!config("services.$provider")) abort('404'); //just to handle providers that doesn't exist
return $this->socialite->with($provider)->redirect();
}
public function getSocialAuthCallback($provider=null)
{
if($user = $this->socialite->with($provider)->user()){
dd($user);
/* This is also not working:
$user1 = new User;
$user1->facebook_id = $user->getId();
$user1->email=$user->email();
$user1->fullname=$user->name();
$user1->provider="facebook";
$user1->save();*/
// not working:
User::create([
'facebook_id' => $user->getId(), 'email' => $user->email(),
'fullname' => $user->name()
]);
}else{
return 'something went wrong';
}
}
My first question: is it possible to test this on a localhost? (Because I can imagine that this could be my problem)
I read the docs and did everything like it is described. I browser to /auth/facebook and I get redirected to Facebook where I "accept" the terms. I get redirected to this link: http://localhost:8000/auth/login#_=_
So I tried to debug and did a dd($user); in my Authcontroller, but there was no output given.
public function redirectToProvider()
{
return Socialite::driver('facebook')->redirect();
}
public function handleProviderCallback()
{
$user = Socialite::driver('facebook')->user();
dd($user);
// $user->token;
}
Anyone an idea what I did wrong?
Need to see your routes configuration for more info, but will give it a shot with the info you provided.
Note that you are getting redirected to http://localhost:8000/auth/login#_=_.
That looks like you are getting redirected to your app's login page after authorizing on facebook.
In config/services.php, make sure that, for your facebook login configuration, your redirect url points to a route which you have defined in your routing configuration to handle the callback.
e.g.
// config/services.php
...
'facebook' => [
'client_id' => 'my_facebook_client_id',
'client_secret' => 'my_facebook_client_secret',
'redirect' => 'http://localhost:8000/auth/facebook/callback',
],
...
The route http://localhost:8000/auth/facebook/callback should then be defined in the routing configuration:
// app/Http/routes.php
...
Route::get('auth/facebook/callback', 'Auth\AuthController#handleProviderCallback');
...
Note that the routing config has to allow GET requests since the user will be redirected.
Your dd($user) should work just fine with this setup.
How you save the user data depends on your model architecture.
For instance, in a simple case where you have no other registration method and only use facebook login, you could do this:
public function handleProviderCallback()
{
$facebookData = Socialite::driver('facebook')->user();
// check if already in DB
try{
$user = User::where('facebook_id', $data->id)->firstOrFail();
} catch (Illuminate\Database\Eloquent\ModelNotFoundException $e) {
// create a new user
$user = new User();
// set the properties you want
// $user->facebook_id = $data->id;
// ...
// then save
$user->save();
}
// login the user
Auth::login($user);
// perhaps return a redirect response
return redirect()->action('MyController#myAction');
}