使用 java 客户端验证 laravel 中的私人频道时出现问题
Problem with authenticating private channels in laravel with java client
我想从服务器(使用 laravel)向客户端(使用 java)发送广播消息。
我在用什么
- Pusher 作为广播驱动程序。
- laravel 用于 api 身份验证的护照。
我在服务器端做了什么
- 我已经在
.env
文件中配置了我的 Pusher 凭据。
- 取消注释
config/app.php
文件中的 App\Providers\BroadcastServiceProvider::class
行。
- 在
config/auth.php
文件中,我添加了以下内容:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'devices' => [
'driver' => 'session',
'provider' => 'devices',
],
'api' => [
'driver' => 'passport',
'provider' => 'devices',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
// using devices table to authenticate over api guard
'devices' => [
'driver' => 'eloquent',
'model' => App\Device::class,
],
],
- 在
App\Providers\BroadcastServiceProvider
class 中,我将以下内容添加到 boot()
函数中:
Broadcast::routes(['prefix' => 'api', 'middleware' => 'auth:api']);
- 在
routes/channels.php
中我添加了以下内容:
Broadcast::channel('device.{device_id}', function ($device, $device_id) {
return $device->id === $device_id;
});
- 通过 运行
php artisan make:event AdvertisementAdded
创建了一个事件 AdvertisementAdded
,添加了 implements ShouldBroadcast
,然后将以下内容添加到其 broadcastOn()
方法中:
return new PrivateChannel('device.'.$this->device_id);
我在客户端做了什么
因为我现在只是在测试,所以我通过邮递员
发送登录请求得到了我的access_token
和device_id
我将该 accessToken 复制到我的 java 客户端并将其作为 String
存储在 accessToken
变量中,代码如下:
String accessToken = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImY3ZTVlMTAzZWE3MzJjMTI5NzY1YTliMmMzOTM0N2ZhOGE4OTU5MjRjNDA5ZjgyOTA4ZDg5NTFjZTBkOGZlNTA2M2M1YTI1MDBlOTdhZDdiIn0.eyJhdWQiOiIxIiwianRpIjoiZjdlNWUxMDNlYTczMmMxMjk3NjVhOWIyYzM5MzQ3ZmE4YTg5NTkyNGM0MDlmODI5MDhkODk1MWNlMGQ4ZmU1MDYzYzVhMjUwMGU5N2FkN2IiLCJpYXQiOjE1NTkwOTYyNDgsIm5iZiI6MTU1OTA5NjI0OCwiZXhwIjoxNTkwNzE4NjQ3LCJzdWIiOiI3Iiwic2NvcGVzIjpbXX0.FKeE9Z-wv2yUNQPl-qsbu9baYGTdbQ6DuzaI1R8azR6l1CIP9uRI4hCaoWvgx0GXWWLPRNhfQl-YD3KP2YOraW16-h4ie_95B9VQrpFxXnlqKojsfh1xSrSNSl5HncslMWQPVjoesBpM5y_cpG19PGgu-SWo0W6s9Fiz_Nm70oyyZB9mSqU8PVQvAOSNr6TMR0aC3iMLFfkyZkTSwj8EoRyD2LGW6v4PFriqx8JLbZASCOiUYBlYnunWrTFDOAenZcoa5Sw7u7kbSvYehjDKRwKjQM6zmPfi0A3Mp0CHjHE599OXb-NG2IMH-wmlT0vEZjP2U97hxmsNW1RtHNXWaRKFL9T-WVmZbJf3fH5hXqTv495L3MQfq_m5YFHyc5NuIqK4K4xMJB956a33ICnH8DmvPmJgderNAhqEX1JHUAsR63K7xbZxRBDS8OlQYcEf-_v75X0kT1s067enSvI8Vs212AVnI6k0FmgQNM8DfJUq6YduD0m2F2ZWpKPrwdd6PdW5ZlZTEv-D8dYIEQ_CwOWohNoENATmTqxDpPBxK5c723MEt8S7Sa9MEGAo56HW3-9pbazbEdY1GqPWKVkov7K_6eBFcWsV67AgJpoKFt6RiBfRvokgiH96WG89qBB_Ucpm8uBahX93FaOXhVLW0VjJH2LQKrGw0bb5LS8Ql5o";
String deviceId = "7";
Map<String, String> authHeaders = new HashMap();
authHeaders.put("Authorization", accessToken);
HttpAuthorizer authorizer = new HttpAuthorizer("http://localhost:8000/api/broadcasting/auth");
authorizer.setHeaders(authHeaders);
PusherOptions options = new PusherOptions();
options.setAuthorizer(authorizer).setCluster(PUSHER_CLUSTER);
Pusher pusher = new Pusher(PUSHER_APP_KEY, options);
pusher.subscribePrivate("private-device." + deviceId, new PrivateChannelEventListener() {
@Override
public void onEvent(String channelName, String eventName, final String data) {
System.out.println(String.format("Received event on channel [%s]", channelName));
}
@Override
public void onSubscriptionSucceeded(String string) {
System.out.println(String.format("Subscribed to channel [%s]", string));
}
@Override
public void onAuthenticationFailure(String string, Exception excptn) {
System.out.println(string);
}
});
pusher.connect(new ConnectionEventListener() {
@Override
public void onConnectionStateChange(ConnectionStateChange change) {
System.out.println("State changed to " + change.getCurrentState() +
" from " + change.getPreviousState());
}
@Override
public void onError(String message, String code, Exception e) {
System.out.println("There was a problem connecting!");
}
});
// Keeping main thread alive
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
当运行上面的代码时,它在控制台输出如下:
State changed to CONNECTING from DISCONNECTED
State changed to CONNECTED from CONNECTING
java.io.IOException: Server returned HTTP response code: 403 for URL: http://localhost:8000/api/broadcasting/auth
我确定 auth:api
中间件在处理其他请求时按我预期的方式工作。
这是我的 routes/api.php
的片段:
Route::middleware('auth:api')->group(function () {
Route::prefix('advertisements')->group(function () {
Route::get('/request', 'AdvertisementsController@getDeviceAdvertisements')
->name('advertisements.getDeviceAdvertisements');
});
});
这是邮递员对该路由的测试(使用与上述相同的访问令牌):
这里是对来自邮递员的 api/broadcasting/auth
路由的测试(使用与上述相同的访问令牌):
有什么问题吗?为什么 auth:api
中间件下的所有 api 路由都能正常工作,但 api/broadcasting/auth
路由不能正常工作??
备注
我尝试使用 public 个频道没有问题。
找了一整天,终于解决了
授权通道时发生错误,而不是使用 auth:api
中间件验证请求时发生错误。
我在 routes/channels.php
中的私人频道授权函数总是 returns false
意味着它将拒绝对 private-device.{device_id}
频道的所有订阅请求:
Broadcast::channel('device.{device_id}', function ($device, $device_id) {
// this always return false, because of inequality of types
return $device->id === $device_id;
});
上面的授权函数总是return false
,因为$device->id
(类型int
)和$device_id
(类型类型为 string
).
所以,为了解决这个问题,我将它们都转换为int
,然后检查是否相等。
这是我用来解决问题的代码:
Broadcast::channel('device.{device_id}', function ($device, $device_id) {
return (int) $device->id === (int) $device_id;
});
我想从服务器(使用 laravel)向客户端(使用 java)发送广播消息。
我在用什么
- Pusher 作为广播驱动程序。
- laravel 用于 api 身份验证的护照。
我在服务器端做了什么
- 我已经在
.env
文件中配置了我的 Pusher 凭据。 - 取消注释
config/app.php
文件中的App\Providers\BroadcastServiceProvider::class
行。 - 在
config/auth.php
文件中,我添加了以下内容:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'devices' => [
'driver' => 'session',
'provider' => 'devices',
],
'api' => [
'driver' => 'passport',
'provider' => 'devices',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
// using devices table to authenticate over api guard
'devices' => [
'driver' => 'eloquent',
'model' => App\Device::class,
],
],
- 在
App\Providers\BroadcastServiceProvider
class 中,我将以下内容添加到boot()
函数中:
Broadcast::routes(['prefix' => 'api', 'middleware' => 'auth:api']);
- 在
routes/channels.php
中我添加了以下内容:
Broadcast::channel('device.{device_id}', function ($device, $device_id) {
return $device->id === $device_id;
});
- 通过 运行
php artisan make:event AdvertisementAdded
创建了一个事件AdvertisementAdded
,添加了implements ShouldBroadcast
,然后将以下内容添加到其broadcastOn()
方法中:
return new PrivateChannel('device.'.$this->device_id);
我在客户端做了什么
因为我现在只是在测试,所以我通过邮递员
发送登录请求得到了我的access_token
和device_id
我将该 accessToken 复制到我的 java 客户端并将其作为 String
存储在 accessToken
变量中,代码如下:
String accessToken = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImY3ZTVlMTAzZWE3MzJjMTI5NzY1YTliMmMzOTM0N2ZhOGE4OTU5MjRjNDA5ZjgyOTA4ZDg5NTFjZTBkOGZlNTA2M2M1YTI1MDBlOTdhZDdiIn0.eyJhdWQiOiIxIiwianRpIjoiZjdlNWUxMDNlYTczMmMxMjk3NjVhOWIyYzM5MzQ3ZmE4YTg5NTkyNGM0MDlmODI5MDhkODk1MWNlMGQ4ZmU1MDYzYzVhMjUwMGU5N2FkN2IiLCJpYXQiOjE1NTkwOTYyNDgsIm5iZiI6MTU1OTA5NjI0OCwiZXhwIjoxNTkwNzE4NjQ3LCJzdWIiOiI3Iiwic2NvcGVzIjpbXX0.FKeE9Z-wv2yUNQPl-qsbu9baYGTdbQ6DuzaI1R8azR6l1CIP9uRI4hCaoWvgx0GXWWLPRNhfQl-YD3KP2YOraW16-h4ie_95B9VQrpFxXnlqKojsfh1xSrSNSl5HncslMWQPVjoesBpM5y_cpG19PGgu-SWo0W6s9Fiz_Nm70oyyZB9mSqU8PVQvAOSNr6TMR0aC3iMLFfkyZkTSwj8EoRyD2LGW6v4PFriqx8JLbZASCOiUYBlYnunWrTFDOAenZcoa5Sw7u7kbSvYehjDKRwKjQM6zmPfi0A3Mp0CHjHE599OXb-NG2IMH-wmlT0vEZjP2U97hxmsNW1RtHNXWaRKFL9T-WVmZbJf3fH5hXqTv495L3MQfq_m5YFHyc5NuIqK4K4xMJB956a33ICnH8DmvPmJgderNAhqEX1JHUAsR63K7xbZxRBDS8OlQYcEf-_v75X0kT1s067enSvI8Vs212AVnI6k0FmgQNM8DfJUq6YduD0m2F2ZWpKPrwdd6PdW5ZlZTEv-D8dYIEQ_CwOWohNoENATmTqxDpPBxK5c723MEt8S7Sa9MEGAo56HW3-9pbazbEdY1GqPWKVkov7K_6eBFcWsV67AgJpoKFt6RiBfRvokgiH96WG89qBB_Ucpm8uBahX93FaOXhVLW0VjJH2LQKrGw0bb5LS8Ql5o";
String deviceId = "7";
Map<String, String> authHeaders = new HashMap();
authHeaders.put("Authorization", accessToken);
HttpAuthorizer authorizer = new HttpAuthorizer("http://localhost:8000/api/broadcasting/auth");
authorizer.setHeaders(authHeaders);
PusherOptions options = new PusherOptions();
options.setAuthorizer(authorizer).setCluster(PUSHER_CLUSTER);
Pusher pusher = new Pusher(PUSHER_APP_KEY, options);
pusher.subscribePrivate("private-device." + deviceId, new PrivateChannelEventListener() {
@Override
public void onEvent(String channelName, String eventName, final String data) {
System.out.println(String.format("Received event on channel [%s]", channelName));
}
@Override
public void onSubscriptionSucceeded(String string) {
System.out.println(String.format("Subscribed to channel [%s]", string));
}
@Override
public void onAuthenticationFailure(String string, Exception excptn) {
System.out.println(string);
}
});
pusher.connect(new ConnectionEventListener() {
@Override
public void onConnectionStateChange(ConnectionStateChange change) {
System.out.println("State changed to " + change.getCurrentState() +
" from " + change.getPreviousState());
}
@Override
public void onError(String message, String code, Exception e) {
System.out.println("There was a problem connecting!");
}
});
// Keeping main thread alive
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
当运行上面的代码时,它在控制台输出如下:
State changed to CONNECTING from DISCONNECTED
State changed to CONNECTED from CONNECTING
java.io.IOException: Server returned HTTP response code: 403 for URL: http://localhost:8000/api/broadcasting/auth
我确定 auth:api
中间件在处理其他请求时按我预期的方式工作。
这是我的 routes/api.php
的片段:
Route::middleware('auth:api')->group(function () {
Route::prefix('advertisements')->group(function () {
Route::get('/request', 'AdvertisementsController@getDeviceAdvertisements')
->name('advertisements.getDeviceAdvertisements');
});
});
这是邮递员对该路由的测试(使用与上述相同的访问令牌):
这里是对来自邮递员的 api/broadcasting/auth
路由的测试(使用与上述相同的访问令牌):
有什么问题吗?为什么 auth:api
中间件下的所有 api 路由都能正常工作,但 api/broadcasting/auth
路由不能正常工作??
备注
我尝试使用 public 个频道没有问题。
找了一整天,终于解决了
授权通道时发生错误,而不是使用 auth:api
中间件验证请求时发生错误。
我在 routes/channels.php
中的私人频道授权函数总是 returns false
意味着它将拒绝对 private-device.{device_id}
频道的所有订阅请求:
Broadcast::channel('device.{device_id}', function ($device, $device_id) {
// this always return false, because of inequality of types
return $device->id === $device_id;
});
上面的授权函数总是return false
,因为$device->id
(类型int
)和$device_id
(类型类型为 string
).
所以,为了解决这个问题,我将它们都转换为int
,然后检查是否相等。
这是我用来解决问题的代码:
Broadcast::channel('device.{device_id}', function ($device, $device_id) {
return (int) $device->id === (int) $device_id;
});