web-dev-qa-db-ja.com

Laravel Auth :: attempt()はfalseを返します

私は家の趣味で、現在バージョン_5.3_のLaravelを勉強しています。 Macを使用していますが、Homesteadvagrantも使用していません。

現在、ログインと登録システムを使用してユーザーを作成するWebサイトで作業しています。

_php artisan migrate_を使用して、データベースをローカルで操作しました。

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

以下にリストされているように、3つのフィールドがあります。

  • Eメール
  • Username
  • パスワード

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クラスを利用していないため、これらのリンクをたどるのは非常に困難です。

10

問題は、登録後にユーザーをloginルートにリダイレクトする方法にあります。 _$request_データにリダイレクトが伴うと誤って仮定しています。

このシナリオを想定してみましょう:リクエストはpostRegisternameemailフィールドでpasswordメソッドにディスパッチされます。コントローラーはユーザーを作成し、データベースに保存します。次に、まだ認証されていないユーザーを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の仕組みではありません。データは別にして、 カスタムヘッダー でリダイレクトすることもできません。

問題の原因がわかったので、それを修正するためのオプションを見てみましょう。

1.フラッシュされたデータでリダイレクトする

この構造を保持する場合は、postRegister()のリクエストデータをセッションにフラッシュし(リクエスト間で永続的)、Sessionを使用してpostLogin()メソッドで取得する必要があります。 facade、session()ヘルパー、または実際の_Illuminate\Session\SessionManager_クラス。

ここに私が意味するものがあります:
コードを少し変更しました。余分な変数を削除し、少しきれいにしました。

_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()メソッドの実装は、良くないセッションデータと結び付けられます。この方法では、postLoginから独立してpostRegisterを使用することはできません。

2.登録直後にユーザーにログインします

これはわずかに優れたソリューションです。登録直後にユーザーをログインする必要があると決めた場合、なぜそれを行うだけではありませんか?

Laravel独自の認証コントローラー が自動的にそれを行うことに注意してください

ところで、ここに私が意味するものがあります:
(理想的には、これは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();
}
_

それでも、完璧からはほど遠い!これに取り組むには他にも多くの方法があります。 1つは events を使用し、失敗すると exceptions をスローし、 カスタム例外を使用してリダイレクトする 。しかし、 this 向けに完全に設計されたソリューションが既にあるので、それらを探索するつもりはありません。

独自の認証コントローラーを作成する場合は、問題ありません。あなたは道に沿って多くを学びます。しかし、Laravel自身の認証コード、特に RegistersUsers および AuthenticatesUsers の特徴を読むことを強くお勧めします。

そしてもう一つの注意; Userモデルでは、その特性を使用する Authenticatable を既に拡張しているため、その_Illuminate\Auth\Authenticatable_特性は必要ありません。

5
sepehr

行bcrypt(pass)を挿入するたびにパスワードをハッシュする必要があります。 Auth :: attemptは、データベースから取得されるパスワードがハッシュされていることを前提としています

1
vachina