Im trying to log in a system user without sessions or cookies.
The following code in my middelware works unless the user id is from a system user:
$interface_token = $request->header('token');
if ($interface_token !== 'my_secret') {
return response('Unauthorized', 401);
}
$user_id = 1; // Just for testing. Here I want to login a system user.
$success = Auth::onceUsingId($user_id);
if (!$success)
{
throw new Exception('failed!');
}
I want to log in a system user since this specific routes are going to be call from an internal service not from a "real" user.
If I update the table users setting system_user = 0 of user id 1, it works.
If system_user = 1 then it doesn't authenticate.
This system_user column is just a tinyint added to the user's table that shouldn't affect but apparently it does.
The user model is using the SystemUserTrait.
Any ideas?
I'm using Laravel 5.4
Edit
The SystemUserTrait is adding a global scope which does the following:
public function apply(Builder $builder, Model $model)
{
$builder->where('system_user', '=', 0);
}
So that's why it was not working with the user system. But now the question is if is possible to disable this to authenticate the user.
I tried the following without success:
$user = User::withoutGlobalScope(SystemUser::class)->find(1);
$success = Auth::login($user);
The user is fetched but the login fails anyway.
Is there a way to avoid using the global scope for a function?
The solution was to fetch the user with User::withoutGlobalScope and then to use Auth::setUser function to avoid queries which used the scope.
$interface_token = $request->header('token');
if ($interface_token !== 'my_secret') {
return response('Unauthorized', 401);
}
$user = User::withoutGlobalScope(SystemUser::class)->find(1);
Auth::setUser($user);
Related
I wanted to do custom redirect logic upon logging in to my site. So I wrote this code
public function login()
{
$user = //what do I put here?
$this->guard()->login($user);
$id = Auth::id();
//dd($id);
$rfid = DB::table('users')->where('id', $id)->value('reference_id');
if ($rfid == null){
dd($id);
return redirect()->action('RedirectController#client');
}
else {
//dd($rfid);
return redirect()->action('RedirectController#employee');
}
}
However my problem is that all it does is redirect. Which makes sense. The code I have there only manages the redirect, there is nothing there to actually log anyone in. So I did some researching and found
$this->guard()->login($user);
As a way to log the user in. However I don't know what to define the variable $user as. I know this should work because I use it in a different place on my site, but it the $user variable that I use there wouldn't work here. So under the scenario of simply login in the user, what do put there in order to authorize the user as in our database, and then log them in?
If you look at Laravel 5.3 AuthenticatesUsers traits , you will understand how login works behind the scene.
you need to change your login method to use attempt instead of login as follows to work it accordingly.
public function login(Request $request)
{
$user = //what do I put here?
$this->guard()->attempt($this->credentials($request), $request->has('remember'));
$id = Auth::id();
//dd($id);
$rfid = DB::table('users')->where('id', $id)->value('reference_id');
if ($rfid == null){
dd($id);
return redirect()->action('RedirectController#client');
}
else {
//dd($rfid);
return redirect()->action('RedirectController#employee');
}}
I recommend you to use it as I mentioned. If you still want to get $user value you can try out
$user = $this->guard()->user();
Though I haven't used it like that.
I have created a log in form for my admin pages and it works, but for now everyone who logs in can access those pages.
My users are also belong to usergroups and my users table in the database has a group_id column. The admin group has an id of 1.
What I'd like to do is that if someone who belongs to the admin group logs in can access the admin pages, but if the user belongs to a different group and tries to log in be redirected to main page or anywhere.
What I'm trying to do is add a similar code to the admin pages controllers
class Dashboard extends MY_Controller {
public function __construct() {
parent::__construct();
// Access control
if(!$this->session->userdata('logged_in')) {
redirect('admin/login');
}
}
}
My model
class Authenticate_model extends CI_Model {
public function login_user($username, $password){
//Secure password
$enc_password = md5($password);
//Validate
$this->db->where('username',$username);
$this->db->where('password',$enc_password);
$result = $this->db->get('users');
if($result->num_rows() == 1){
return $result->row();
} else {
return false;
}
}
}
You can do it yourself, provide validation and set $SESSION variable to retrieve if the user is logged in. But this is too much work, and error prone.
I recommend you to use this popular library: https://github.com/benedmunds/CodeIgniter-Ion-Auth. It is really easy to set up, you just need to copy some files and you are ready to go.
If you really want to do it your self(thats the question) then you need to store in SESSION two variables - logged_in and is_admin.
I would recomend two create library with function:
function is_logged_in($admin = FALSE){
$is_logged = $this->session->userdata('logged_in');
if($admin){
$is_logged = $this->session->userdata('is_admin')
}
return $is_logged;
}
This assumes that you store two booleans "logged_in" and "is_admin" in SESSION.(If user has group_id = 1 then you would store TRUE in is_admin)
Then you can protect your site members only pages
if(!$this->your_authenticatation_library->is_logged_in()){redirect('notMembersControler')}
and admin page:
if(!$this->your_authenticatation_library->is_logged_in(TRUE)){redirect('notMembersControler')}
Thats the basic idea, you need to work around depending on what you are up to. Hope this helps!
I'm new in laravel
I coded a script that many users may work with
but the problem that I have is this :
when a user like "Helen" signs in she can see her profile
but if next another user like "Maria" logs on , Marias panel will be shown for both of them
I think it means just one session can be active at the same time and the value of session will be for the latest user
and the older users session doesn't expire just the value in the session will be changed , thus she identifies as another user and can see that users profile, and also when a user logs out , because of close of the session , all users will be signed out.
here is my simple code :
public function Login(){
$this->Token();
$pack=Input::all();
try {
$result=DB::table('user')->where('Email','=',$pack['email'])->get();
if (Hash::check($pack['password'], $result[0]->Password)){
session(['there' => $result['0']->Email]);
return redirect('dashboard');
}
return redirect('dashboard')->with('does','wrong password');
}catch(Exception $e){
return redirect('dashboard')->with('does',.$e);
}
}
public function UserType() {
if(!session('there'))
return "Not Logged";
else {
$result = DB::table('user')->where('Email', '=', session('there'))->get();
if($result!=null)
return "User";
}
public function ShowDashboard(){
if($this->UserType()=="Not Logged")
else
return view('pages/dashboard');
}
I am not sure why you are session() to manage user logins... Also, they depend a lot on situations where users are login from the same computer, same browser... cookies... etc etc... and maybe that's why you might be getting 2 different session values at the same time...
In any case.. please try and prefer using Laravel's predefined functions of Auth to handle your login/logout procedures.
public function Login()
{
// What does this do? Check for a CSRF token? If yes, then
// please understand then Laravel automatically checks
// for the CSRF token on POST/PUT requests and therefore
// there is no special need to use the below function...
$this->Token();
$pack = request()->only(['email', 'password']);
// I don't really feel try catch is required here... but completely your choice...
try {
if(auth()->attempt($pack)) {
return redirect('dashboard')
}
return redirect->back()->with('does', 'wrong password');
} catch(Exception $e) {
return redirect->back()->with('does', $e);
}
}
public function ShowDashboard()
{
// You can remove this if/else by adding the 'auth' middleware
// to this route
if(!auth()->check())
return view('pages.dashboard');
else
return redirect(route('login'));
}
I found a lot of problems in your above code...
Please use camelCase for naming functions... (I haven't changed the naming in my code above because I don't really know what rules you are following at your workplace or idk...)
Please don't return strings for a simple true/false situation.
Please try and use Models whenever possible. The raw DB commands are required for very complex and extensive queries
I am currently developing a website using Laravel.
A user belongs to 1 and only 1 group.
How do I restrict the route
Route::('/view/profile/{id}', 'ProfileController#showProfile');
to be only accessible by other users belonging to the same group. I would also like to allow the admin to access this route. However the admin does not belong to any group.
I know there are two ways to solve your problem.
You can create a custom middleware and bind it to your route.
Or you can do a simple check in your controller method.
I will give an example of the second method since it is the easiest.
Example:
// YourController.php
public function yourMethod()
{
// Get the user from authentication
$user = Auth::user();
// Check user and redirect to login when NULL
// This also can be done with auth middleware (check link in method 1)
if (!$user) return Response::redirect('yourLoginRoute');
// Check if has not group throw forbidden
if ($user->group->id != theGroupId) return App::abort(403);
}
Edit after comment #PaulLucero
So if I understand correctly only users of the same group can visit eachothers profile page (view/profile/{id}). Also you want to use a middleware to solve this problem but are unable to retrieve the route parameter {id}.
You can retrieve a parameter in Laravel 4 outside a route by using Route::input('yourParameter'). Check this and scroll down to Accessing A Route Parameter Value.
Example:
class YourMiddleware
{
public function handle($request, Closure $next)
{
// Get id from route and get user model
$user_id = Route::input('id');
$user = User::find($user_id);
// Do some checks
....
// Get user from auth
$auth_user = Auth::user();
// Do some checks
....
// If groups don't match throw 403
if ($user->group_id != $auth_user->group_id) return App::abort(403);
return $next($request);
}
}
I think this should do the trick.
create a custom middleware try like this
public function yourMethod()
{
$user = Auth::user();
if ($user->group_id == 1) {
return Response::redirect('yourRouteToGroupID-1');
else if(if ($user->group_id == 2) {)
return Response::redirect('yourRouteToGroupID-2');
else{
return App::abort(403);
}
}
How can I get a security token for any user, not only the one currently logged in ?
I would like to be able to call isGranted() on a user fetched from the database
isGranted() comes from the Security service, so it would be hard/unnecessary to use that to get Roles without adjusting the state of the session.
Don't get me wrong, it's definitely possible... This would work, for example:
public function strangeAction()
{
// Get your User, however you normally get it
$user = $userRepository->find($id);
// Save the current token so you can put it back later
$previousToken = $this->get("security.context")->getToken();
// Create a new token
$token = new UsernamePasswordToken($user, null, "main", $user->getRoles());
// Update the security context with the new token
$this->get("security.context")->setToken($token);
// Now you have access to isGranted()
if ($this->get("security.context")->isGranted("ROLE_SOMETHING"))
{ /* Do something here */ }
// Don't forget to reset the token!
$this->get("security.context")->setToken($previousToken);
}
...but that really makes no sense.
In reality, you don't need the token. A much better way of doing this would be to add an isGranted() method into your User entity:
// Namespace\YourBundle\Entity\User.php
class User
{
...
public function isGranted($role)
{
return in_array($role, $this->getRoles());
}
...
}
Now you can get those roles in your controllers:
public function notSoStrangeAction()
{
// Get your User, however you normally get it
$user = $userRepository->find($id);
// Find out if that User has a Role associated to it
if ($user->isGranted("ROLE_SOMETHING"))
{ /* Do something here */ }
}
I had the same requirements a while ago. So I implemented it myself. Since you require the hierarchy information from the container it is not possible advised to extend the user entity with this functionality though.
// first check if the role is inside the user roles of the user
// if not then check for each user role if it is a master role of the check role
public function isGranted($user, $checkrole){
$userroles = $user->getRoles();
if (in_array($checkrole, $userroles)){return true;}
foreach ($userroles as $userrole){
if ($this->roleOwnsRole($userrole, $checkrole)){return true;}
}
return false;
}
// recursively loop over the subroles of the master to check if any of them are
// the suggested slave role. If yes then the masterrole is a master and has
// the same grants as the slave.
private function roleOwnsRole($masterRole, $slaveRole, $checkvalidityroles=true, $hierarchy=null)
{
if ($hierarchy===null){$hierarchy = $this->container->getParameter('security.role_hierarchy.roles');}
if ($masterRole === $slaveRole){ return false; }
if($checkvalidityroles && (!array_key_exists($masterRole, $hierarchy) || !array_key_exists($slaveRole, $hierarchy))){ return false; }
$masterroles = $hierarchy[$masterRole];
if(in_array($slaveRole, $masterroles)){
return true;
}else{
foreach($masterroles as $masterrolerec){
if ($this->roleOwnsRole($masterrolerec, $slaveRole, false, $hierarchy)){return true;}
}
return false;
}
}
I think the best way is to call AccessDecisionManager manually - like $securityContext->isGranted() does as well but for the currently logged in user. This is good too if you are using Symfony Voters to determine access.
$token = new UsernamePasswordToken($userObject, 'none', 'main', $userObject->getRoles());
$hasAccess = $this->get('security.access.decision_manager')->decide($token, array('voter'), $optionalObjectToCheckAccessTo);