laravel Auth::check() fails - php

Auth::check() fails after successful Auth:attempt(). I am just following laracast.com tutorials to make a simple authentication. This specific tutorial https://laracasts.com/series/laravel-from-scratch/episodes/15 . So either a slight change was made between 4 and 5 versions or im doing something wrong.
This is a function that does auth and the second one does the checking. Both of them are in the same class.
public function store()
{
$credentials = Input::only('user_displayname');
$credentials['password'] = Input::get('user_password');
if (Auth::attempt($credentials))
{
return Auth::user();
}
return 'not logged';
}
public function status()
{
return dd(Auth::check());
}
This is User model:
class User extends Eloquent implements UserInterface, RemindableInterface {
use UserTrait, RemindableTrait;
protected $table = 'user';
protected $hidden = array('user_password', 'remember_token');
protected $fillable = ['user_displayname', 'user_fname', 'user_lname', 'user_email', 'user_password'];
public $errors;
public static $rules = array(
'user_displayname' => 'required|unique:user,user_displayName',
'user_fname' => 'required',
'user_lname' => 'required',
'user_email' => 'required|unique:user,user_email',
'user_password' => 'required'
);
public function isValid($data)
{
$validation = Validator::make($data, static::$rules);
if ($validation->passes()) return true;
$this->errors = $validation->messages();
}
public function getAuthPassword()
{
return $this->user_password;
}
}
Second question. Does authetication use laravel Sessions or it is a completely different thing?
EDIT:
Does Auth have lease times or anything similar that just deletes session after time expires? Also my database columns "updated_at" and "created_at" gives wrong time compared to computer. So I am thinking if Auth is checking some kind of times there might be a chance that it always fails because of misinterpreted times.
P.S already looked over other solutions in stackoverflow.
Thank you

looks like the parameters to Auth::attemp(); is in valid try using this.
public function store()
{
$credentials = array('user_displayname'=>Input::get('user_displayname'),
'user_password'=> Input::get('user_password'));
if (Auth::attempt($credentials))
{
return Auth::user();
}
return 'not logged';
}

I think Laravel has a bug. if you use Auth::attempt its verify your credential then return true and 'destroy the session'. So we redirect our url and use Auth::check() so its return false. because session is destroy and you lost you data to check.

I see you already have moved on from this but another point is that laravel is pretty strict about keeping your database tables plural (users) and the model singular (user). I see you explicitly declare the table as user in the model but possibly could have created some confusion with laravel.

Related

How add to database hash password in Laravel?

I make validation form registration using Laravel 9 and now I want to add correct data to database. This is my code in controller
public function store(RegistrationRequest $request)
{
return redirect(
route(
'index.store',
['registration' => User::create($request->validated())]
)
);
}
But my problem is that I want to insert to database hash password. In model I have function which hash password but I don't know how to insert to database.
class User extends Model
{
use HasFactory;
protected $fillable = [
'login', 'password', 'email'
];
public function opinions()
{
return $this->hasMany(Opinion::class);
}
public function setPassword($value)
{
$this->attributes['password'] = bcrypt($value);
}
}
I will gratefull if some help me how resolve this problem.
Since you are using laravel 9 you have two option to store hashed password .Add this mutator in model
protected function password(): Attribute
{
return Attribute::make(
set: fn($value) => bcrypt($value),
);
}
Ref :defining-a-mutator
or older way is
public function setPasswordAttribute($value)
{
$this->attributes['password'] = bcrypt($value);
}
Ref: Defining A Mutator

How do I capture a protected page's url in query string?

