按照官方文档插件实例中编译出来的插件安装后为何没生效。
我在控制台中可以看到自定义的插件打印的日志,但是
%% 只允许 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,我已经通过环境变量配置了。请问有更多详细的流程文档能够支持吗?
提示
- 需要先把配置中的
authorization.no_match
设置为 deny
,默认拒绝未经授权的操作。
- 要设置同样的订阅规则,无需开发插件,可以通过 EMQX 内置的 基于文件进行授权 来实现。
依然所有客户端都可以登录
clientid 中有包含了 A-Za-z0-9_
以外的字符么?
另外可以尝试先不修改代码,直接编译后运行,查看有没有对应的信息输出 emqx_plugin_template.erl#L94
确保有输出,即插件钩子能够被正确挂载后,再对 authn/authz 钩子函数进行功能修改。
我试过初始化一个空的插件。可以打印插件的所有信息。然后我才按照官方插件文档这个链接)代码去编译的。但是任意clientID的用户登录。
我的步骤是这样的,
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 配置:
感谢反馈,我们会尽快更新文档
按照你说的修改,我关闭了所以得客户端授权数据源,未匹配时执行也改为了“deny”。
sub任何topic时候都不成功,客户端报错如下图,
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}.
用你的方法解决了我的问题。
我试了一下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}}.
否则还是实现不了向任意主题发布消息的功能,不知道我的改动是否正确。