【问题标题】:Add additional data(ajax) to native authentication in Laravel在 Laravel 中向本机身份验证添加附加数据(ajax)
【发布时间】:2020-05-05 09:56:46
【问题描述】:

我正在尝试通过在用户登录后编写统计信息来在 Laravel 中实现用户跟踪。即位置,时区等。我有点幸运地实现了它。

我通过在登录表单上附加事件侦听器来使用 ajax 提交按钮。表单提交后,调用ajax方法。此方法通过使用 api 调用获取用户的统计信息。然后,该 ajax 请求将该数据发送到StatsController@store,后者随后将该条目记录到 stats 表中。

这只能通过使用e.preventDefault(); 来实现,如果我不使用它,记录不会插入到数据库中,它会抛出一个错误,该错误在重定向到仪表板后迅速消失。

Ajax 方法驻留在布局文件中被调用的 js 文件中。

这是一个ajax方法:

function getCoords(){

    return fetch('https://ipinfo.io/geo')
    .then((response) => {
        if (!response.ok) {
            throw new Error('Network response was not ok');
        }
        else{

            return response.json();

        }

    })
    .then((response) => {

        let url = "/writeStats";
        let token = document.querySelector("meta[name='csrf-token']").getAttribute("content");
        let forma = document.getElementById("loginForm");

        let formElements = {};

        formElements.email = forma.elements[1].value;
        formElements.password = forma.elements[2].value;

        $.ajax({
            url: url,
            type: 'POST',
            data: {_token: token , message: "bravo", stats: response, formElements: formElements},
            dataType: 'JSON',
            success: (response) => { 
                console.log("success");
                console.log(response);
            },
            error: (response) => {
                console.log("error");
                console.log(response);
            }
        }); 

    })
    .catch((error) => {
        console.error('There has been a problem with your fetch operation:', error);
    });

}

window.addEventListener("click", (e) => {

    if(e.target.id==="loginBtn"){
        //e.preventDefault();
        getCoords();
    }

});

web.php:

Route::post('/writeStats','StatsController@store');

统计控制器:

public function store(Request $request)
{
    if($request->ajax()){

        $email = $request->formElements["email"];
        $password = $request->formElements["password"];

        $user = DB::table('users')->where("email", "=", $email)->first();

        if(Hash::check($password, $user->password)) {   

            $stat = new Stats;
            $stat->ip = $request->stats["ip"];
            $stat->city = $request->stats["city"];
            $stat->region = $request->stats["region"];
            $stat->country = $request->stats["country"];
            $stat->coords = $request->stats["loc"];
            $stat->timezone = $request->stats["timezone"];
            $stat->user_id = $user->id;
            $stat->save();

            $response = array(
                "message" => "bravo",
                "request" => $request->all(),
                "stats" => $request->stats,
                "user" => $user,
                "stat" => $stat,
            );

            return response()->json($response);

        }

    }

}

php artisan --version 显示Laravel Framework 6.9.0

我的问题是:如何在用户登录后插入统计表?

编辑1:

我现在正在尝试一些不同的方法。我现在在 LoginController 中使用 authenticated 方法,而不是来自 StatsController 的一些自定义方法。

public function authenticated(Request $request)
    {
        $credentials = $request->only('email', 'password');

        $email = $request->input("email");
        $password = $request->input("password");

        $user = DB::table('users')->where("email", "=", $email)->first();
        if (Auth::attempt($credentials)) {

            $stat = new Stats;
            $stat->ip = $request->stats["ip"];
            $stat->city = $request->stats["city"];
            $stat->region = $request->stats["region"];
            $stat->country = $request->stats["country"];
            $stat->coords = $request->stats["loc"];
            $stat->timezone = $request->stats["timezone"];
            $stat->user_id = auth()->user()->id;
            $stat->save();

            $response = array(
                "stat" => $request->all(),
            );

            return redirect()->intended('dashboard');

        }
    }

在 web.php 中:

Route::post('/login','Auth\LoginController@authenticated');

仍然没有运气。我只是不知道使用什么方法。感觉如此接近,就像我错过了一些小东西。

编辑2:

让我改一下问题:

如何将api调用响应发送到登录控制器,以便用户通过身份验证后,我可以将api响应数据插入另一个表(不是用户表)? 我可以:

  1. 以某种方式将 api 响应插入到身份验证请求中?
  2. 或者,如何在将记录写入表stats的同时进行身份验证?

我尝试了这两种方法(参见:原始和编辑),但不确定我应该写什么......

