使用axios进行API请求时,与Laravel API一直未授权。

11

我正在使用Laravel 5.6和Axios库(标准的Laravel5.6软件包)进行个人项目开发。

我需要使用Laravel的API和axios的http请求发送GET请求,然后再发送POST请求。但是,由于它是一个仅为VueJS提供从数据库获取内容的内部API,因此我不使用Passport或任何类似的库。

如果我使用auth:api中间件设置我的API路由,无论请求类型如何,我总是会收到未经授权的响应,这是错误输出:

Error: Request failed with status code 401

错误信息:

message: "Unauthenticated."

但是,根据文档所述,axios头部信息是在laravel的bootstrap.js中设置的,以从meta标签中读取授权令牌(代码已在那里):

window.axios = require('axios');

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

// further down the file...
let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}

如果需要,以下是HTTP请求代码:

axios.post('/api/latest', formData)

那么,如果这些都已设置,为什么我还未经身份验证?

我尝试移除auth:api中间件,当然,它正常工作:

- Route::middleware('auth:api')->get('/latest', 'InternalApiController@latestEp');
+ Route::get('/latest', 'InternalApiController@latestEp');

我做错了什么?

3个回答

21

因为这是一个仅为VueJS提供从数据库获取信息的内部API,所以我不使用Passport或类似的库。

如果该API不是无状态的,也就是说已知用户已通过标准会话cookie登录,则可以仅对API路由使用默认的'web'中间件。

在默认的RouteServiceProvider中,将mapApiRoutes函数更改为使用web中间件:

protected function mapApiRoutes()
{
    Route::prefix('api')
        // ->middleware('api')
        ->middleware('web')
        ->namespace($this->namespace)
        ->group(base_path('routes/api.php'));
}

话虽如此,由于API路由默认没有受到限制,因此你真的应该将它们放在默认的'auth'中间件后面。

routes/api.php文件中:

Route::group(['middleware' => 'auth'], function() {
    Route::get('/latest', 'InternalApiController@latest');
});

如果你想确保它是一个 AJAX 请求,你可以创建一个简单的中间件来检查请求是否设置了 X-Requested-With 头,并且它的值为 XMLHttpRequest

class RequestIsAjax
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if (!$request->ajax()) {
            return redirect()->route('login.index');
        }

        return $next($request);
    }
}

将其注册在\App\Http\Kernel类中的$routeMiddleware数组中。

protected $routeMiddleware = [
    'ajax' => \App\Http\Middleware\RequestIsAjax::class,

即使我更改了代码,如果我在api.php中添加Route::middleware('auth:api')->get('/latest', 'InternalApiController@latest');,我仍然会收到相同的错误提示。 - K3nzie
@K3nzie,你仍在使用auth:api,它检查api身份验证守卫。只需使用middleware('auth')即可解决问题。 - Emile Bergeron
好的,我已经修复了,但是这样API端点仍然可以从Web访问,而我只想让它从Vue中使用,这可能吗? - K3nzie
1
@K3nzie 我添加了一个简单的 AJAX 检查中间件,可以帮助隐藏 API 端点,防止意外的浏览器导航。 - Emile Bergeron
1
运行得像魔法一样!你救了我。 - Ale Ponzo
显示剩余5条评论

2
使用 Laravel 8 时,我尝试从后端 API 请求数据时遇到了 401 错误。按照被接受的答案做了一些调整,但仍然无法解决问题。我认为这是因为我的控制面板位于子域名 users.mydomain.tld,而我使用 Axios 的主要域名为 mydomain.tld/some/path。问题在于会话 cookie 的路径。重新配置时,您需要清除所有 cookie(开发工具栏)。然后,在您进行更改后,像往常一样重新登录。否则,cookie 将会出错,您将无法查看修复情况或无法登录,直到您将其清除。

我撤销了我所做的所有更改(按照被接受的答案),并确定了 SESSION_DOMAIN 环境变量是关键因素,至少对于用户主要区域位于子域名的情况是如此。

在您的 .env 文件中:

SESSION_DOMAIN=".yourdomain.tld"

app/Providers/RouteServiceProvider.php文件中,在boot()方法中将api改为web:
Route::prefix('api')
    //->middleware('api')
    ->middleware('web')
    ->namespace($this->namespace)
    ->group(base_path('routes/api.php'));

routes/api.php 中:
Route::middleware('auth')->get('/user', function (Request $request) {
    return $request->user();
});

在您的resources/js/bootstrap.js文件中:
window.axios.defaults.withCredentials = true;

修改bootstrap.js文件后,需要再次运行npm run dev进行重新编译。


现在,您应该能够在前端JavaScript中使用Axios,无论您使用的是jQuery还是Vue等框架。

axios.get('/api/user')
    .then(response => console.dir(response.data))
    .catch(error => console.log(error));

我更惊讶的是,我三年前的问题仍然引起关注,哈哈,但很好知道!这是有用的信息。 - K3nzie

0

CSRF令牌与授权令牌不同。您很可能需要手动添加授权令牌,这通常类似于this,具体取决于您的授权方法。


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