feat(authentication): require header in csv file and use new json format
This commit is contained in:
parent
72c4696584
commit
661f2de01e
|
@ -1,2 +1,3 @@
|
|||
user_id,password_hash
|
||||
myuser3,8d41233e39c95b5da13361e354e1c9e639f07b27d397463a8f91b71ee07ccfb2
|
||||
myuser4,5809df0154f3cb4ac5c3a5572eaca0c5f7f9d858e887fc675b2becab9feb19d1
|
|
|
@ -1,4 +1,10 @@
|
|||
[
|
||||
{
|
||||
"myuser1": "09343625c6c123d3434932fe1ce08bae5ac00a8f95bd746e10491b0bafdd1817",
|
||||
"myuser2": "8767a7d316ad68cb607c7c805b859ffa78277dda13b7a3e2e8b53cad3cabbc6e"
|
||||
"user_id":"myuser1",
|
||||
"password_hash":"09343625c6c123d3434932fe1ce08bae5ac00a8f95bd746e10491b0bafdd1817"
|
||||
},
|
||||
{
|
||||
"user_id":"myuser2",
|
||||
"password_hash":"8767a7d316ad68cb607c7c805b859ffa78277dda13b7a3e2e8b53cad3cabbc6e"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -52,6 +52,8 @@
|
|||
}
|
||||
}).
|
||||
|
||||
|
||||
|
||||
-record(user_info,
|
||||
{ user_id :: {user_group(), user_id()}
|
||||
, password_hash :: binary()
|
||||
|
@ -188,17 +190,13 @@ list_users(#{user_group := UserGroup}) ->
|
|||
%% Internal functions
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
%% Example:
|
||||
%% {
|
||||
%% "myuser1":"password_hash1",
|
||||
%% "myuser2":"password_hash2"
|
||||
%% }
|
||||
%% Example: data/user-credentials.json
|
||||
import_users_from_json(Filename, #{user_group := UserGroup}) ->
|
||||
case file:read_file(Filename) of
|
||||
{ok, Bin} ->
|
||||
case emqx_json:safe_decode(Bin) of
|
||||
case emqx_json:safe_decode(Bin, [return_maps]) of
|
||||
{ok, List} ->
|
||||
import(UserGroup, List);
|
||||
trans(fun import/2, [UserGroup, List]);
|
||||
{error, Reason} ->
|
||||
{error, Reason}
|
||||
end;
|
||||
|
@ -206,44 +204,43 @@ import_users_from_json(Filename, #{user_group := UserGroup}) ->
|
|||
{error, Reason}
|
||||
end.
|
||||
|
||||
%% Example:
|
||||
%% myuser1,password_hash1
|
||||
%% myuser2,password_hash2
|
||||
%% Example: data/user-credentials.csv
|
||||
import_users_from_csv(Filename, #{user_group := UserGroup}) ->
|
||||
case file:open(Filename, [read, binary]) of
|
||||
{ok, File} ->
|
||||
Result = import(UserGroup, File),
|
||||
case get_csv_header(File) of
|
||||
{ok, Seq} ->
|
||||
Result = trans(fun import/3, [UserGroup, File, Seq]),
|
||||
file:close(File),
|
||||
Result;
|
||||
{error, Reason} ->
|
||||
{error, Reason}
|
||||
end;
|
||||
{error, Reason} ->
|
||||
{error, Reason}
|
||||
end.
|
||||
|
||||
import(UserGroup, ListOrFile) ->
|
||||
trans(fun do_import/2, [UserGroup, ListOrFile]).
|
||||
|
||||
do_import(_UserGroup, []) ->
|
||||
import(_UserGroup, []) ->
|
||||
ok;
|
||||
do_import(UserGroup, [{UserID, PasswordHash} | More])
|
||||
import(UserGroup, [#{<<"user_id">> := UserID, <<"password_hash">> := PasswordHash} | More])
|
||||
when is_binary(UserID) andalso is_binary(PasswordHash) ->
|
||||
import_user(UserGroup, UserID, PasswordHash),
|
||||
do_import(UserGroup, More);
|
||||
do_import(_UserGroup, [_ | _More]) ->
|
||||
{error, bad_format};
|
||||
import(UserGroup, More);
|
||||
import(_UserGroup, [_ | _More]) ->
|
||||
{error, bad_format}.
|
||||
|
||||
%% Importing 5w users needs 1.7 seconds
|
||||
do_import(UserGroup, File) ->
|
||||
import(UserGroup, File, Seq) ->
|
||||
case file:read_line(File) of
|
||||
{ok, Line} ->
|
||||
case binary:split(Line, [<<",">>, <<"\n">>], [global]) of
|
||||
[UserID, PasswordHash, <<>>] ->
|
||||
import_user(UserGroup, UserID, PasswordHash),
|
||||
do_import(UserGroup, File);
|
||||
[UserID, PasswordHash] ->
|
||||
Fields = binary:split(Line, [<<",">>, <<" ">>, <<"\n">>], [global, trim_all]),
|
||||
case get_user_info_by_seq(Fields, Seq) of
|
||||
{ok, #{user_id := UserID,
|
||||
password_hash := PasswordHash}} ->
|
||||
import_user(UserGroup, UserID, PasswordHash),
|
||||
do_import(UserGroup, File);
|
||||
_ ->
|
||||
{error, bad_format}
|
||||
import(UserGroup, File, Seq);
|
||||
{error, Reason} ->
|
||||
{error, Reason}
|
||||
end;
|
||||
eof ->
|
||||
ok;
|
||||
|
@ -251,6 +248,31 @@ do_import(UserGroup, File) ->
|
|||
{error, Reason}
|
||||
end.
|
||||
|
||||
get_csv_header(File) ->
|
||||
case file:read_line(File) of
|
||||
{ok, Line} ->
|
||||
Seq = binary:split(Line, [<<",">>, <<" ">>, <<"\n">>], [global, trim_all]),
|
||||
{ok, Seq};
|
||||
eof ->
|
||||
{error, empty_file};
|
||||
{error, Reason} ->
|
||||
{error, Reason}
|
||||
end.
|
||||
|
||||
get_user_info_by_seq(Fields, Seq) ->
|
||||
get_user_info_by_seq(Fields, Seq, #{}).
|
||||
|
||||
get_user_info_by_seq([], [], #{user_id := _, password_hash := _} = Acc) ->
|
||||
{ok, Acc};
|
||||
get_user_info_by_seq(_, [], _) ->
|
||||
{error, bad_format};
|
||||
get_user_info_by_seq([UserID | More1], [<<"user_id">> | More2], Acc) ->
|
||||
get_user_info_by_seq(More1, More2, Acc#{user_id => UserID});
|
||||
get_user_info_by_seq([PasswordHash | More1], [<<"password_hash">> | More2], Acc) ->
|
||||
get_user_info_by_seq(More1, More2, Acc#{password_hash => PasswordHash});
|
||||
get_user_info_by_seq(_, _, _) ->
|
||||
{error, bad_format}.
|
||||
|
||||
-compile({inline, [add/4]}).
|
||||
add(UserGroup, UserID, Password, Algorithm) ->
|
||||
Credential = #user_info{user_id = {UserGroup, UserID},
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
user_id,password_hash
|
||||
myuser3,8d41233e39c95b5da13361e354e1c9e639f07b27d397463a8f91b71ee07ccfb2
|
||||
myuser4,5809df0154f3cb4ac5c3a5572eaca0c5f7f9d858e887fc675b2becab9feb19d1
|
|
|
@ -1,4 +1,10 @@
|
|||
[
|
||||
{
|
||||
"myuser1": "09343625c6c123d3434932fe1ce08bae5ac00a8f95bd746e10491b0bafdd1817",
|
||||
"myuser2": "8767a7d316ad68cb607c7c805b859ffa78277dda13b7a3e2e8b53cad3cabbc6e"
|
||||
"user_id":"myuser1",
|
||||
"password_hash":"09343625c6c123d3434932fe1ce08bae5ac00a8f95bd746e10491b0bafdd1817"
|
||||
},
|
||||
{
|
||||
"user_id":"myuser2",
|
||||
"password_hash":"8767a7d316ad68cb607c7c805b859ffa78277dda13b7a3e2e8b53cad3cabbc6e"
|
||||
}
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue