首页 文章

Laravel 5.6上的Ajax Auth重定向

提问于
浏览
2

我有一个用于触发Ajax Post的Like按钮,此路由受auth:api中间件保护:

的myproject /路线/ api.php

Route::group(['middleware' => ['auth:api']], function () {
    Route::post('/v1/like', 'APIController@set_like');
});

当经过身份验证的用户单击“赞”按钮时,完全没有问题,一切都顺利进行 . 但是当客人点击按钮时,我通过Javascript将它们重定向到登录页面,经过身份验证后,它们被重定向到RedirectIfAuthenticated中间件中指定的页面,通常是/ home . 我修改了这个中间件如下:

MyProject的/应用/ HTTP /中间件/ RedirectIfAuthenticated.php

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Auth;

class RedirectIfAuthenticated
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string|null  $guard
     * @return mixed
     */
    public function handle($request, Closure $next, $guard = null)
    {
        if (Auth::guard($guard)->check()) {
            return redirect()->intended('/home');
        }
        return $next($request);
    }
}

我的Ajax调用是这样的:

var toggleLike = function(){
    var token = USER_TOKEN; //javascript variable
    var current_type = $(thisLikeable).attr("data-type");
    var current_id = $(thisLikeable).attr("data-id");
    var jqxhr = $.post( APP_URL + "/api/v1/like", {api_token: token, type: current_type, id: current_id}, function(data) {
        setLikeAppearance(data.message);
    })
    .fail(function(xhr, status, error){
        if (xhr.status == 401) {
            window.location = APP_URL + "/login" ;
        }
    });
};

这里的问题是aim()函数,对于Ajax调用,它不存储正确的会话变量,我不知道如何正确设置它 . 我显然遗漏了一些明显的东西,有人可以帮忙吗?干杯!

EDIT

我想要实现的是:

  • GUEST在// mysite / blabla中

  • 点击按钮

  • 被重定向到登录

  • 登录(或注册)

  • 被重定向到// mysite / blabla,已经触发了Like

3 回答

  • 2

    发生的事情是,API会话不受管理,换句话说,它是无状态的 . 因此,会话中间件未在Laravel框架上实现API请求 . 虽然你可以手动添加,但它并不是空闲的 . 因此,如果API不使用会话并使用重定向,则fronted不知道它,因为API和前端作为两个单独的应用程序工作 . 因此,您需要向前端发送响应的状态,并让前端处理重定向,就像您使用ajax一样 . 如果未经身份验证,只需删除重定向,并让API抛出未经授权的异常 . 然后从处理程序处理未经授权的异常 .

    这是怎么做的 .

    将此添加到 app/Exceptions/Handler.php

    /**
     * Convert an authentication exception into an unauthenticated response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Illuminate\Auth\AuthenticationException  $exception
     * @return \Illuminate\Http\Response
     */
    protected function unauthenticated($request, AuthenticationException $exception)
    {
        if ($request->expectsJson()) {
            return response()->json(['error' => 'Unauthenticated.'], 401);
        }
    
        return redirect()->guest('login');
    }
    

    如果请求是json(api请求),这将向用户发送401消息Unauthenticated,否则(如果Web请求)将重定向到登录

    检查下面的 render 方法或从source检查它以查看API请求中的's happening. when an unauthorized exception is thrown we are telling to check the request type and if it' s,我们发送一个带有401状态代码的json响应 . 所以从前端知道我们可以在看到401状态代码后将用户重定向到登录页面 .

    From source

    /**
     * Render an exception into a response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Exception  $e
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function render($request, Exception $e)
    {
        if (method_exists($e, 'render') && $response = $e->render($request)) {
            return Router::toResponse($request, $response);
        } elseif ($e instanceof Responsable) {
            return $e->toResponse($request);
        }
        $e = $this->prepareException($e);
        if ($e instanceof HttpResponseException) {
            return $e->getResponse();
        } elseif ($e instanceof AuthenticationException) {
            return $this->unauthenticated($request, $e);
        } elseif ($e instanceof ValidationException) {
            return $this->convertValidationExceptionToResponse($e, $request);
        }
        return $request->expectsJson()
                        ? $this->prepareJsonResponse($request, $e)
                        : $this->prepareResponse($request, $e);
    }
    

    AFTER EDIT

    目标 method() 仅适用于Web路由,因为它使用会话来提取预期路由或手动传递值 . 这是intent()方法 .

    /**
     * Create a new redirect response to the previously intended location.
     *
     * @param  string  $default
     * @param  int     $status
     * @param  array   $headers
     * @param  bool    $secure
     * @return \Illuminate\Http\RedirectResponse
     */
    public function intended($default = '/', $status = 302, $headers = [], $secure = null)
    {
        $path = $this->session->pull('url.intended', $default);
    
        return $this->to($path, $status, $headers, $secure);
    }
    

    要实现重定向到用户可以从中进行的页面

    1 - 手动传递一些带有URL的查询,如 /login?redirect=like(not the url, just a mapping for /comments/like url)&value=true(true is liked, false is unliked) 并手动处理 .

    2 - 从url获取并检查查询参数

    3 - 使用to()方法传递预期的url而不是使用expected() . 这是to()方法 . (见4看推荐方式)

    /**
     * Create a new redirect response to the given path.
     *
     * @param  string  $path
     * @param  int     $status
     * @param  array   $headers
     * @param  bool    $secure
     * @return \Illuminate\Http\RedirectResponse
     */
    public function to($path, $status = 302, $headers = [], $secure = null)
    {
        return $this->createRedirect($this->generator->to($path, [], $secure), $status, $headers);
    }
    

    4 - 但是,我建议发送重定向URL(我的意思是映射ex:like)作为对前端的响应,并让前端处理重定向 . 如果API仅由网站使用,则API重定向将起作用 . 假设您对移动应用程序使用相同的API,请想知道API重定向将如何工作 . 这不是重定向API的工作,除非它适用于OAuth身份验证之类的内容,它将指定重定向URL .

    记得清理url params以阻止XSS之类的东西 . 更好地发送一些值并将其映射到网址 . 喜欢 [
    //喜欢映射
    // comments / like是实际的url

    'like'=>'评论/喜欢'
    ]
    然后从数组中获取映射URL或使用前端映射 .

  • 0

    如果某个按钮不适用于访客,则不应在页面上呈现该按钮 . 相反,您应该呈现一个登录链接,然后如果用户登录,您将重定向到他之前的位置 . 现在,用户可以看到并单击按钮 .

  • 0

    您可以在 RedirectIfAuthenticated.php 中进行更改,以区分 Ajax call和普通登录,如下所示:

    namespace App\Http\Middleware;
    
    use Closure;
    use Illuminate\Support\Facades\Auth;
    
    class RedirectIfAuthenticated
    {
        /**
         * Handle an incoming request.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  \Closure  $next
         * @param  string|null  $guard
         * @return mixed
         */
        public function handle($request, Closure $next, $guard = null)
        {
            if (Auth::guard($guard)->check()) {
    
                if ($request->has('api_token')) {
                    // do whatever you want
    
                    return response()->json('some response'); 
                }
    
                    return redirect()->intended('/home');
            }
            return $next($request);
        }
    }
    

    Update:

    另一种解决方案是从您的路线中删除 Auth 中间件 . 在 APIController@set_like 函数中手动登录用户,触发类似&return json response .

相关问题