首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

11.Orber拦截器 | 11. Orber Interceptors

11.1使用拦截器

对于Inter-ORB通信,例如通过IIOP,可以拦截请求和回复。为了能够使用InterceptorsOrber,interceptors必须定义配置参数。

配置Orber使用拦截器

interceptors必须定义配置参数,例如,作为命令行选项:

代码语言:javascript
复制
erl -orber interceptors "{native, ['myInterceptor']}"
      

有可能使用多个拦截器; 只需将它们添加到列表中,它们将按照它们出现在列表中的顺序调用。

也可以在运行时激活和停用拦截器,但这只会影响当前现有的连接。有关更多信息,请参阅Orber的参考手册,了解有关操作orber:activate_audit_trail/0/1orber:activate_audit_trail/0/1.

创建拦截器

每个提供的拦截器都必须输出以下功能:

  • new_out_connection / 3/5 - 当客户端应用程序调用驻留在远程ORB上的对象时,将调用其中一个操作。如果一个拦截器导出了两个版本,arity 3和5,那么将调用哪个操作是Orber内部的。
  • new_in_connection / 3/5 - 当客户端ORB尝试建立与目标ORB的连接时,将调用其中一个操作。如果一个拦截器导出了两个版本,arity 3和5,那么将调用哪个操作是Orber内部的。
  • out_request / 6 - 提供客户端ORB上的所有请求数据。
  • out_request_encoded / 6 - 类似于out_request请求主体是编码。
  • in_request_encoded / 6 - 在新的请求到达目标ORB后,请求数据以编码格式传递给拦截器。
  • in_request / 6 - 在调用目标对象的操作之前,调用拦截器in_request
  • out_reply / 6 - 在目标对象回复之后,out_reply操作被调用的结果是对象调用。
  • out_reply_encoded / 6 - 在将响应发送回客户端ORB之前,将以编码格式调用结果调用此操作。
  • in_reply_encoded / 6 - 在客户端ORB收到回复后,以编码格式回复此函数。
  • in_reply / 6 - 在将响应传递给客户端之前,调用该操作。
  • closed_in_connection / 1 - 当连接在客户端终止时,调用该函数。
  • closed_out_connection / 1 - 如果传出连接终止,将调用此操作。

操作new_out_connectionnew_in_connectionclosed_in_connectionclosed_out_connection操作仅调用一次,每个连接。对于每个远程CORBA对象的请求/响应,剩下的操作被调用,如下所示。

图11.1:Interceptor函数的调用顺序。

11.2 拦截器示例

假设我们希望创建一个简单的访问服务,其目的是:

  • 只允许ORB驻留在特定节点上的传入请求。
  • 限制任何客户端可以调用操作的对象。
  • 只允许传出请求调用有限的外部ORB%27。
  • 向每个二进制请求/回复正文添加校验和。

为了限制访问,我们使用一个保护所有信息的受保护和命名的ets表。 如何启动和维护ets-table是特定于实现的,但它包含{Node,ObjectTable,ChecksumModule},其中Node用作ets-key,ObjectTable是另一个ets-table的引用,我们在其中存储客户端是哪些对象 允许调用操作,并且ChecksumModule确定我们应该使用哪个模块来处理校验和。

代码语言:javascript
复制
new_in_connection(Arg, Host, Port) ->
    %% Since we only use one interceptor we do not care about the
    %% input Arg since it is set do undefined by Orber.
    case ets:lookup(in_access_table, Host) of
         [] ->
            %% We may want to log the Host/Port to see if someone tried
            %% to hack in to our system.
            exit("Access not granted");
         [{Host, ObjTable, ChecksumModule}] ->
            {ObjTable, ChecksumModule}
    end.
    

每当调用其中一个拦截器函数时,返回的元组(即{ObjTable,ChecksumModule})将作为第一个参数传递。除非连接尝试没有失败,否则我们现在准备好接收来自客户端ORB的请求。

当一个新的请求进入时,第一个被调用的拦截器函数是in_request_encoded。 我们将通过以下方式从编码请求主体中移除校验和:

