.crossbar 平级目录中添加 authenticator.py 用来操作 crossbar 的认证, 客户端 crossbar 连接输入的用户名密码在这个文件里进行动态认证
from pprint import pprint
from twisted.internet.defer import inlineCallbacks
from autobahn.twisted.wamp import ApplicationSession
from autobahn.wamp.exception import ApplicationError
# crossbar "database"
USERDB = {
'frontend': { # 用户名
'secret': '123456', # 密码
'role': 'frontend' # 角色
},
'backend': {
'authid': 'ID10001',
'secret': '111111',
'role': 'backend'
}
}
class AuthenticatorSession(ApplicationSession):
@inlineCallbacks
def onJoin(self, details):
def authenticate(realm, authid, details):
print("WAMP-CRA dynamic authenticator invoked: realm='{}', authid='{}'".format(realm, authid))
if authid in USERDB:
return USERDB[authid]
else:
raise ApplicationError(u'com.example.no_such_user', 'could not authenticate session - no such user {}'.format(authid))
try:
yield self.register(authenticate, u'com.example.authenticate')
print("WAMP-CRA dynamic authenticator registered!")
except Exception as e:
print("Failed to register dynamic authenticator: {0}".format(e))
修改 .crossbar 文件夹下的 config.json 文件, 默认是 anonymous 配置,再 roles 节点里面修改,添加 authenticator 认证管理 e.g.
...
"realms": [
{
"name": "realm1",
"roles": [
{
"name": "authenticator",
"permissions": [
{
"uri": "com.example.authenticate",
"match": "exact",
"allow": {
"call": false,
"register": true,
"publish": false,
"subscribe": false
},
"disclose": {
"caller": false,
"publisher": false
},
"cache": true
}
]
},
{
"name": "backend",
"permissions": [
{
"uri": "",
"match": "prefix",
"allow": {
"call": true,
"register": true,
"publish": true,
"subscribe": true
},
"disclose": {
"caller": false,
"publisher": false
},
"cache": true
}
]
},
{
"name": "frontend",
"permissions": [
{
"uri": "com.example.add2",
"match": "exact",
"allow": {
"call": true,
"register": false,
"publish": false,
"subscribe": false
},
"disclose": {
"caller": false,
"publisher": false
},
"cache": true
}
]
}
]
}
],
"transports": [
{
"type": "web",
"endpoint": {
"type": "tcp",
"port": 8080
},
"paths": {
"/": {
"type": "static",
"directory": "../web"
},
"ws": {
"type": "websocket",
"auth": {
"wampcra": {
"type": "dynamic",
"authenticator": "com.example.authenticate"
}
}
}
}
}
],
"components": [
{
"type": "class",
"classname": "authenticator.AuthenticatorSession",
"realm": "realm1",
"role": "authenticator"
}
]
...
"name": "backend" 角色为后端,配置权限
"match": "prefix" 设置 uri 的匹配规则。 prefix matching 前缀匹配
{
"name": "backend",
"permissions": [
{
"uri": "",
"match": "prefix",
"allow": {
"call": true,
"register": true,
"publish": true,
"subscribe": true
},
"disclose": {
"caller": false,
"publisher": false
},
"cache": true
}
]
}
设置 websocket 认证方式, auth 中配置 wampcra 模式,类型为 dynamic
"ws": {
"type": "websocket",
"auth": {
"wampcra": {
"type": "dynamic",
"authenticator": "com.example.authenticate"
}
}
}
"name" : "authenticator" 启动crossbar 挂载的 component
"components": [
{
"type": "class",
"classname": "authenticator.AuthenticatorSession",
"realm": "realm1",
"role": "authenticator"
}
]
crossbar 客户端连接添加user和key
backend 角色 python 例子 e.g.
import os
import sys
from twisted.internet import reactor
from twisted.internet.defer import inlineCallbacks
from autobahn.twisted.wamp import ApplicationSession
from autobahn.wamp.types import PublishOptions
from autobahn.wamp import auth
USER = u'backend'
USER_SECRET = u'111111'
class ClientSession(ApplicationSession):
def onConnect(self):
self.join(self.config.realm, [u"wampcra"], USER)
def onChallenge(self, challenge):
if challenge.method == u"wampcra":
if u'salt' in challenge.extra:
key = auth.derive_key(USER_SECRET,
challenge.extra['salt'],
challenge.extra['iterations'],
challenge.extra['keylen'])
else:
key = USER_SECRET
signature = auth.compute_wcs(key, challenge.extra['challenge'])
return signature
else:
raise Exception("Invalid authmethod {}".format(challenge.method))
@inlineCallbacks
def onJoin(self, details):
def add2(x, y):
print("add2() called with {} and {}".format(x, y))
return x + y
try:
reg = yield self.register(add2, u'com.example.add2')
print("procedure add2() registered")
except Exception as e:
print("could not register procedure: {}".format(e))
try:
reg = yield self.register(add2, u'com.example.wewobackend.test')
print("wewobackend.test registered")
except Exception as e:
print("wewobackend.test could not register procedure: {}".format(e))
def onLeave(self, details):
print("Client session left: {}".format(details))
self.disconnect()
def onDisconnect(self):
reactor.stop()
if __name__ == '__main__':
from autobahn.twisted.wamp import ApplicationRunner
runner = ApplicationRunner(url=u'ws://localhost:8080/ws', realm=u'realm1')
runner.run(ClientSession)