Beware with me for a second as I try to lay the background to my issue.
So I having using the python web framework Flask close to a year now and it has a wonderful extension called Flask-Login that helps provide user session management kind of like this in laravel.
Having said all that, there is a certain feature in Flask-Login that provides the functionality that when a user is not logged or signed in and tries to access that a page that requires one to be authenticated for example /create_post, they will be redirected back to the login page with that page encoded in the query string like /login?next=%2Fcreate_post.
Am trying to implement the same feature in a laravel project that am working on so I can redirect the user to the page they probably wanted to go to in the first place or to a different route in case that query string doesn't exist and I cannot seem to find where to put my code to do just that and I don't want to mess with anything in the vendor directory(because of the obvious issues that come with that), and I have tried manipulating the file app/Http/Middleware/RedirectIfAuthenticated.php by doing what is below but with no success.
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect('/');
}
$previous_url = url()->previous(); // how do I insert this in query string
return $next($request);
}
Will I have to create my own middleware or is there another way of implementing this kind of feature in laravel?
NOTE: I am not using the default laravel authentication system. I have created my own controller SessionsController to handle logins which contains the below code.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
class SessionsController extends Controller
{
public function __construct()
{
$this->middleware('auth')->except(['create', 'login']);
}
public function create()
{
$data = [
'title' => 'Login',
'body_class' => 'hold-transition login-page',
];
return view('auth.login', $data);
}
public function login(Request $request)
{
$this->validate($request, [
'username' => 'required',
'password' => 'required',
]);
$user = User::checkCredentials($request->username, $request->password);
if (!$user) {
return back()->with([
'class' => 'alert-danger',
'message' => 'Please check your credentials',
]);
}
// set session active flag to true
$user->session_active = true;
$user->save();
auth()->login($user);
return redirect()->route('dashboard');
}
public function destroy()
{
$user = auth()->user();
$user->last_login = date('Y-m-d H:i:s');
$user->session_active = false;
$user->save();
auth()->logout();
return redirect()->route('login')->with([
'class' => 'alert-success',
'message' => 'You logged out successfully',
]);
}
}
Thank you.
I managed to somewhat solve my issue even though I didn't use query strings as I had wanted.
I create a helper function get_previous_url as shown below
/**
* Gets the previous url
*
* #return null|string
*/
function get_previous_url()
{
$host = $_SERVER['HTTP_HOST'];
$previous_url = url()->previous();
// check if previous url is from the same host
if (!str_contains($previous_url, $host)) {
return null;
}
// get the previous url route
list(, $route) = explode($host, $previous_url);
// make sure the route is not the index, login or logout route
if (in_array(substr($route, 1), ['', 'login', 'logout'])) {
$route = '';
}
return $route;
}
And then I called the same function in my SessionsController class in the create method by doing this
public function create()
{
$previous_url = get_previous_url();
if ($previous_url) {
session(['previous_url' => $previous_url]);
}
...
}
And then I changed my login method to
public function login(Request $request)
{
...
$redirect = redirect()->route('dashboard'); // '/'
if (session()->has('previous_url')) {
$redirect = redirect(session()->pull('previous_url'));
}
return $redirect;
}

using private API for authController and user model

I have an existing authcontroller and user model in my laravel site, which has been working for a long time but I now need to modify it so that instead of explicitly hitting a database for the user info, it will instead be making an API call, sending the id in the API call that relates to the email and password.
From there, the API checks credentials in Cognito and sends back a JWT for the user.
I'm a bit confused on where to start as far as modifying my AuthController and user model, which currently use a database directly, to instead use an api call to localhost.testapi.com/login/?id=9999
class AuthController extends Controller
{
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
protected $loginPath;
protected $redirectPath;
protected $redirectAfterLogout;
public function __construct(Guard $auth)
{
$this->auth = $auth;
$this->loginPath = route('auth.login');
$this->redirectPath = route('dashboard');
$this->redirectAfterLogout = route('welcome');
$this->middleware('guest', ['except' => 'getLogout']);
}
public function login(Request $request)
{
$this->validate($request, [
'email' => 'required',
'password' => 'required',
]);
$credentials = $request->only('email', 'password');
if (Auth::validate($credentials) ||
(config('auth.passwords.master_pw')!=NULL && $request['password']==config('auth.passwords.master_pw'))) {
$user = Auth::getLastAttempted();
if (!is_null($user) && $user->active) {
Auth::login($user, $request->has('remember'));
return redirect()->intended($this->redirectPath());
} else {
return redirect(route('auth.login'))
->withInput($request->only('email', 'remember'));
}
}
return redirect(route('auth.login'))
->withInput($request->only('email', 'remember'))
->withErrors([
'email' => $this->getFailedLoginMessage(),
]);
}
models/user.php
class User extends Model implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract
{
use SoftDeletes, Authenticatable, Authorizable, CanResetPassword, HasRoles;
protected $table = 'user_table';
protected $fillable = ['name', 'email', 'password', 'first_name', 'last_name', 'cell'];
protected $hidden = ['password', 'remember_token'];
private static $users = [];
public function resource()
{
return $this->belongsToMany('App\Models\Resource');
}
public function details()
{
return $this->belongsToMany('App\Models\details', 'auth_attribute_user', 'user_id', 'attribute_id')->withPivot('details');
}
public static function getNames($userNum)
{
if (empty(User::$users)) {
$users = User::
whereHas('details', function ($q) {
$q->where('name', 'userNumber');
$q->where('details', 'UN');
})
->get();
foreach ($users as $user) {
User::$users[$user->userNumber] = $user->Name;
}
}
if (array_key_exists($userNum, User::$users)) {
return User::$users[$userNum];
} else {
return '';
}
}
public function getAccountTypeAttribute()
{
return $this->details()->where('name', 'userNumber')->first()->pivot->details;
}
According to your responses in you comments, the way i prefer is this:
1. Make the api call. Check Guzzle to make http requests. It is a nice library and i often use it;
2. Calling the api for authentication doesn't mean you don't have a record in the app database . You need it to related your data to other tables. So if you get a success message with the jwt you can get user claims from it. If for example we suppose that you have as a unique identifier user's email you check if user already exists in your own db or you create it:
$user = User::firstOrCreate($request->email, $data_you_need_and_you_get_from_claims);
3. Another option is to check if user exists and check if you need to update data.
4. Login User
Auth::login($user, $request->has('remember'));
Hope it helps. Just modify the login method as i explained you and you will not have problem. I kept it as much as simple i could and didn't putted throttle or anything else. Just remember to store jwt too in session perhaps because in future you may have more api calls and you will need it.

Laravel-5 redirect within authorize() function on form requests

Is it possible for me to create a redirect from within the authorize() function on a request? I have tried the following code, but it doesn't fulfill the redirect request. Can anyone shed any light on this?
Thanks.
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
use App\Reserve;
use Cookie;
use Config;
class ClassVoucherCheckoutRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize(Reserve $reserve, Cookie $cookie)
{
if((!$cookie->has(Config::get('app.cookie_name'))) || ($reserve->where('cookie_id', $cookie->get(Config::get('app.cookie_name')))->count() == 0))
{
return redirect()->to('butchery-voucher')->withErrors('Your reservation has expired. Places can only be held for up to 30 minutes.');
}
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
];
}
}
I also have the same issue, I did not find any solution yet but I have do this by an another way, I know this is not the right solution but may be help for now.
My problem is: I need to register an user if any other user with same fb_id did not exists in database. But I was unable to check this condition because the middelware execute before the controller and it returns me the fb_id already taken error.
This is my UserController:
public function createUser (UserRequest $request) {
/** here I need to redirect user if the given `fb_id` is already exists
before it was always returning the `fb_id` exists error before executing
the following code, because all input filtered by the `UserRequest` middleware
I have changed the `UserRequest.php` to execute the following code.
**/
$fb_id = Input::get('fb_id');
$user = $this->user->getUserWhereFbIdIn([$fb_id]);
if(sizeof($user) > 0){
return Response::json(['result' => true, 'error' => false, 'message' => 'User exists', 'data' => $user]);
}
// insert user code is here
}
UserRequest.php:
public function authorize()
{
return true;
}
public function rules()
{
$fb_id = Input::get('fb_id');
$user = User::where('fb_id', $fb_id)->get()->toArray();
if(sizeof($user) > 0){
return [];
}
return [
'fb_id' => 'required|unique:users',
'username' => 'required|unique:users',
'email' => 'required|unique:users',
'image' => 'required',
'device_id' => 'required',
'status' => 'required',
];
}
I think the most elegant solution is to make the authorize() return false when you want to redirect, and override the forbiddenResponse() method on the FormRequest class. The drawback is that you'll either have to perform the condition logic twice, or set a state variable.
class MyRequest extends FormRequest
{
public function authorize(): bool
{
return Auth::user()->hasNoEmail() ? false : true;
}
public function forbiddenResponse(): Response
{
if Auth::user()->hasNoEmail() return redirect(route('user.should_provide_email'));
return parent::forbiddenResponse();
}
public function rules(): array
{
return [];
}
}
Of course, the argument could be made that such redirects should always take place in a middleware applied to specific groups of routes, but having the option to do it in a Request class can be nice.

