如何在 socket.io 聊天中区分 Symfony 用户 roles/groups
How to differentiate between Symfony user roles/groups in socket.io chat
我一直在玩 socket.io 的聊天,我有一个问题:如何区分聊天室中的管理员用户和普通用户?我希望管理员拥有踢人和禁止他人的权力,但我的用户没有。
我正在使用 Symfony 开发我的应用程序,我想将其用户数据库用于聊天用户。我正在为我的 Symfony 应用程序的用户使用 FOSUserBundle。他们被分成多个组,所以我有 admin
组,还有其他组。
admin
组有 ROLE_ADMIN
,这意味着其中的每个用户都具有该角色。那是管理员组,该组中的每个用户都应该有权禁止、踢出、静音等聊天室中的其他用户。
为了在聊天中使用我的 Symfony 用户,我一直在阅读 Redis 以获得他们的会话,但我不确定如何区分我的管理员用户和普通用户。如何防止普通用户向服务器发出用户无法访问的请求?因为任何人都可以发出请求,但是 如果这些请求来自存储在 Apache 服务器上的 MySQL 数据库中的用户,我如何验证 这些请求?
如果不是 Symfony,如何在常规 PHP 应用程序中完成此操作?说到底admin是怎么定义的并不重要,重要的是如何将他连接到Node服务器上,以及如何让Node服务器和我的用户数据库一起工作。
我有一个简单的想法,将用户的数据加密并发送到节点服务器,然后在那里解密。只有这两个服务器知道私钥,所以即使一个客户端得到了加密数据,他也不能向另一个客户端发出请求。我可能会做一些 IP 检查和时间戳。然后可以使用节点服务器上的解密数据来判断用户是否是管理员,并允许他发送某些请求。这是个好主意还是有更好的方法?
我通常会创建一个 SecurityAccessManager
服务来通过 voters 调用来检查用户的角色(如果需要,我可以提供一个示例)来检查特定权限,例如 "is this user can update this specific post?"
配置
company.navigation.security_access:
class: Company\NavigationBundle\Services\SecurityAccessManager
arguments:
- @security.authorization_checker
- @security.token_storage
服务代码
namespace Company\NavigationBundle\Services;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
class SecurityAccessManager
{
private $authorizationChecker;
private $tokenStorage;
private $debug;
public function __construct(
AuthorizationCheckerInterface $authorizationChecker,
TokenStorage $tokenStorage)
{
$this->authorizationChecker = $authorizationChecker;
$this->tokenStorage = $tokenStorage;
$this->debug = true;
}
// *************************************************************************
// User
// *************************************************************************
public function getUser()
{
return $this->tokenStorage->getToken()->getUser();
}
public function getUserId()
{
return $this->tokenStorage->getToken()->getUser()->getId();
}
public function isAuthenticatedUser()
{
return $this->authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED');
}
// *************************************************************************
// Roles checker
// *************************************************************************
public function isAdmin()
{
if($this->authorizationChecker->isGranted('ROLE_ADMIN') !== true) {
return false;
} else {
return true;
}
}
public function checkRightAdmin()
{
if($this->authorizationChecker->isGranted('ROLE_ADMIN') !== true) {
throw new AccessDeniedException('Unauthorised access! '.($this->debug ? __FUNCTION__ : null));
}
return true;
}
public function checkUserHasRightToEditPost($postId)
{
// Check if user has right to modify the post
if ($this->authorizationChecker->isGranted('is_user_has_right_to_edit_post', $postId) === false) {
throw new AccessDeniedException('Unauthorised access! '.($this->debug ? __FUNCTION__ : null));
}
return true;
}
}
然后,在您的控制器操作中,您可以检查用户的权限
namespace Company\YourBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class YourBunbleController extends Controller
{
/**
* Get the service
* @return \Company\NavigationBundle\Services\SecurityAccessManager
*/
private function getService()
{
return $this->get('company.navigation.security_access');
}
public function updatePostAction(Request $request, $postId)
{
// Throw 403 if user has no admin rights
$this->getService()->checkRightAdmin();
// Throw 403 if user has no rights to update the post
$this->getService()->checkUserHasRightToEditPost();
//OK, you can update database
...
}
}
I had an idea of simply encrypting and sending the user's data to the node server, then decrypt it there. Only the two servers know the private keys, so even if a client gets its hands on the encrypted data, he can't make a request with it for another client.
这是基本思路。
我会怎么做?
我会使用 JWT 之类的东西将 userId 发送到节点应用程序。不一定要加密,因为我只关心jwt签名,确保请求确实是由真实用户发出的。
之后,我将使用 userId 对 php 应用程序进行 服务器端 调用以检查用户的角色。
详细说明:
- 节点应用程序和 php 应用程序将使用共享密钥来签署 JWT 令牌。
- PHP 应用程序会将生成的令牌公开给前端。
- socket.io 客户端会将令牌作为身份验证的一部分发送到节点应用程序。
如何处理封禁
- 使用用户 ID 保存打开的套接字列表
- 在 nodejs 应用程序中创建一个网络服务端点,它可以处理来自 php 应用程序的 "ban" 请求。
- 当nodejs应用程序收到这样的请求时,根据userid查找socket并关闭连接。
我一直在玩 socket.io 的聊天,我有一个问题:如何区分聊天室中的管理员用户和普通用户?我希望管理员拥有踢人和禁止他人的权力,但我的用户没有。
我正在使用 Symfony 开发我的应用程序,我想将其用户数据库用于聊天用户。我正在为我的 Symfony 应用程序的用户使用 FOSUserBundle。他们被分成多个组,所以我有 admin
组,还有其他组。
admin
组有 ROLE_ADMIN
,这意味着其中的每个用户都具有该角色。那是管理员组,该组中的每个用户都应该有权禁止、踢出、静音等聊天室中的其他用户。
为了在聊天中使用我的 Symfony 用户,我一直在阅读 Redis 以获得他们的会话,但我不确定如何区分我的管理员用户和普通用户。如何防止普通用户向服务器发出用户无法访问的请求?因为任何人都可以发出请求,但是 如果这些请求来自存储在 Apache 服务器上的 MySQL 数据库中的用户,我如何验证 这些请求?
如果不是 Symfony,如何在常规 PHP 应用程序中完成此操作?说到底admin是怎么定义的并不重要,重要的是如何将他连接到Node服务器上,以及如何让Node服务器和我的用户数据库一起工作。
我有一个简单的想法,将用户的数据加密并发送到节点服务器,然后在那里解密。只有这两个服务器知道私钥,所以即使一个客户端得到了加密数据,他也不能向另一个客户端发出请求。我可能会做一些 IP 检查和时间戳。然后可以使用节点服务器上的解密数据来判断用户是否是管理员,并允许他发送某些请求。这是个好主意还是有更好的方法?
我通常会创建一个 SecurityAccessManager
服务来通过 voters 调用来检查用户的角色(如果需要,我可以提供一个示例)来检查特定权限,例如 "is this user can update this specific post?"
配置
company.navigation.security_access:
class: Company\NavigationBundle\Services\SecurityAccessManager
arguments:
- @security.authorization_checker
- @security.token_storage
服务代码
namespace Company\NavigationBundle\Services;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
class SecurityAccessManager
{
private $authorizationChecker;
private $tokenStorage;
private $debug;
public function __construct(
AuthorizationCheckerInterface $authorizationChecker,
TokenStorage $tokenStorage)
{
$this->authorizationChecker = $authorizationChecker;
$this->tokenStorage = $tokenStorage;
$this->debug = true;
}
// *************************************************************************
// User
// *************************************************************************
public function getUser()
{
return $this->tokenStorage->getToken()->getUser();
}
public function getUserId()
{
return $this->tokenStorage->getToken()->getUser()->getId();
}
public function isAuthenticatedUser()
{
return $this->authorizationChecker->isGranted('IS_AUTHENTICATED_REMEMBERED');
}
// *************************************************************************
// Roles checker
// *************************************************************************
public function isAdmin()
{
if($this->authorizationChecker->isGranted('ROLE_ADMIN') !== true) {
return false;
} else {
return true;
}
}
public function checkRightAdmin()
{
if($this->authorizationChecker->isGranted('ROLE_ADMIN') !== true) {
throw new AccessDeniedException('Unauthorised access! '.($this->debug ? __FUNCTION__ : null));
}
return true;
}
public function checkUserHasRightToEditPost($postId)
{
// Check if user has right to modify the post
if ($this->authorizationChecker->isGranted('is_user_has_right_to_edit_post', $postId) === false) {
throw new AccessDeniedException('Unauthorised access! '.($this->debug ? __FUNCTION__ : null));
}
return true;
}
}
然后,在您的控制器操作中,您可以检查用户的权限
namespace Company\YourBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class YourBunbleController extends Controller
{
/**
* Get the service
* @return \Company\NavigationBundle\Services\SecurityAccessManager
*/
private function getService()
{
return $this->get('company.navigation.security_access');
}
public function updatePostAction(Request $request, $postId)
{
// Throw 403 if user has no admin rights
$this->getService()->checkRightAdmin();
// Throw 403 if user has no rights to update the post
$this->getService()->checkUserHasRightToEditPost();
//OK, you can update database
...
}
}
I had an idea of simply encrypting and sending the user's data to the node server, then decrypt it there. Only the two servers know the private keys, so even if a client gets its hands on the encrypted data, he can't make a request with it for another client.
这是基本思路。
我会怎么做? 我会使用 JWT 之类的东西将 userId 发送到节点应用程序。不一定要加密,因为我只关心jwt签名,确保请求确实是由真实用户发出的。
之后,我将使用 userId 对 php 应用程序进行 服务器端 调用以检查用户的角色。
详细说明:
- 节点应用程序和 php 应用程序将使用共享密钥来签署 JWT 令牌。
- PHP 应用程序会将生成的令牌公开给前端。
- socket.io 客户端会将令牌作为身份验证的一部分发送到节点应用程序。
如何处理封禁
- 使用用户 ID 保存打开的套接字列表
- 在 nodejs 应用程序中创建一个网络服务端点,它可以处理来自 php 应用程序的 "ban" 请求。
- 当nodejs应用程序收到这样的请求时,根据userid查找socket并关闭连接。