首页 文章

Laravel Auth :: attempt()返回false

提问于
浏览
5

我是家庭爱好者,正在学习Laravel,目前版本为 5.3 . 我使用的是Mac,既不是_2673944也不是 vagrant .

我目前正在开发一个使用登录和注册系统来创建用户的网站 .

我已经使用 php artisan migrate 在本地操作我的数据库 .

Screen Shot 2016-12-27 at 4.18.38 PM.png

如下所列,它有三个字段,即:

  • 电子邮件

  • 用户名

  • 密码

我有一个 User 模型(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):

<?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() 作为我的哈希方法 .

但是,这个问题是,它总会导致失败 .

Screen Shot 2016-12-27 at 4.41.38 PM.png

我检查了以下链接:

附:这些链接似乎很难遵循,因为我没有使用 Input 类 .

3 回答

  • 3

    问题在于您在注册后将用户重定向到 login 路由的方式 . 您错误地假设 $request 数据将伴随重定向 .

    让我们假设这种情况:使用 nameemailpassword 字段将请求分派到 postRegister 方法 . 控制器创建用户并将其保存到数据库中 . 然后,它将尚未通过身份验证的用户重定向到 login 路由 . postLogin 方法被触发,但这次没有请求数据 . 结果, Auth::attempt($credentials) 失败,你在屏幕上得到了令人讨厌的 Failure .

    如果在创建数组后立即添加 dd($credentials) ,您将看到它没有值:

    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的一部分),无论如何 . 这不是HTTP的工作原理 . 请求数据,you can't even redirect with custom headers .

    既然您知道问题的根源是什么,那么让我们看看有哪些方法可以解决它 .

    1.使用闪烁数据重定向

    如果要保留此结构,则需要将 postRegister() 的请求数据刷新到会话中(在请求之间保持不变),然后使用 Session facade, session() helper或实际的 Illuminate\Session\SessionManager 类在 postLogin() 方法中检索它 .

    这就是我的意思:
    (我稍微修改了你的代码;删除了额外的变量,使它变得更清晰,等等)

    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 .

    2.注册后立即登录用户

    这是一个稍好的解决方案;如果您决定在注册后立即登录用户,为什么不这样做呢?

    请注意Laravel自己的身份验证控制器does it automatically .

    顺便说一句,这就是我的意思:
    (理想情况下,这应该分解为多种方法,就像Laravel 's own authentication controller. But it'只是一个让你入门的例子 . )

    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,在失败时抛出exceptionsredirecting using custom exceptions . 但我'm not gonna explore them as there'已经a solution perfectly designed for this .

    如果你想编写自己的身份验证控制器,那么's fine. You'将会学到很多东西 . 但我强烈建议阅读Laravel自己的身份验证代码,尤其是RegistersUsersAuthenticatesUsers特征,以便从中学习 .

    再说一遍;你在 User 模型中不需要那个 Illuminate\Auth\Authenticatable 特征,因为它已经扩展了使用该特征的Authenticatable .

  • -2

    每次插入行bcrypt(pass)时都应该对密码进行哈希处理 . Auth :: attempt假定从数据库中检索的密码是经过哈希处理的

  • 1

    Auth::attempt 使用 \Hash::make($someString) 生成哈希 . 您也应该使用它来从相同的字符串生成相同的哈希值(我假设种子与 bcrypt() 函数不同) .

    所以改变这一行:

    $password = bcrypt($request['password']);
    

    至:

    $password = \Hash::make($request['password']);
    

相关问题