Python RabbitMQ使用RPC的RESTful api授权

Python RabbitMQ使用RPC的RESTful api授权,python,flask,rabbitmq,Python,Flask,Rabbitmq,我以前使用flaskrestful和flaks auth(例如@auth.login\u required)构建RESTful api进行api授权。现在我将monolith服务拆分为几个微服务(例如api服务)。我尝试了amqpstorm和pika,因为我尝试使用RabbitMQ来实现同步RPC调用,以授权来自flask的api请求,并与gunicorn一起工作。RPC客户机确实向RPC服务器发送了请求,RPC服务器也完成了该任务,但RPC客户机未能通过回调获得响应,从而阻塞了请求。因此,fl

我以前使用
flaskrestful
flaks auth
(例如
@auth.login\u required
)构建RESTful api进行api授权。现在我将monolith服务拆分为几个微服务(例如api服务)。我尝试了
amqpstorm
pika
,因为我尝试使用RabbitMQ来实现同步RPC调用,以授权来自flask的api请求,并与gunicorn一起工作。RPC客户机确实向RPC服务器发送了请求,RPC服务器也完成了该任务,但RPC客户机未能通过回调获得响应,从而阻塞了请求。因此,flask请求没有响应。以下是一些代码片段,以
amqpstorm
为例

# Implementation of RPC server
import amqpstorm
from amqpstorm import Message

from config import AMQP_USER, AMQP_PASSWORD, AMQP_SERVER

AMQP_EXCHANGE = 'rpc-authorization'
QUEUE_STATISTICS = 'auth-statistics'
BINDING_STATISTICS = 'auth.statistics.*'

def on_request(message):
    msg = json.loads(s=message.body)
    print(' RPC server [received request] '.center(80, '#'), '\n',
          msg)
    # Some processing of verifying bearer token using Redis
    response = ProcessAuthZ.verify_bearer(msg=msg)
    print(' RPC server [finished job] '.center(80, '#'), '\n',
          response)
    dst_props = {'correlation_id': message.correlation_id}
    response = Message.create(channel=message.channel,
                              body=json.dumps(obj={'authZ': response}),
                              properties=dst_props)
    response.publish(routing_key=message.reply_to,
                     exchange=AMQP_EXCHANGE)
    message.ack()

if __name__ == '__main__':
    conn_broker = amqpstorm.Connection(hostname=AMQP_SERVER,
                                       username=AMQP_USER,
                                       password=AMQP_PASSWORD)
    channel = conn_broker.channel()

    channel.queue.declare(queue=QUEUE_STATISTICS)
    channel.basic.qos(prefetch_count=1)
    channel.basic.consume(callback=on_request,
                          queue=QUEUE_STATISTICS)
    channel.start_consuming()
考虑到api授权应该是同步的,而来自
flask
gunicorn
的请求应该是异步的,使用
RabbitMQ
RPC和
flask
的正确方法是什么

# Implementation of RPC client
from flask import request
import json
import amqpstorm
from amqpstorm import Message

from conf_rabbitmq import AMQP_USER, AMQP_PASSWORD, AMQP_SERVER

AMQP_EXCHANGE = 'rpc-authorization'
QUEUE_STATISTICS = 'auth-statistics'
BINDING_STATISTICS = 'auth.statistics.*'


class AuthZ(object):
    def __init__(self):
        self.host = AMQP_SERVER
        self.username = AMQP_USER
        self.password = AMQP_PASSWORD
        self.channel = None
        self.response = None
        self.connection = None
        self.callback_queue = None
        self.correlation_id = None
        self.open()

    def open(self):
        self.connection = amqpstorm.Connection(hostname=self.host,
                                               username=self.username,
                                               password=self.password)

        self.channel = self.connection.channel()

        result = self.channel.queue.declare(queue='', exclusive=True)
        self.callback_queue = result['queue']

        self.channel.basic.consume(callback=self._on_response,
                                   queue=self.callback_queue,
                                   no_ack=True)

    def close(self):
        self.channel.stop_consuming()
        self.channel.close()
        self.connection.close()

    @property
    def metadata(self):
        ign, bearer = request.headers['Authorization'].split()
        metadata = request.get_json()['params']
        metadata.update({'bearer': bearer})
        dst_metadata = json.dumps(obj=metadata)
        return dst_metadata

    def request_authz(self):
        self.response = None
        message = Message.create(channel=self.channel,  body=self.metadata)
        message.reply_to = self.callback_queue
        self.correlation_id = message.correlation_id
        print(' RPC client [sent request] '.center(80, '#'))
        message.publish(routing_key=QUEUE_STATISTICS)

        while not self.response:
            self.channel.process_data_events()
        return self.response

    def _on_response(self, message):
        if self.correlation_id != message.correlation_id:
            return
        dst = json.loads(s=message.body)['authZ']
        print(' RPC client [received response] '.center(80, '#'))
        self.response = dst
# RESTful api using flask-restful
from flask_restful import Resource
import AuthZ

class Demo:
    def post(self):
        authz = AuthZ()
        verified = authz.request_authz()
        authz.close()
        if verified == 'authorized':
            return {'data': 'You have access to it'}
        else:
            return {'data': 'You have no access to it'}