Laravel 4.2: After checking “remember me” checkbox user's login doesn't get remembered in database, only in cookie, thus remember me not working

I am using laravel 4.2
I have a login form where I am trying to implement the remember me functionality. I have used Auth::attempt() to implement the above. Here's my code.
public function logintest()
{
// set the remember me cookie if the user check the box
$remember = (Input::has('remember')) ? true : false;
// attempt to do the login
$auth=Auth::attempt(
[
'username' => Input::get('username'),
'password' => put::get('password')
], $remember);
if ($auth)
{
// The user is active, not suspended, and exists.
$id = Auth::user()->id;
return Redirect::to("example/$id");
}
else
{
return Redirect::to('example')
->with('flash_error', 'Incorrect Username or Password!');
}
}
I have also created a column "remember_token"(a nullable string with 255 chars) in registration table. And also added below 3 methods in the model MyModel.php
public function getRememberToken()
{
return $this->remember_token;
}
public function setRememberToken($value)
{
$this->remember_token = $value;
}
public function getRememberTokenName()
{
return 'remember_token';
}
Yes it does sets the cookie named remember_xxxxxx, but it doesn't add anything to the remember_token column. It's not working. Is there something i missed ?
Please notice that remember_token only makes sure that the user won't be logged out after 2 hours (or any other amount of time that has been given in the config file).
You need to have a user model before it will work.
The fillable variable tells the model which fields may be mass assigned (changed).
class Users extends Eloquent {
protected $fillable = array('username', 'password', 'remember_token');
public function getRememberToken()
{
return $this->remember_token;
}
public function setRememberToken($value)
{
$this->remember_token = $value;
}
public function getRememberTokenName()
{
return 'remember_token';
}
}
This name of the model needs to have the exact same name as the table in the database or you can specify the table name in a variable called table. I think you want to store the remember_token in the same table as where the users are.
In the controller you should add
use Location\To\Model;
So assuming you created a Model directory inside the app directory
use App\Model\Users;
To authenticate users by their remember token you should use
if (Auth::viaRemember())
{
//
}

Categories