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