Merge pull request #7310 from JimMoen/enhanced-authn-mnesia-fuzzy-query

feat(authn): enhanced authn users fuzzy searching
This commit is contained in:
JimMoen 2022-03-15 17:18:08 +08:00 committed by GitHub
commit a04bb57c19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 15 deletions

View File

@ -42,10 +42,14 @@
, list_users/2 , list_users/2
]). ]).
-export([format_user_info/1]). -export([ query/4
, format_user_info/1
, group_match_spec/1]).
-define(TAB, ?MODULE). -define(TAB, ?MODULE).
-define(FORMAT_FUN, {?MODULE, format_user_info}). -define(AUTHN_QSCHEMA, [ {<<"like_username">>, binary}
, {<<"user_group">>, binary}]).
-define(QUERY_FUN, {?MODULE, query}).
-type(user_group() :: binary()). -type(user_group() :: binary()).
@ -201,9 +205,39 @@ lookup_user(UserID, #{user_group := UserGroup}) ->
{error, not_found} {error, not_found}
end. end.
list_users(PageParams, #{user_group := UserGroup}) -> list_users(QueryString, #{user_group := UserGroup}) ->
MatchSpec = group_match_spec(UserGroup), NQueryString = QueryString#{<<"user_group">> => UserGroup},
{ok, emqx_mgmt_api:paginate(?TAB, MatchSpec, PageParams, ?FORMAT_FUN)}. emqx_mgmt_api:node_query(node(), NQueryString, ?TAB, ?AUTHN_QSCHEMA, ?QUERY_FUN).
%%--------------------------------------------------------------------
%% Query Functions
query(Tab, {QString, []}, Continuation, Limit) ->
Ms = ms_from_qstring(QString),
emqx_mgmt_api:select_table_with_count(Tab, Ms, Continuation, Limit,
fun format_user_info/1);
query(Tab, {QString, FuzzyQString}, Continuation, Limit) ->
Ms = ms_from_qstring(QString),
FuzzyFilterFun = fuzzy_filter_fun(FuzzyQString),
emqx_mgmt_api:select_table_with_count(Tab, {Ms, FuzzyFilterFun}, Continuation, Limit,
fun format_user_info/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 = #user_info{user_id = {_, UserID}}
, [{username, like, UsernameSubStr} | Fuzzy]) ->
binary:match(UserID, UsernameSubStr) /= nomatch andalso run_fuzzy_filter(E, Fuzzy).
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
%% Internal functions %% Internal functions
@ -280,6 +314,14 @@ trans(Fun, Args) ->
format_user_info(#user_info{user_id = {_, UserID}, is_superuser = IsSuperuser}) -> format_user_info(#user_info{user_id = {_, UserID}, is_superuser = IsSuperuser}) ->
#{user_id => UserID, is_superuser => IsSuperuser}. #{user_id => UserID, is_superuser => IsSuperuser}.
ms_from_qstring(QString) ->
[Ms] = lists:foldl(fun({user_group, '=:=', UserGroup}, AccIn) ->
[group_match_spec(UserGroup) | AccIn];
(_, AccIn) ->
AccIn
end, [], QString),
Ms.
group_match_spec(UserGroup) -> group_match_spec(UserGroup) ->
ets:fun2ms( ets:fun2ms(
fun(#user_info{user_id = {Group, _}} = User) when Group =:= UserGroup -> fun(#user_info{user_id = {Group, _}} = User) when Group =:= UserGroup ->

View File

@ -269,16 +269,21 @@ t_list_users(_) ->
fun(U) -> {ok, _} = emqx_enhanced_authn_scram_mnesia:add_user(U, State) end, fun(U) -> {ok, _} = emqx_enhanced_authn_scram_mnesia:add_user(U, State) end,
Users), Users),
{ok, #{data := [?USER_MAP, ?USER_MAP],
#{data := [?USER_MAP, ?USER_MAP], meta := #{page := 1, limit := 2, count := 3}} = emqx_enhanced_authn_scram_mnesia:list_users(
meta := #{page := 1, limit := 2, count := 3}}} = emqx_enhanced_authn_scram_mnesia:list_users( #{<<"page">> => 1, <<"limit">> => 2},
#{<<"page">> => 1, <<"limit">> => 2}, State),
State), #{data := [?USER_MAP],
{ok, meta := #{page := 2, limit := 2, count := 3}} = emqx_enhanced_authn_scram_mnesia:list_users(
#{data := [?USER_MAP], #{<<"page">> => 2, <<"limit">> => 2},
meta := #{page := 2, limit := 2, count := 3}}} = emqx_enhanced_authn_scram_mnesia:list_users( State),
#{<<"page">> => 2, <<"limit">> => 2}, #{data := [#{user_id := <<"u1">>,
State). is_superuser := _}],
meta := #{page := 1, limit := 3, count := 1}} = emqx_enhanced_authn_scram_mnesia:list_users(
#{ <<"page">> => 1
, <<"limit">> => 3
, <<"like_username">> => <<"1">>},
State).
t_is_superuser(_Config) -> t_is_superuser(_Config) ->
ok = test_is_superuser(#{is_superuser => false}, false), ok = test_is_superuser(#{is_superuser => false}, false),