问题在于注册后将用户重定向到login
路由的方式.您错误地认为$request
数据将伴随重定向.
让我们假设这样的场景:一个请求被分派到具有name
、email
和password
字段的postRegister
方法.控制器创建用户并将其保存到数据库中.则它将尚未认证的用户重定向到login
路由.postLogin
方法被触发,但这一次没有请求数据.结果,Auth::attempt($credentials)
失败了,你会在屏幕上看到令人讨厌的Failure
.
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';
}
It will return something like this:
array:2 [
"username" => null
"password" => null
]
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.
既然你知道问题的根源是什么,让我们看看有什么办法可以解决它.
1.使用闪存数据重定向
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';
}
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
.
2. Login the user right after the registration
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?
Note that Laravel's own authentication controller does it automatically.
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();
}
但仍然是far from perfect!还有很多其他方法可以解决这个问题.其中一个可能使用events,失败时投掷exceptions,失败时投掷a solution perfectly designed for this197/65732">redirecting using custom exceptions.但我不会go 探索它们,因为已经有a solution perfectly designed for this个了.
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.
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.