Reputation: 709
I'm using Laravel 9 authentication. It's a successful login, but on the main page, it is not logged in. So I'm expecting it to authenticate.
Login controller
if (Auth::attempt([
'x_username' => $data['username'],
'x_user_password' => $data['password']
])) {
return true; //login success
} else {
return false;
}
Dashboard controller (it shows 2)
if(Auth::check()) {
echo "1"; //not happened, but login before is success?
} else {
echo "2";
}
$user = Auth::user();
var_dump($user); //it shows NULL
Models
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
protected $table = 'tbl_x_user';
protected $fillable = [
'x_username',
'x_user_email',
'x_user_password',
];
protected $hidden = [
'x_user_password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
public function getAuthPassword()
{
return $this->x_user_password;
}
}
auth.php
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
],
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
'password_timeout' => 10800,
kernels.php
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
protected $middleware = [
// \App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class,
\Illuminate\Http\Middleware\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
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,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\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,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
}
Notes
Upvotes: 3
Views: 2015
Reputation: 38609
After wasting a couple of hours found a solution for this. The issue cause is
auth()->attempt
always check fields such asusername
,password
. In your case, you have used a custom column name on the table.
The solution that I found is
Mappable
)Bonus
Now, you can use
username
to get the field data. Ex:
$user = User::where(['username' => 'ab'])->first();
$user->username(); # bonus
composer require sofa/eloquence
composer require sofa/eloquence-mappable
User
modelImport
use Sofa\Eloquence\Eloquence;
use Sofa\Eloquence\Mappable;
use
use Eloquence, Mappable;
In model body
protected array $maps = [
'username' => 'x_username', # I used x_username as my local test
'password' => 'x_user_password',
];
if (auth()->attempt(['username' => 'ab', 'password' => 'ab@123'])) {
return view('welcome');
} else {
return "not logged in";
}
IMPORTANT: Laravel encrypts passwords using Hashing. So make sure your password is hashed in the DB. Because Auth
attempt()
always works with Hashing
For testing purposes, I used welcome.blade.php.
@auth
<h3>Logged In</h3>
@else
<h3>Not yet Logged In</h3>
@endauth
And the output was
Migration
Schema::create('x_users', static function (Blueprint $table) {
$table->increments('id');
$table->string('x_username');
$table->string('x_user_email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('x_user_password');
$table->rememberToken();
$table->timestamps();
});
User create
User::create([
'x_username' => 'ab',
'x_user_email' => '[email protected]',
'x_user_password' => Hash::make('ab@123'),
]);
In model
Used $guarded
to ignore MassAssignment
error (Not recommended. Just for time save)
protected $table = 'x_users';
protected $guarded = [];
Upvotes: 0
Reputation: 968
I've tested it on a new Laravel app with simple Breeze authentication, see below for the set-up used.
$ laravel new testing
$ cd testing
$ composer require laravel/breeze --dev
$ php artisan breeze:install
Then I've updated the users migration like this:
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('x_username')->unique();
$table->string('x_user_email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('x_user_password');
$table->rememberToken();
$table->timestamps();
});
Then I've run php artisan migrate:fresh
, which will rebuild the database from scratch.
Inside the RegisteredUserController
I've made an update to use the new fields you specified:
$user = User::create([
'x_username' => $request->name,
'x_user_email' => $request->email,
'x_user_password' => Hash::make($request->password),
]);
I've updated the model according to what you set in your question.
Then I've registered a new user through visiting /register
.
I'm automatically logged in after registering, so I'll logout using the logout link provided in the navigation from Breeze.
Now, inside resources/views/auth/login.blade.php
I've changed the email address field to use the username:
<div>
<x-input-label for="username" value="Username" />
<x-text-input id="username" class="block mt-1 w-full" type="text" name="username" :value="old('username')" required autofocus />
<x-input-error :messages="$errors->get('username')" class="mt-2" />
</div>
So now that the project is set up, let's have a look at what isn't working. To log in with the new fields we'll need to change the login code (in Breeze's case the App\Http\Requests\Auth\LoginRequest
.
I've changed the authenticate
method inside the request as follows:
public function authenticate()
{
$this->ensureIsNotRateLimited();
if (! Auth::attempt([
'x_username' => $this->input('username'),
'password' => $this->input('password'),
], $this->boolean('remember'))) {
RateLimiter::hit($this->throttleKey());
throw ValidationException::withMessages([
'email' => trans('auth.failed'),
]);
}
RateLimiter::clear($this->throttleKey());
}
Note that credentials should contain two types of fields:
In the example code the field that's used to fetch the user from the database is x_username
(Laravel filters out all fields containing the key password
, and then uses the others to find a user).
The field used to verify the password is password
. You've already specified the getAuthPassword
method in your user to make sure that it uses the x_user_password
field. Laravel will thus check if the password credential entered can be hashed to the same value as in x_user_password
.
As far as I can see this is the only mistake you made: not using the key password
in your Auth::attempt()
call.
If you have any issues with your session not sticking, ensure that the session cookie is properly sent to the server. Check your browser console under "Storage" and then "Cookies" to see if the cookie was sent to the browser. If the cookie isn't sent, the session will not be recognised, and you will not be logged in.
Sometimes the cookie will not be sent to the server, for example if you set secure => true
in session.php
(which can be done through SESSION_SECURE_COOKIE=true
in your .env). The cookie will then only be sent if you're visiting your app over HTTPS.
Other than the secure
setting, the domain
and path
of course also matter. Since you've said you hadn't touched the session.php
configuration I'll assume that there's no issues there.
Upvotes: 0
Reputation: 49
Have you added the middleware to the route?
Route::get('/', function () {})->middleware('auth');
or you can do this inside the controller
public function __construct()
{
$this->middleware('auth');
}
Upvotes: 0
Reputation: 32
You can try this:
In Blade:
@auth
// User is Authenticated
@else
// User is Not Authenticated
@endauth
Upvotes: 0