php Laravel Auth::attempt() 返回 false

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41342907/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 02:23:20  来源:igfitidea点击:

Laravel Auth::attempt() returns false

phplaravelauthenticationlaravel-5

提问by Programming_Duders

I am a home hobbyist and am studying Laravel, currently in version 5.3. I am using a Mac, neither homesteadnor vagrant.

我是一个家庭爱好者,正在学习 Laravel,目前在5.3. 我使用的是 Mac,既不homesteadvagrant.

I'm currently working on a website that uses a login and a register system to create users.

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

I've used php artisan migrateto manipulate my database locally.

我曾经php artisan migrate在本地操作我的数据库。

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

屏幕截图 2016-12-27 at 4.18.38 PM.png

As listed below, it has three fields, namely:

如下所示,它包含三个字段,即:

  • Email
  • Username
  • Password
  • 电子邮件
  • 用户名
  • 密码

I have a Usermodel (users.php):

我有一个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',
    ];

}

And also, a UserControllerclass (UserController.php):

还有一个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'; 
    }
}

?>

As you can see, I am using bcrypt()as my hashing method.

如您所见,我正在使用bcrypt()我的散列方法。

However, this problem is, it will always result to a failure.

然而,这个问题是,它总是会导致失败。

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

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

I have checked the following links:

我检查了以下链接:

P.S. These links seem very hard to follow as I do not utilize the Inputclass.

PS 这些链接似乎很难遵循,因为我不使用Input该类。

采纳答案by sepehr

The problem is with the way you're redirecting the user to loginroute after the registration. You're falsely assuming that the $requestdata will be accompanied with the redirect.

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

Let's assume this scenario: A request gets dispatched to the postRegistermethod with name, emailand passwordfields. The controller creates the user and saves it into the database. Then it redirects the user, who is not yet authenticated, to the loginroute. The postLoginmethod gets triggered, but this time with no request data. As a result, Auth::attempt($credentials)fails and you get that nasty Failureon screen.

让我们假设这个场景:一个请求被分派到postRegister带有nameemailpassword字段的方法。控制器创建用户并将其保存到数据库中。然后它将尚未通过身份验证的用户重定向到该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:

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

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.

您不能使用自定义请求数据重定向(除非使用作为 URL 一部分的查询字符串),无论怎样。这不是 HTTP 的工作方式。除了请求数据之外,您甚至无法使用自定义标头重定向

Now that you know what's the root of your problem, let's see what are the options to fix it.

现在您知道问题的根源是什么,让我们看看有哪些解决方法。

1. Redirect with flashed data

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 Sessionfacade, session()helper or the actual Illuminate\Session\SessionManagerclass.

如果您想保留此结构,您需要将请求数据postRegister()写入会话(在请求之间是持久的),然后在postLogin()方法中使用SessionFacade、session()helper 或实际Illuminate\Session\SessionManager类检索它。

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 postLoginindependently from the postRegister.

我强烈建议您不要使用这种方法。这样postLogin(),应该负责登录用户的方法的实现与不好的会话数据耦合。这样,您就无法postLogin独立于postRegister.

2. Login the user right after the registration

2. 注册后立即登录用户

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.

请注意,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.)

顺便说一句,这就是我的意思:(
理想情况下,这应该分解为多个方法,就像 Laravel 自己的身份验证控制器一样。但这只是让您入门的示例。)

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 exceptionson failure and redirecting using custom exceptions. But I'm not gonna explore them as there's already 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 RegistersUsersand AuthenticatesUserstraits in order to learn from it.

如果您想编写自己的身份验证控制器,那很好。一路上你会学到很多东西。但我强烈建议阅读 Laravel 自己的身份验证代码,特别是RegistersUsersAuthenticatesUserstrait 以便从中学习。

And one more note; you don't need that Illuminate\Auth\Authenticatabletrait in your Usermodel as it's already extending Authenticatablewhich use that trait.

还有一张纸条;您Illuminate\Auth\AuthenticatableUser模型中不需要该特征,因为它已经在扩展Authenticatable使用该特征的部分。

回答by vachina

You should hash your password everytime you insert a row bcrypt(pass). Auth::attempt assumes that the password being retrieved from the database is hashed

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

回答by DevK

Auth::attemptuses \Hash::make($someString)to generate the hash. You should use this as well in order to generate same hashes from same strings (I assume the seed is different than with bcrypt()function).

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

So change this line:

所以改变这一行:

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

To:

到:

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