Laravel 5.3 Ajax 登录

3

我正在尝试在一个新的Laravel 5.3项目中使用ajax登录我的用户。

我已经生成了auth路由,并将其添加到我的web.php文件中:

Auth::routes();

我有一个包含电子邮件、密码输入和CSRF字段的HTML表单。同时我还有以下javascript文件:

$("form.login").submit(function(e) {
    e.preventDefault();

    $.ajax({   
        method: "POST",
        dataType: "json",
        headers: { 
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'),
        },
        data: $("form.login").serialize(),
        url: "/login"
    })
    .done(function(data) {
        console.log(data);
    });
});

当我发布时,这将出现在我的网络选项卡中: chrome dev tools 它会重定向回原始页面,没有返回任何数据。
为什么会这样?5.3不再提供json响应吗?

尝试在登录方法的开头添加 dd() 并检查您是否可以在请求中看到该 dd。如果可以,很可能您在该代码中有一个重定向,应该使用 Response 解决。如果没有,则很可能问题在于路由的中间件。 - Luís Cruz
2个回答

5

完整解决方案:

你好,reinierkors,

我也曾尝试使用5.3版本实现同样的功能,最终我成功了,并且解决方案非常干净。

首先,我在App\Http\Controllers\Api下创建了一个名为Auth的新文件夹,这样我就可以为API添加新的身份验证控制器,以便重写一些函数,然后将身份验证控制器(LoginControllerForgotPasswordControllerRegisterController)复制到这个新文件夹中。

在LoginController类中: 我重写了使重定向的函数。

第一个函数:当身份验证返回成功时会自动调用。

第二个函数:当身份验证返回错误时会自动调用。

最后一个函数:当用户在尝试5次登录后被锁定时,会自动调用。

     /**
     * Send the response after the user was authenticated.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    protected function sendLoginResponse(Request $request) {
        $this->clearLoginAttempts($request);

        return response()->json(['SUCCESS' => 'AUTHENTICATED'], 200);
    }

    /**
     * Get the failed login response instance.
     *
     * @return \Illuminate\Http\Response
     */
    protected function sendFailedLoginResponse() {
        return response()->json(['ERROR' => 'AUTH_FAILED'], 401);
    }

    /**
     * Error after determining they are locked out.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    protected function sendLockoutResponse(Request $request) {
        $seconds = $this->limiter()->availableIn(
            $this->throttleKey($request)
        );

        return response()->json(['ERROR' => 'TOO_MANY_ATTEMPTS', 'WAIT' => $seconds], 401);
    }

在 RegisterController 类中,我重写了那些造成重定向的函数。
在第一个函数中,我修改了验证器响应以返回更加便于处理的响应(数组)。
第二个函数将在注册成功后自动调用。
    /**
     * Handle a registration request for the application.
     *
     * @param Request $request
     * @return \Illuminate\Http\Response
     */
    public function register(Request $request) {
        $validator = $this->validator($request->all());

        if($validator->fails())
            return response()->json(['ERROR' => $validator->errors()->getMessages()], 422);

        event(new Registered($user = $this->create($request->all())));

        $this->guard()->login($user);

        return $this->registered($request, $user)
            ?: redirect($this->redirectPath());
    }

    /**
     * The user has been registered.
     *
     * @param Request $request
     * @param  mixed $user
     * @return mixed
     */
    protected function registered(Request $request, $user) {
        return response()->json(['SUCCESS' => 'AUTHENTICATED']);
    }

在 ForgotPasswordController 类中: 我重写了处理重定向的函数。

我修改了重置链接电子邮件函数,这样我们就可以获取消息并以 JSON 格式显示,而不是重定向。

     /**
     * Send a reset link to the given user.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function sendResetLinkEmail(Request $request)
    {
        $validator = Validator::make($request->only('email'), [
            'email' => 'required|email',
        ]);

        if ($validator->fails())
            return response()->json(['ERROR' => 'VALID_EMAIL_REQUIRED'], 422);

        // We will send the password reset link to this user. Once we have attempted
        // to send the link, we will examine the response then see the message we
        // need to show to the user. Finally, we'll send out a proper response.
        $response = $this->broker()->sendResetLink(
            $request->only('email')
        );

        if ($response === Password::RESET_LINK_SENT) {
            return response()->json(['SUCCESS' => 'EMAIL_SENT'], 200);
        }

        // If an error was returned by the password broker, we will get this message
        // translated so we can notify a user of the problem. We'll redirect back
        // to where the users came from so they can attempt this process again.
        return response()->json(['ERROR' => 'EMAIL_NOT_FOUND'], 401);
    }

1

如果想要解释我的错误(和 op 的类似),请参见此帖子的编辑历史记录

我是如何解决它的

@iSensical 的一点帮助下,我解决了这个问题。

app/Exceptions/Handler.php 中有一个 unauthenticated 函数,默认情况下,该函数知道请求是否带有 json 响应,并使用 expectsJson() 函数进行判断。

问题并不是 Laravel 本身造成的。出乎意料的是,这是人为因素。我写了一段糟糕的代码。

我的 ajax 请求没有使用 Laravel 的直观标头。

我原来的代码:

$http({
    url     : '{{ route('angular.auth.login.post') }}',
    method  : 'POST',
    data    : $.param($scope.user)+'&x-csrf-token='+CSRF_TOKEN,
    headers : { 'Content-Type': 'application/x-www-form-urlencoded' }
})
[...]

我们可能使用了错误的Content-Type。正确的应该是application/json,就像这样:application/json
headers : { 'Content-Type': 'application/json' }

假设config/auth.php已设置为默认值,即web。请验证Http/Middleware/authenticate.php中handle()函数中的内容。它应该包含以下代码: if (Auth::guard($guard)->guest()) { return redirect()->guest('login'); }如果有带有$request->ajax() || $request->wantsJson()的代码,则不应重定向到301。 - iSensical
我没有Http/Middleware/authenticate.php这个文件,但是感谢@iSensical,你说得对。有一个函数可以处理这个问题。在5.3版本的app/Exceptions/Handler.php中,有一个默认的unauthenticated函数,它会检查请求是否需要Json响应。我将编辑我的帖子来解释它如何为我工作以及我的错误之处。 - shooteram
谢谢你尝试了一下。我似乎仍然无法让它工作,我认为他们在5.3中完全删除了JSON响应。即使像dataType: "json"这样添加到ajax请求中,它仍然会重定向。 - reinierkors

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接