Laravel Auth :: attempt()返回false [英] Laravel Auth::attempt() returns false
问题描述
我是一名家庭爱好者,正在学习Laravel,当前版本为5.3
.我正在使用Mac,而不是homestead
或vagrant
.
I am a home hobbyist and am studying Laravel, currently in version 5.3
. I am using a Mac, neither homestead
nor vagrant
.
我目前正在使用登录和注册系统创建用户的网站上.
I'm currently working on a website that uses a login and a register system to create users.
我已经使用php artisan migrate
在本地操作我的数据库.
I've used php artisan migrate
to manipulate my database locally.
如下所示,它具有三个字段,即:
As listed below, it has three fields, namely:
- 电子邮件
- 用户名
- 密码
我有一个User
模型(users.php):
I have a User
model (users.php):
<?php
namespace blog;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Authenticatable;
class User extends Model implements Authenticatable {
use \Illuminate\Auth\Authenticatable;
use Notifiable;
protected $fillable = [
'username', 'email', 'password',
];
}
还有一个UserController
类(UserController.php):
And also, a UserController
class (UserController.php):
<?php
namespace blog\Http\Controllers;
use Auth;
use blog\User;
use Illuminate\Http\Request;
class UserController extends Controller {
public function postRegister(Request $request) {
$username = $request['username'];
$email = $request['email'];
$password = bcrypt($request['password']);
$user = new User();
$user->email = $email;
$user->username = $username;
$user->password = $password;
$user->save();
return redirect()->route('login');
}
public function postLogin(Request $request) {
$credentials = [
'username' => $request['username'],
'password' => $request['password'],
];
if(Auth::attempt($credentials)) {
return redirect()->route('dashboard');
}
return 'Failure';
}
}
?>
如您所见,我正在使用bcrypt()
作为我的哈希方法.
As you can see, I am using bcrypt()
as my hashing method.
但是,这个问题总是会导致失败.
However, this problem is, it will always result to a failure.
我检查了以下链接:
P.S.这些链接似乎很难遵循,因为我没有使用Input
类.
P.S. These links seem very hard to follow as I do not utilize the Input
class.
推荐答案
问题在于注册后将用户重定向到login
路由的方式.您错误地假设$request
数据将伴随重定向.
The problem is with the way you're redirecting the user to login
route after the registration. You're falsely assuming that the $request
data will be accompanied with the redirect.
让我们假设这种情况:使用name
,email
和password
字段将请求分派到postRegister
方法.控制器创建用户并将其保存到数据库中.然后,它将尚未通过身份验证的用户重定向到login
路由. postLogin
方法被触发,但是这次没有请求数据.结果,Auth::attempt($credentials)
失败,并且您在屏幕上看到该讨厌的Failure
.
Let's assume this scenario: A request gets dispatched to the postRegister
method with name
, email
and password
fields. The controller creates the user and saves it into the database. Then it redirects the user, who is not yet authenticated, to the login
route. The postLogin
method gets triggered, but this time with no request data. As a result, Auth::attempt($credentials)
fails and you get that nasty Failure
on screen.
如果在创建数组后立即添加dd($credentials)
,则会看到它没有值:
If you add a dd($credentials)
right after you create the array, you'll see that it has no values:
public function postLogin(Request $request)
{
$credentials = [
'username' => $request['username'],
'password' => $request['password'],
];
// Dump data
dd($credentials);
if (Auth::attempt($credentials)) {
return redirect()->route('dashboard');
}
return 'Failure';
}
它将返回如下内容:
array:2 [
"username" => null
"password" => null
]
您不能使用自定义请求数据进行重定向(除非使用URL中的querystring进行重定向),无论如何.这不是HTTP的工作方式.除了请求数据之外,您甚至无法使用自定义标头重定向.
You cannot redirect with custom request data (unless with querystring which is part of the URL), not matter what. It's not how HTTP works. Request data aside, you can't even redirect with custom headers.
现在您知道问题的根源是什么,让我们看看有哪些解决方案.
Now that you know what's the root of your problem, let's see what are the options to fix it.
如果要保留此结构,则需要将postRegister()
的请求数据刷新到会话中(在请求之间是持久的),然后使用Session
外观在postLogin()
方法中检索它们,session()
助手或实际的Illuminate\Session\SessionManager
类.
In case you want to preserve this structure, you need to flash the request data of postRegister()
into the session (which is persistent between requests) and then retrieve it in the postLogin()
method using Session
facade, session()
helper or the actual Illuminate\Session\SessionManager
class.
这是我的意思:
(我略微修改了您的代码;删除了多余的变量,使其变得有点整洁了,等等.)
Here's what I mean:
(I slightly modified your code; dropped extra variables, made it a lil bit cleaner, etc.)
public function postRegister(Request $request)
{
// Retrieve all request data including username, email & password.
// I assume that the data IS validated.
$input = $request->all();
// Hash the password
$input['password'] = bcrypt($input['password']);
// Create the user
User::create($input);
// Redirect
return redirect()
// To the route named `login`
->route('login')
// And flash the request data into the session,
// if you flash the `$input` into the session, you'll
// get a "Failure" message again. That's because the
// password in the $input array is already hashed and
// the attempt() method requires user's password, not
// the hashed copy of it.
//
->with($request->only('username', 'password'));
}
public function postLogin(Request $request)
{
// Create the array using the values from the session
$credentials = [
'username' => session('username'),
'password' => session('password'),
];
// Attempt to login the user
if (Auth::attempt($credentials)) {
return redirect()->route('dashboard');
}
return 'Failure';
}
我强烈建议您不要使用这种方法.这样,应该负责登录用户的postLogin()
方法的实现与不好的会话数据结合在一起.这样,您将无法独立于postRegister
使用postLogin
.
I strongly recommend you against using this approach. This way the implementation of postLogin()
method which is supposed to be responsible to login users gets coupled with session data which is not good. This way, you're not able to use postLogin
independently from the postRegister
.
这是一个更好的解决方案;如果您确定需要在注册后立即登录用户,为什么不这样做呢?
This is a slightly better solution; If you decided that you need to log in the user right after the registration, why not just doing that?
请注意,Laravel自己的身份验证控制器自动执行.
Note that Laravel's own authentication controller does it automatically.
顺便说一下,这就是我的意思:
(理想情况下,这应该分为多种方法,就像Laravel自己的身份验证控制器一样.但这只是入门的一个示例.)
By the way, here's what I mean:
(Ideally this should be broken down into multiple methods, just like Laravel's own authentication controller. But it's just an example to get you started.)
public function postRegister(Request $request)
{
$input = $request->all();
$input['password'] = bcrypt($input['password']);
User::create($input);
// event(UserWasCreated::class);
if (Auth::attempt($request->only('username', 'password'))) {
return redirect()
->route('dashboard')
->with('Welcome! Your account has been successfully created!');
}
// Redirect
return redirect()
// To the previous page (probably the one generated by a `getRegister` method)
->back()
// And with the input data (so that the form will get populated again)
->withInput();
}
但是,它仍然远非完美!还有许多其他方法可以解决此问题.可能正在使用事件,并抛出使用自定义异常进行重定向.但是,我不会去探讨它们,因为已经有为此目的而完美设计的解决方案.
But still, it's far from perfect! There are many other ways to tackle this. One could be using events, throwing exceptions on failure and redirecting using custom exceptions. But I'm not gonna explore them as there's already a solution perfectly designed for this.
如果您想编写自己的身份验证控制器,那很好.您将在此过程中学到很多东西.但我强烈建议阅读Laravel自己的身份验证代码,尤其是 RegistersUsers
和 AuthenticatesUsers
特质,以便从中学习.
If you want to write your own authentication controller, that's fine. You'll learn a lot along the way. But I strongly suggest reading Laravel's own authentication code, especially RegistersUsers
and AuthenticatesUsers
traits in order to learn from it.
还有一个音符;您不需要在User
模型中使用Illuminate\Auth\Authenticatable
特征,因为它已经扩展了
And one more note; you don't need that Illuminate\Auth\Authenticatable
trait in your User
model as it's already extending Authenticatable
which use that trait.
这篇关于Laravel Auth :: attempt()返回false的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!