【问题讨论】:

    标签: ajax laravel


    【解决方案1】:

    这就是它的预期行为。由于在您的用例中,表单提交依赖于异步操作,因此您需要这种行为。

    https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault

    Event 接口的 preventDefault() 方法告诉用户代理,如果事件没有得到显式处理,则不应像往常一样采取其默认操作。

    更新:参考:using a fetch inside another fetch in javascript 用于嵌套异步操作。

    【讨论】:

    • 是的,我知道。我不知道如何首先提交从 api 派生的数据,然后进行身份验证和后续重定向。如何做到这一点?
    • 身份验证是原生 Laravel 身份验证,不是来自 ajax 调用。您可以在控制器方法中看到这一点。所以我不需要链接承诺。我需要将 api 的响应“注入”到本地 Laravel 身份验证请求。
    • 所以你想要本地表单提交但在该事件之前进行异步调用?
    • 简而言之,是的。我想检查(本机)身份验证并同时获取 api 调用响应并将其插入表'stats'中。
    • 您是否尝试在异步内容完成后提交表单? form.submit() - 你仍然需要使用 preventDefault()
    【解决方案2】:

    我找到了一个完美的解决方案。为了更好地解释,我有几个错误:

    第一个是 ajax 调用中的 dataType,预计将返回 json 响应。不需要任何响应,因为在登录和随后从 api 插入数据时,用户被发送到/dashboard

    第二个是我使用e.preventDefault();,因为我想看看提交后我会得到什么。没有必要,上一段中的最后一句解释。

    顺便说一句,返回的是 html 代码,因为用户被重定向到查看...

    这里是修改后的代码:

    登录控制器:

    <?php
    
    namespace App\Http\Controllers\Auth;
    
    use App\Http\Controllers\Controller;
    use Illuminate\Foundation\Auth\AuthenticatesUsers;
    
    use Illuminate\Http\Request;
    use Auth;
    use App\Stats;
    
    class LoginController extends Controller
    {
        /*
        |--------------------------------------------------------------------------
        | Login Controller
        |--------------------------------------------------------------------------
        |
        | This controller handles authenticating users for the application and
        | redirecting them to your home screen. The controller uses a trait
        | to conveniently provide its functionality to your applications.
        |
        */
    
        use AuthenticatesUsers;
    
        /**
         * Where to redirect users after login.
         *
         * @var string
         */
        protected $redirectTo = '/dashboard';
    
        /**
         * Create a new controller instance.
         *
         * @return void
         */
        public function __construct()
        {
            $this->middleware('guest')->except('logout');
        }
    
        public function authenticated(Request $request)
        {
    
            $email = $request->formElements["email"];
            $password = $request->formElements["password"];
    
            if (Auth::attempt(['email' => $email,'password' => $password])) {
    
                $stat = new Stats;
                $stat->ip = $request->stats["ip"];
                $stat->city = $request->stats["city"];
                $stat->region = $request->stats["region"];
                $stat->country = $request->stats["country"];
                $stat->coords = $request->stats["loc"];
                $stat->timezone = $request->stats["timezone"];
                $stat->user_id = auth()->user()->id;
                $stat->save();
    
                $response = array(
                    "stat" => $request->all(),
                );
    
                return redirect()->intended('dashboard');
            }
        }
    }
    

    布局文件中调用的脚本中的 ajax 方法和事件监听器代码:

    function getCoords(){
    
        return fetch('https://ipinfo.io/geo')
        .then((response) => {
            if (!response.ok) {
                throw new Error('Network response was not ok');
            }
            else{
    
                return response.json();
    
            }
    
        })
        .then((response) => {
    
            let url = "/login";
            let token = document.querySelector("meta[name='csrf-token']").getAttribute("content");
            let forma = document.getElementById("loginForm");
    
            let formElements = {};
    
            formElements.email = forma.elements[1].value;
            formElements.password = forma.elements[2].value;
            console.log(formElements);
            $.ajax({
                url: url,
                type: 'POST',
                data: {_token: token , message: "bravo", stats: response, formElements: formElements},
                dataType: 'html',
                success: (response) => { 
                    console.log("success");
                    console.log(response);
                    forma.submit();
    
                },
                error: (response) => {
                    console.log("error");
                    console.log(response);
                }
            }); 
    
        })
        .catch((error) => {
            console.error('There has been a problem with your fetch operation:', error);
        });
    
    }
    
    window.addEventListener("click", (e) => {
    
        if(e.target.id==="loginBtn"){
            getCoords();     
        }
    
    });
    
    window.addEventListener("keypress", (e) => {
    
        let forma = document.getElementById("loginForm");
        let isFocused = (document.activeElement === forma.elements[2]);
    
        if(forma.elements[1].value && forma.elements[2].value && e.key === 'Enter' && isFocused){
    
            getCoords();
    
        }
    
    });
    

    如果你想在 Laravel 中添加 ajax 调用 身份验证,那么对于“任何可能关心的人”来说,这就是一个解决方案。可能也可以用于其他用途……例如自定义身份验证或其他用途。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-30
      • 2020-12-24
      • 2017-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多