Просмотр исходного кода

feat(authz): authz mnesia rules searching by `clientid` or `username`

JimMoen 4 лет назад
Родитель
Сommit
16ec8fe289
2 измененных файлов с 80 добавлено и 24 удалено
  1. 70 12
      apps/emqx_authz/src/emqx_authz_api_mnesia.erl
  2. 10 12
      apps/emqx_authz/src/emqx_authz_mnesia.erl

+ 70 - 12
apps/emqx_authz/src/emqx_authz_api_mnesia.erl

@@ -24,8 +24,12 @@
 
 -import(hoconsc, [mk/1, mk/2, ref/1, ref/2, array/1, enum/1]).
 
--define(FORMAT_USERNAME_FUN, {?MODULE, format_by_username}).
--define(FORMAT_CLIENTID_FUN, {?MODULE, format_by_clientid}).
+-define(QUERY_USERNAME_FUN, {?MODULE, query_username}).
+-define(QUERY_CLIENTID_FUN, {?MODULE, query_clientid}).
+
+-define(ACL_USERNAME_QSCHEMA, [{<<"like_username">>, binary}]).
+-define(ACL_CLIENTID_QSCHEMA, [{<<"like_clientid">>, binary}]).
+
 
 -export([ api_spec/0
         , paths/0
@@ -42,8 +46,11 @@
         , purge/2
         ]).
 
--export([ format_by_username/1
-        , format_by_clientid/1]).
+%% query funs
+-export([ query_username/4
+        , query_clientid/4]).
+
+-export([format_result/1]).
 
 -define(BAD_REQUEST, 'BAD_REQUEST').
 -define(NOT_FOUND, 'NOT_FOUND').
@@ -293,9 +300,10 @@ fields(meta) ->
 %% HTTP API
 %%--------------------------------------------------------------------
 