代码语言:javascript
复制
in_request_encoded({ObjTable, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
    NewBin = ChecksumModule:remove_checksum(Bin),
    {NewBin, Extra}.
    

如果校验和检查失败,ChecksumModule应该调用exit / 1。 但是,如果检查成功,我们现在准备检查是否允许客户端ORB对象调用目标对象上的操作。 请注意,可以在in_request_encoded中运行这两项检查。 请注意,校验和计算必须相对较快以确保良好的吞吐量。

如果我们愿意,可以限制任何客户端只使用服务器导出的操作的子集:

代码语言:javascript
复制
in_request({ObjTable, ChecksumModule}, ObjKey, Ctx, Op, Params, Extra) ->
    case ets:lookup(ObjTable, {ObjKey, Op}) of
         [] ->
            exit("Client tried to invoke illegal operation");
         [SomeData] ->
            {Params, Extra}
    end.
    

此时,Orber现在准备调用目标对象的操作。由于我们不关心答复是out_reply,函数什么也不做,即:

代码语言:javascript
复制
out_reply(_, _, _, _, Reply, Extra) ->
    {Reply, Extra}.
    

如果客户端ORB希望将校验和添加到回复中,我们使用以下命令添加它:

代码语言:javascript
复制
out_reply_encoded({ObjTable, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
    NewBin = ChecksumModule:add_checksum(Bin),
    {NewBin, Extra}.
    

警告

如果我们像上面的行为那样操作二进制文件Bin == remove_checksum(add_checksum(Bin))...

对于传出请求,原则是相同的。因此,这里不再对此作进一步的描述。完整的拦截器模块如下所示:

代码语言:javascript
复制
-module(myInterceptor).

%% Interceptor functions.
-export([new_out_connection/3,
     new_in_connection/3,
     closed_in_connection/1,
     closed_out_connection/1,
     in_request_encoded/6,
     in_reply_encoded/6,
     out_reply_encoded/6,
     out_request_encoded/6,
     in_request/6,
     in_reply/6,
     out_reply/6,
     out_request/6]).

new_in_connection(Arg, Host, Port) ->
    %% Since we only use one interceptor we do not care about the
    %% input Arg since it is set do undefined by Orber.
    case ets:lookup(in_access_table, Host) of
         [] ->
            %% We may want to log the Host/Port to see if someone tried
            %% to hack in to our system.
            exit("Access not granted");
         [{Host, ObjTable, ChecksumModule}] ->
            {ObjTable, ChecksumModule}
    end.

new_out_connection(Arg, Host, Port) ->
    case ets:lookup(out_access_table, Host) of
         [] ->
            exit("Access not granted");
         [{Host, ObjTable, ChecksumModule}] ->
            {ObjTable, ChecksumModule}
    end.

in_request_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
    NewBin = ChecksumModule:remove_checksum(Bin),
    {NewBin, Extra}.

in_request({ObjTable, _}, ObjKey, Ctx, Op, Params, Extra) ->
    case ets:lookup(ObjTable, {ObjKey, Op}) of
         [] ->
            exit("Client tried to invoke illegal operation");
         [SomeData] ->
            {Params, Extra}
    end.

out_reply(_, _, _, _, Reply, Extra) ->
    {Reply, Extra}.

out_reply_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
    NewBin = ChecksumModule:add_checksum(Bin),
    {NewBin, Extra}.

out_request({ObjTable, _}, ObjKey, Ctx, Op, Params, Extra) ->
    case ets:lookup(ObjTable, {ObjKey, Op}) of
         [] ->
            exit("Client tried to invoke illegal operation");
         [SomeData] ->
            {Params, Extra}
    end.

out_request_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
    NewBin = ChecksumModule:add_checksum(Bin),
    {NewBin, Extra}.

in_reply_encoded({_, ChecksumModule}, ObjKey, Ctx, Op, Bin, Extra) ->
    NewBin = ChecksumModule:remove_checksum(Bin),
    {NewBin, Extra}.

in_reply(_, _, _, _, Reply, Extra) ->
    {Reply, Extra}.

closed_in_connection(Arg) ->
    %% Nothing to clean up.
    Arg.

closed_out_connection(Arg) ->
    %% Nothing to clean up.
    Arg.
    

还可以使用拦截器进行调试,例如,打印调用哪些对象和操作,使用哪些参数和操作的结果。结合配置参数orber_debug_level找出什么问题或仅仅记录流量是相当容易的。

扫码关注腾讯云开发者

领取腾讯云代金券

http://www.vxiaotou.com