You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Laravel Sanctum认证Pusher时出现401未授权错误求助

Laravel Sanctum + Pusher 401未授权问题解决方案

问题现象

使用Laravel Sanctum完成Pusher频道认证时,收到401未授权响应,错误信息如下:

[Error] Pusher :  : ["Error: Unable to retrieve auth string from channel-authorization endpoint - received status: 401 from http://localhost:8000/broadcasting/auth. Clients must be authorized to join private or presence channels. See: https://pusher.com/docs/channels/server_api/authorizing-users/"]

已配置BroadcastServiceProvider使用Sanctum认证守卫:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;

class BroadcastServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Broadcast::routes(['middleware' => ['auth:sanctum']]);

        require base_path('routes/channels.php');
    }
}

前端已传递X-CSRF-TOKEN头,尝试替换为Bearer格式的Authorization头后,问题仍未解决,前端代码如下:

import axios from '@/lib/axios'
import Echo from 'laravel-echo'
import Pusher from 'pusher-js'
import Cookies from 'js-cookie'

export default async function echo() {
    if (typeof window !== 'undefined') {
        Pusher.logToConsole = true

        // const csrf = () => axios.get('/sanctum/csrf-cookie')

        const key = '<redacted>'

        const pusherClient = new Pusher(key, {
            cluster: 'eu',
            forceTLS: true,
            channelAuthorization: {
                endpoint: 'http://localhost:8000/broadcasting/auth',
                headers: {
                    Accept: 'application/json',
                    'X-CSRF-TOKEN': Cookies.get('XSRF-TOKEN'),
                },
            },
        })

        window.Echo = new Echo({
            broadcaster: 'pusher',
            client: pusherClient,
        })

        window.Echo.private('chat').listen(
            'App\\Events\\PrivateMessageSent',
            e => {
                console.log(e)
            },
        )
    }
}

解决方案

1. 完善前端授权头配置

Sanctum需要Authorization: Bearer {token}头完成API请求认证,前端需将登录后获取的有效令牌加入Pusher的授权请求头:

// 替换为你实际存储令牌的键名(比如登录后存在Cookies或localStorage中的令牌)
const token = Cookies.get('auth_token'); 

const pusherClient = new Pusher(key, {
    cluster: 'eu',
    forceTLS: true,
    channelAuthorization: {
        endpoint: 'http://localhost:8000/broadcasting/auth',
        headers: {
            Accept: 'application/json',
            'X-CSRF-TOKEN': Cookies.get('XSRF-TOKEN'),
            'Authorization': `Bearer ${token}` // 新增Bearer令牌头
        },
    },
})

2. 校验Sanctum核心配置

  • 打开config/sanctum.php,确保stateful数组包含前端域名(本地开发需包含前端端口):
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost,127.0.0.1:8000,127.0.0.1:3000')),
  • 检查.env文件中SESSION_DOMAIN设置,本地开发可设为.localhost

3. 确认频道授权规则

打开routes/channels.php,确保chat私有频道的授权逻辑允许当前用户访问:

Broadcast::channel('chat', function ($user) {
    // 这里返回true表示允许用户加入频道,可根据业务需求添加自定义校验(比如用户权限)
    return true;
});

若返回false或未定义该频道的授权规则,会直接返回401。

4. 配置跨域支持

如果前后端跨域部署,需确保config/cors.php配置正确:

'paths' => ['api/*', 'sanctum/csrf-cookie', 'broadcasting/auth'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'], // 生产环境替换为具体前端域名
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,

注意supports_credentials必须设为true,否则跨域请求无法携带Cookies和Authorization头。

5. 确保用户已完成登录

Pusher频道授权需要用户处于登录状态,前端初始化Echo前需校验令牌是否存在:

export default async function echo() {
    if (typeof window !== 'undefined') {
        const token = Cookies.get('auth_token');
        if (!token) return; // 用户未登录则终止初始化

        Pusher.logToConsole = true
        // ... 后续初始化代码
    }
}

内容的提问来源于stack exchange,提问作者Richard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 01:55:16