-users(get, #{query_string := QString}) ->
-    {Table, MatchSpec} = emqx_authz_mnesia:list_username_rules(),
-    {200, emqx_mgmt_api:paginate(Table, MatchSpec, QString, ?FORMAT_USERNAME_FUN)};
+users(get, #{query_string := QueryString}) ->
+    Response = emqx_mgmt_api:node_query(node(), QueryString,
+                                        ?ACL_TABLE, ?ACL_USERNAME_QSCHEMA, ?QUERY_USERNAME_FUN),
+    emqx_mgmt_util:generate_response(Response);
 users(post, #{body := Body}) when is_list(Body) ->
     lists:foreach(fun(#{<<"username">> := Username, <<"rules">> := Rules}) ->
                           emqx_authz_mnesia:store_rules({username, Username}, format_rules(Rules))
@@ -303,8 +311,9 @@ users(post, #{body := Body}) when is_list(Body) ->
     {204}.
 
 clients(get, #{query_string := QueryString}) ->
-    {Table, MatchSpec} = emqx_authz_mnesia:list_clientid_rules(),
-    {200, emqx_mgmt_api:paginate(Table, MatchSpec, QueryString, ?FORMAT_CLIENTID_FUN)};
+    Response = emqx_mgmt_api:node_query(node(), QueryString,
+                                        ?ACL_TABLE, ?ACL_CLIENTID_QSCHEMA, ?QUERY_CLIENTID_FUN),
+    emqx_mgmt_util:generate_response(Response);
 clients(post, #{body := Body}) when is_list(Body) ->
     lists:foreach(fun(#{<<"clientid">> := Clientid, <<"rules">> := Rules}) ->
                           emqx_authz_mnesia:store_rules({clientid, Clientid}, format_rules(Rules))
@@ -379,6 +388,54 @@ purge(delete, _) ->
                    }}
     end.
 
+%%--------------------------------------------------------------------
+%% Query Functions
+
+query_username(Tab, {_QString, []}, Continuation, Limit) ->
+    Ms = emqx_authz_mnesia:list_username_rules(),
+    emqx_mgmt_api:select_table_with_count(Tab, Ms, Continuation, Limit,
+                                          fun format_result/1);
+
+query_username(Tab, {_QString, FuzzyQString}, Continuation, Limit) ->
+    Ms = emqx_authz_mnesia:list_username_rules(),
+    FuzzyFilterFun = fuzzy_filter_fun(FuzzyQString),
+    emqx_mgmt_api:select_table_with_count(Tab, {Ms, FuzzyFilterFun}, Continuation, Limit,
+                                          fun format_result/1).
+
+query_clientid(Tab, {_QString, []}, Continuation, Limit) ->
+    Ms = emqx_authz_mnesia:list_clientid_rules(),
+    emqx_mgmt_api:select_table_with_count(Tab, Ms, Continuation, Limit,
+                                          fun format_result/1);
+
+query_clientid(Tab, {_QString, FuzzyQString}, Continuation, Limit) ->
+    Ms = emqx_authz_mnesia:list_clientid_rules(),
+    FuzzyFilterFun = fuzzy_filter_fun(FuzzyQString),
+    emqx_mgmt_api:select_table_with_count(Tab, {Ms, FuzzyFilterFun}, Continuation, Limit,
+                                          fun format_result/1).
+
+%%--------------------------------------------------------------------
+%% Match funcs
+
+%% Fuzzy username funcs
+fuzzy_filter_fun(Fuzzy) ->
+    fun(MsRaws) when is_list(MsRaws) ->
+        lists:filter( fun(E) -> run_fuzzy_filter(E, Fuzzy) end
+                    , MsRaws)
+    end.
+
+run_fuzzy_filter(_, []) ->
+    true;
+run_fuzzy_filter( E = [{username, Username}, _Rule]
+                , [{username, like, UsernameSubStr} | Fuzzy]) ->
+    binary:match(Username, UsernameSubStr) /= nomatch andalso run_fuzzy_filter(E, Fuzzy);
+run_fuzzy_filter( E = [{clientid, ClientId}, _Rule]
+                , [{clientid, like, ClientIdSubStr} | Fuzzy]) ->
+    binary:match(ClientId, ClientIdSubStr) /= nomatch andalso run_fuzzy_filter(E, Fuzzy).
+
+%%--------------------------------------------------------------------
+%% format funcs
+
+%% format rule from api
 format_rules(Rules) when is_list(Rules) ->
     lists:foldl(fun(#{<<"topic">> := Topic,
                       <<"action">> := Action,
@@ -388,14 +445,15 @@ format_rules(Rules) when is_list(Rules) ->
                    AccIn ++ [{ atom(Permission), atom(Action), Topic }]
                 end, [], Rules).
 
-format_by_username([{username, Username}, {rules, Rules}]) ->
+%% format result from mnesia tab
+format_result([{username, Username}, {rules, Rules}]) ->
     #{username => Username,
       rules => [ #{topic => Topic,
                    action => Action,
                    permission => Permission
                   } || {Permission, Action, Topic} <- Rules]
-     }.
-format_by_clientid([{clientid, Clientid}, {rules, Rules}]) ->
+     };
+format_result([{clientid, Clientid}, {rules, Rules}]) ->
     #{clientid => Clientid,
       rules => [ #{topic => Topic,
                    action => Action,

+ 10 - 12
apps/emqx_authz/src/emqx_authz_mnesia.erl

@@ -158,21 +158,19 @@ delete_rules({clientid, Clientid}) ->
 delete_rules(all) ->
     mria:dirty_delete(?ACL_TABLE, ?ACL_TABLE_ALL).
 
--spec(list_username_rules() -> {mria:table(), ets:match_spec()}).
+-spec(list_username_rules() -> ets:match_spec()).
 list_username_rules() ->
-    MatchSpec = ets:fun2ms(
-                  fun(#emqx_acl{who = {?ACL_TABLE_USERNAME, Username}, rules = Rules}) ->
-                          [{username, Username}, {rules, Rules}]
-                  end),
-    {?ACL_TABLE, MatchSpec}.
+    ets:fun2ms(
+      fun(#emqx_acl{who = {?ACL_TABLE_USERNAME, Username}, rules = Rules}) ->
+              [{username, Username}, {rules, Rules}]
+      end).
 
--spec(list_clientid_rules() -> {mria:table(), ets:match_spec()}).
+-spec(list_clientid_rules() -> ets:match_spec()).
 list_clientid_rules() ->
-    MatchSpec = ets:fun2ms(
-                  fun(#emqx_acl{who = {?ACL_TABLE_CLIENTID, Clientid}, rules = Rules}) ->
-                          [{clientid, Clientid}, {rules, Rules}]
-                  end),
-    {?ACL_TABLE, MatchSpec}.
+    ets:fun2ms(
+      fun(#emqx_acl{who = {?ACL_TABLE_CLIENTID, Clientid}, rules = Rules}) ->
+              [{clientid, Clientid}, {rules, Rules}]
+      end).
 
 -spec(record_count() -> non_neg_integer()).
 record_count() ->