如何在每个会话基础上限制Autobahn Python订阅

1 投票
2 回答
708 浏览
提问于 2025-05-01 14:38

我在服务器端使用autobahnpython和twisted(wamp),在浏览器中使用autobahnjs。有没有简单的方法可以根据每个会话来允许或限制订阅?比如说,一个客户端不应该能够订阅与其他用户相关的话题。

虽然我没有使用crossbar.io,但我尝试了在这个页面末尾的“示例”部分中显示的Python代码,http://crossbar.io/docs/Authorization/,其中首先通过RPC调用来给客户端授权。当然,我使用的是我自己的授权逻辑。一旦授权成功,我想让客户端有权订阅仅与该客户端相关的话题,比如'com.example.user_id'。我的问题是,即使授权通过,我也没有找到在ApplicationSession类中限制订阅请求的方法,而这个类就是进行授权的地方。我该如何防止一个用户ID为user_a的客户端订阅'com.example.user_b'的话题呢?

暂无标签

2 个回答

0

我找到了一种相对简单的解决方案,使用了一个Node的客人。下面是代码:

    // crossbar setup
var autobahn = require('autobahn');

var connection = new autobahn.Connection({
        url: 'ws://127.0.0.1:8080/ws',
        realm: 'realm1'
    }
);

// Websocket to Scratch setup
// pull in the required node packages and assign variables for the entities
var WebSocketServer = require('websocket').server;
var http = require('http');

var ipPort = 1234; // ip port number for Scratch to use

// this connection is a crossbar connection
connection.onopen = function (session) {

    // create an http server that will be used to contain a WebSocket server
    var server = http.createServer(function (request, response) {
        // We are not processing any HTTP, so this is an empty function. 'server' is a wrapper for the
        // WebSocketServer we are going to create below.
    });

    // Create an IP listener using the http server
    server.listen(ipPort, function () {
        console.log('Webserver created and listening on port ' + ipPort);
    });

    // create the WebSocket Server and associate it with the httpServer
    var wsServer = new WebSocketServer({
        httpServer: server
    });

    // WebSocket server has been activated and a 'request' message has been received from client websocket
    wsServer.on('request', function (request) {
        // accept a connection request from Xi4S
        //myconnection is the WS connection to Scratch
        myconnection = request.accept(null, request.origin); // The server is now 'online'

        // Process Xi4S messages
        myconnection.on('message', function (message) {

            console.log('message received: ' + message.utf8Data);
            session.publish('com.serial.data', [message.utf8Data]);

            // Process each message type received
            myconnection.on('close', function (myconnection) {
                console.log('Client closed connection');
                boardReset();
            });
        });
    });
};

connection.open();
0

你可以通过创建自己的路由器来进行授权。要做到这一点,你需要继承 Router() 类,并至少重写 authorize() 方法:

def authorize(self, session, uri, action):
    return True

这个方法其实很简单,如果你返回 True,那么这个会话就被授权去做它想做的事情。你可以制定一个规则,比如所有的订阅都必须以 'com.example.USER_ID' 开头。那么,你的 Python 代码会把网址分开,取出第三个部分,然后和当前的会话 ID 比较,如果匹配就返回 True,不匹配就返回 False。不过,这里有点复杂。我有一段代码做了类似的事情,下面是我的 authorize() 方法:

@inlineCallbacks
def authorize(self, session, uri, action):
    authid = session._authid
    if authid is None:
        authid = 1
    log.msg("AuthorizeRouter.authorize: {} {} {} {} {}".format(authid,
        session._session_id, uri, IRouter.ACTION_TO_STRING[action], action))
    if authid != 1:
        rv = yield self.check_permission(authid, uri, IRouter.ACTION_TO_STRING[action])
    else:
        rv = yield True

    log.msg("AuthorizeRouter.authorize: rv is {}".format(rv))

    if not uri.startswith(self.svar['topic_base']):
        self.sessiondb.activity(session._session_id, uri, IRouter.ACTION_TO_STRING[action], rv)

    returnValue(rv)

    return

注意,我深入会话中获取 _authid,这样做可能不太好(我觉得),因为我不应该查看这些私有变量。不过我也不知道还有哪里能获取它。

另外要提的是,这和身份验证是密切相关的。在我的实现中,_authid 是经过认证的用户 ID,这个和 Unix 用户 ID 类似(是一个正整数,且唯一)。我很确定这个可以是任何东西,比如字符串,所以如果你想用 'user_b' 作为 _auth_id 也是可以的。

-g

撰写回答