Advertisement
Guest User

Untitled

a guest
Apr 17th, 2019
204
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.59 KB | None | 0 0
  1. Я задавал вопрос насчет архитектуры БД, а теперь я сформулировал вопрос насчет архитектуры сервиса сообщений.
  2.  
  3. Сервис сообщений будет полагаться на протокол wamp и на шаблон pub/sub. В обычной ситуации, когда мы отправляем запрос через http, мы отправляем запрос к серверу, сервер валидирует данные, делает что-то ещё (например сохраняет в БД) и затем отправляет ответ. Роутер wamp такое поведение не предусматривает и просто перенаправляет сообщения между клиентами.
  4. Значит, нужно на серверной стороне написать такой клиент, который будет подписываться на [u]все сообщения[/u], валидировать их, сохранять в БД, а затем только перенаправлять клиенту пользователя.
  5.  
  6. Т.е. Алиса публикует сообщение по uri server.message.to.bob, сервер валидирует его и делает публикацию на client.message.to.bob.
  7.  
  8. Ситуация очень не типична. Судя по всему, даже нельзя вернуть клиенту ошибку об [i]собственной ошибке[/i] (прим. ошибка валидации). Это совсем отлично от RESTful API. Как лучше написать архитектуру чтобы она была понятна другим разработчикам?
  9.  
  10. Я планировал это сделать просто. Создать скрипт (который будет реквайриться сервером или отдельно через консоль как демон), который будет подписываться на все сообщения.
  11.  
  12. Messenger.js
  13.  
  14. var autobahn = require('autobahn');
  15.  
  16. var connection = new autobahn.Connection({
  17. ...
  18. });
  19.  
  20. connection.onopen = function(session) {
  21.  
  22. session.subscribe('server.message', function(m) {
  23. let message = new Message(...) //серилиазируем сообщение
  24.  
  25. message.validate(); // в случае ошибки нельзя вернуть ответ клиенту
  26.  
  27. session.publish(`client.message.to.${message.to}`); // Ничего страшного если сделать публикацию не дожидаясь сохранения в БД, чтобы повысить скорость?
  28.  
  29. message.save();
  30. }, { match: "prefix" }); //"prefix" говорит о том что нужно подписаться на все совпадения с префиксом server.message
  31.  
  32. //Кто-то кому-то пишет
  33. session.subscribe('server.writing', function(w) {
  34. //валидируем что пользователь может вообще писать другому пользователю...
  35.  
  36. session.publish(`client.writing.to.${w.to}`);
  37. }, { match: "prefix" }); //"prefix" говорит о том что нужно подписаться на все совпадение с префиксом server.message
  38.  
  39. };
  40.  
  41. connection.open();
  42.  
  43. Или, я не понимаю, wamp должен только "уведомить" что кто-то отправил сообщение, а клиент должен сам сделать запрос к серверу чтобы получить сообщения? Не будет ли это слишком медленно? Мне не нравится такой подход - в чем смысл по два раза делать запрос, гонять трафик, создавать лишнюю нагрузку?
  44.  
  45. Наверно, для такого случая конечно лучше использовать микросервисы(?) написанные на Питоне, которые можно встроить в роутер https://crossbar.io/docs/Router-Components/ а не скрипты на ноде.
  46.  
  47.  
  48. Следующий вопрос...
  49.  
  50. Чтобы авторизовать публикации для клиентов %%напомню что они могут приходить только от сервера%%, нужно воспользоваться встроенным в роутер механизмом - функции динамической авторизации. Которая, принимает в качестве аргументов данные сессии (роль, дополнительные данные авторизации, которые предоставляются самим клиентом
  51. к прим. jwt), uri по которому происходит действие, и само действия (публикация или подписка) и ещё опции этого действия (пример { match: "prefix" }). В ответ эта функция должна вернуть разрешено или нет совершать это действие.
  52.  
  53. https://crossbar.io/docs/Authorization/#dynamic-authorization
  54.  
  55. >The method must accept three arguments: (session, uri, action, options) and must return a dict with the following keys...
  56.  
  57. Нужно чтобы для каждого (для n-ого количества) uri и действия была своя проверка.
  58.  
  59. К примеру,
  60.  
  61. 1. Пользователь может только сделать публикацию на сервер
  62. 2. Пользователь может только подписаться на относящиеся к нему публикации с сервера
  63. 3. Сервер может подписаться на относящиеся к нему публикации
  64. 4. Сервер может публиковать для пользователей данные
  65.  
  66. На практике, это выглядит ещё обширнее:
  67.  
  68. def authorize(session, uri, action, options):
  69.  
  70. if re.match('^server\.message\.to\.', uri) and action == 'publish':
  71. //проверяем токен и делаем всё остальное... и если всё ок - возвращаем True
  72. token = session['authextra']['Bearer token']
  73. payload = jwt.decode(token, JWT_SECRET)
  74. ...
  75. return True
  76.  
  77. if re.match('^client\.message\.to\.', uri) and action == 'subscribe':
  78. //делаем тоже самое...
  79.  
  80.  
  81. if re.match('^client\.message\.to\.', uri) and action == 'publish':
  82. // нужно проверить что это делает именно сервер
  83. // для этого я решил создать jwt со свойством isServer: true
  84. // как ещё надёжней сделать эту проверку?
  85. token = session['authextra']['Bearer token']
  86. payload = jwt.decode(token, JWT_SECRET)
  87. if 'isServer' in payload and payload['isServer']:
  88. ...
  89. return True
  90.  
  91.  
  92. if re.match('^server\.writing\.to\.', uri) and action == 'publish':
  93. //проверяем что пользователь присутствует в системе
  94. ...
  95. return True
  96.  
  97.  
  98. //и так далее, таких проверок может быть n-ое количество
  99.  
  100. return False // запрещаем всё во всех остальных случаях "default"
  101.  
  102.  
  103. Вопрос прост - Как вынести это n-ое количество проверок в отдельную архитектуру?
  104.  
  105.  
  106. [i]Спасибо большое...[/i]
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement