# perxis-python ## Расширения ### Локальная разработка Для работы расширения требуется указание системного контекста при выполнении запросов. Это возможно только в случае прямой работы с сервисами perxis минуя envoy, для этого они должны быть в одной сети. Поэтому нужен локально запущенный экземпляр perxis. Для его запуска нужно в каталоге perxis выполнить команду make run-local. После этого в контейнере в той же сети можно запустить сервис с расширением ### Пример написания сервиса расширений Готовый пример с реализацией простого сервиса можно посмотреть в каталоге examples/extension_service ## Аутентификация gRPC Python предоставляет способ перехвата RPC и добавления метаданных, связанных с аутентификацией, через AuthMetadataPlugin. Те, кому нужен специальный метод аутентификации, могут просто предоставить конкретную реализацию следующего интерфейса: ```python class AuthMetadataPlugin: """A specification for custom authentication.""" def __call__(self, context, callback): """Implements authentication by passing metadata to a callback. Implementations of this method must not block. Args: context: An AuthMetadataContext providing information on the RPC that the plugin is being called to authenticate. callback: An AuthMetadataPluginCallback to be invoked either synchronously or asynchronously. """ ``` Затем передайте экземпляр конкретной реализации в функцию grpc.metadata_call_credentials, которая будет преобразована в объект CallCredentials. ОБРАТИТЕ ВНИМАНИЕ, что можно передать объект функции Python напрямую, но мы рекомендуем наследовать от базового класса, чтобы гарантировать правильность реализации. ```python def metadata_call_credentials(metadata_plugin, name=None): """Construct CallCredentials from an AuthMetadataPlugin. Args: metadata_plugin: An AuthMetadataPlugin to use for authentication. name: An optional name for the plugin. Returns: A CallCredentials. """ ``` Объект CallCredentials можно передать непосредственно в RPC, например: ```python call_credentials = grpc.metadata_call_credentials(my_foo_plugin) stub.FooRpc(request, credentials=call_credentials) ``` ### Пример авторизации и аутентификации OAuth2 ```python import grpc from oauthlib.oauth2 import Client from oauthlib.oauth2.rfc6749.parameters import prepare_token_request from auth import OAuth2Plugin from users.users_pb2 import GetRequest from users.users_pb2_grpc import UsersStub # Могут быть использованы как встроенные клиенты, такие как WebApplicationClient, BackendApplicationClient, # так и допускается реализовать собственный класс с кастомным поведением class ExtendedClient(Client): def __init__(self, client_id, grant_type, username, password, **kwargs): self.grant_type = grant_type self.username = username self.password = password super(ExtendedClient, self).__init__(client_id, **kwargs) def prepare_request_body(self, body='', scope=None, include_client_id=False, **kwargs): kwargs['client_id'] = self.client_id kwargs['include_client_id'] = include_client_id return prepare_token_request(self.grant_type, body=body, username=self.username, password=self.password, scope=scope, **kwargs) oauth2_plugin = OAuth2Plugin( client=ExtendedClient(client_id='client_id', grant_type='password', username='user', password='pass'), client_secret='client_secret', token_url='https://example.com/oauth/token', audience='audience' ) call_credentials = grpc.metadata_call_credentials(oauth2_plugin) with grpc.insecure_channel('localhost:50051') as channel: request = GetRequest(user_id=1) stub = UsersStub(channel) stub.Get(request, credentials=call_credentials) ```