自定义插件未生效

按照官方文档插件实例中编译出来的插件安装后为何没生效。
我在控制台中可以看到自定义的插件打印的日志,但是

%%  只允许 clientid 为 [A-Za-z0-9_] 的客户端连接。
on_client_authenticate(_ClientInfo = #{clientid := ClientId}, Result, _Env) ->
  case re:run(ClientId, "^[A-Za-z0-9_]+$", [{capture, none}]) of
    match -> {ok, Result};
    nomatch -> {stop, {error, banned}}
  end.

使用实例中的代码后,依然所哟客户端都可以登陆。实例中讲到authorization设置为deny,我已经通过环境变量配置了。请问有更多详细的流程文档能够支持吗?

提示

  1. 需要先把配置中的 authorization.no_match 设置为 deny,默认拒绝未经授权的操作。
  2. 要设置同样的订阅规则,无需开发插件,可以通过 EMQX 内置的 基于文件进行授权 来实现。

依然所有客户端都可以登录

clientid 中有包含了 A-Za-z0-9_ 以外的字符么?

另外可以尝试先不修改代码,直接编译后运行,查看有没有对应的信息输出 emqx_plugin_template.erl#L94
确保有输出,即插件钩子能够被正确挂载后,再对 authn/authz 钩子函数进行功能修改。

我试过初始化一个空的插件。可以打印插件的所有信息。然后我才按照官方插件文档这个链接)代码去编译的。但是任意clientID的用户登录。

我先按照您的步骤尝试复现一下 :thinking:

我的步骤是这样的,
1、先用rebar3命令new出我自己的插件模块。
2、编译并安装,可以正确打印出new的模板插件里边的日志。
3、添加官方链接里边的“只允许 clientid 为 [A-Za-z0-9_] 的客户端连接”和“只允许订阅 /room/{clientid} 的主题,但是可以发送消息给任意主题。”示例代码。
4、再次编译,卸载旧插件,安装新编译的插件,并启动。
5、启动完成后可以看到各个钩子的log。但是未见实例中的功能生效。

提示
1.需要先把配置中的 authorization.no_match 设置为 deny,默认拒绝未经授权的操作。
2.要设置同样的订阅规则,无需开发插件,可以通过 EMQX 内置的 基于文件进行授权 来实现。

我看官方链接里边还有两条提示。
是不是因为我没按照提示的内去修改,所以不行?
请问有没有这两个提示的更详细的指导文档?

这两条提示是在与客户端进行 pub/sub 时进行 authz 检查时相关的。和客户端登录认证无关。
按照你的步骤复现,clientid 中带有正则表达式无法匹配的字符时,无法连接。其他客户端可以连接


哦哦哦,不好意思,确实是我登录认证时候的正则表达式没看清楚。现在重新试了一下可以。
那你说的这个pub/sub这个我该如何去实现呢?

我按照实例中的

%% 只允许订阅 /room/{clientid} 的主题,但是可以发送消息给任意主题。
on_client_authorize(_ClientInfo = #{clientid := ClientId}, subscribe, Topic, Result, _Env) ->
  case emqx_topic:match(Topic, <<"/room/", ClientId/binary>>) of
    true -> {ok, Result};
    false -> stop
  end;
on_client_authorize(_ClientInfo, _Pub, _Topic, Result, _Env) -> {ok, Result}.

添加后,可以订阅其他的topic。

%% 只允许订阅 /room/{clientid} 的主题,但是可以发送消息给任意主题。
on_client_authorize(_ClientInfo = #{clientid := ClientId}, subscribe, Topic, Result, _Env) ->
  io:format("Authorizing client: ~p to subscribe to topic: ~p~n", [ClientId, Topic]),
  case emqx_topic:match(Topic, <<"/room/", ClientId/binary>>) of
    true -> {ok, Result};
    false -> stop
  end;
on_client_authorize(_ClientInfo = #{clientid := ClientId}, _Pub, _Topic, Result, _Env) ->
  io:format("Handling client: (~s) default authorization for client. topic: (~s)~n",
    [ClientId, _Topic]),
  {ok, Result}.

Erlang语法也不太熟。我试着加了一点log。
在sub的时候只有Handling这个段log。

没有看到on_client_authorize第一段的log。

在 v5.1.2(含) 之后的版本中,authz 检查提供了 qos check 的功能。
参考:emqx_channel.erl#R2128-R2129

所以在 v5.1.2 以后的版本中,authz 插件所挂载的钩子函数应该写为:

on_client_authorize(_ClientInfo = #{clientid := ClientId}, #{action_type := subscribe, qos := _}, Topic, Result, _Env) ->
  case emqx_topic:match(Topic, <<"/room/", ClientId/binary>>) of
    true -> {ok, Result#{result => allow}};
    false -> {stop, Result#{result => deny}}
  end;
on_client_authorize(_ClientInfo, _Action, _Topic, Result, _Env) -> {ok, Result}.

此外,需要关注提示中的内容:

需要先把配置中的 authorization.no_match 设置为 deny,默认拒绝未经授权的操作。

可以通过 dashboard 操作关闭其他授权数据源,及其他 authz 配置:

感谢反馈,我们会尽快更新文档 :rocket:

按照你说的修改,我关闭了所以得客户端授权数据源,未匹配时执行也改为了“deny”。
sub任何topic时候都不成功,客户端报错如下图,
image
pub也任何topic也不行。如下是控制台打印的log。


控制台的“ Authorizing client: ”和“Handling client: ”是我添加的log。下方是我的钩子代码

on_client_authorize(_ClientInfo = #{clientid := ClientId}, #{action_type := subscribe}, Topic, Result, _Env) ->
  io:format("Authorizing client: (~s) to (~s) to topic: (~s)~n", [ClientId, subscribe, Topic]),
  case emqx_topic:match(Topic, <<"/room/", ClientId/binary>>) of
    true -> {ok, Result};
    false -> stop
  end;
on_client_authorize(_ClientInfo = #{clientid := ClientId}, _Action, _Topic, Result, _Env) ->
  io:format("Handling client: (~s) (~p) default authorization for client. topic: (~s)~n",
    [ClientId, _Action, _Topic]),
  {ok, Result}.

image

Hi, 请使用更新后的代码:


subed /room/abc, can not sub /room/abcd

用你的方法解决了我的问题。
我试了一下flase时候直接stop的话会继续匹配我的MySQL和file客户端授权源。

 case emqx_topic:match(Topic, <<"/room/", ClientId/binary>>) of
    true -> {ok, Result#{result => allow}};
    false -> {stop}
  end;

再次感谢技术支持。

您好,经过我的测试,

on_client_authorize(_ClientInfo, _Action, _Topic, Result, _Env) -> {ok, Result}.

应改为

on_client_authorize(_ClientInfo,_Action,_Topic,Result,_Env)->{ok,Result#{result => allow}}.

否则还是实现不了向任意主题发布消息的功能,不知道我的改动是否正确。