[英]Ajax Auth redirect on Laravel 5.6
我有一个触发 Ajax Post 的 Like 按钮,该路由受 auth:api 中间件保护:
myproject/routes/api.php
Route::group(['middleware' => ['auth:api']], function () {
Route::post('/v1/like', 'APIController@set_like');
});
当经过身份验证的用户单击“赞”按钮时,完全没有问题,一切正常。 但是当客人点击按钮时,我通过 Javascript 将他们重定向到登录页面,在身份验证后,他们被重定向到 RedirectIfAuthenticated 中间件中指定的页面,通常是 /home。 我修改了该中间件如下:
myproject/app/Http/Middleware/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" ;
}
});
};
这里的问题是 expected() 函数,对于 Ajax 调用,它没有存储正确的会话变量,我不知道如何正确设置它。 我显然遗漏了一些明显的东西,有人可以帮忙吗? 干杯!
编辑
我想要实现的是:
正在发生的事情是 API 中的会话不受管理,或者换句话说,它是无状态的。 所以会话中间件没有在 Laravel 框架上实现 API 请求。 虽然可以手动添加,但使用起来也不是闲着。 因此,如果 API 不使用会话并使用重定向,则前端不知道它,因为 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 请求),这将向用户发送带有消息 Unauthenticated 的 401,否则(如果 Web 请求)将重定向到登录
检查下面的render
方法或从源代码检查它以了解发生了什么。 当抛出未经授权的异常时,我们告诉检查请求类型,如果它来自 API 请求,我们将发送带有 401 状态代码的 json 响应。 所以从前端知道我们可以在看到 401 状态代码后将用户重定向到登录页面。
从源头
/**
* 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);
}
编辑后
预期的method()
仅用于 Web 路由,因为它使用 session 来提取预期的路由或手动传递的值。 这是预期的() 方法。
/**
* 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 参数以阻止 XSS 之类的东西。 最好发送一些值并将其映射到 url。 喜欢
[ //like is mapping //comments/like is the actual url 'like' => 'comments/like' ]
然后,从数组中获取映射 url 或使用前端映射。
您可以在RedirectIfAuthenticated.php 中进行更改以区分Ajax调用和正常登录,如下所示:
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);
}
}
更新:
另一种解决方案是从您的路由中删除Auth中间件。 在APIController@set_like函数中手动登录用户,触发 like & return json 响应。
如果一个按钮不是给客人的,那么你不应该在页面上呈现它。 相反,您应该呈现一个登录链接,然后如果用户登录,您会将他重定向回他之前的位置。 现在,用户可以看到并单击该按钮。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.