diff --git a/apps/emqx_dashboard/i18n/emqx_dashboard_i18n.conf b/apps/emqx_dashboard/i18n/emqx_dashboard_i18n.conf index d6587c203..e404b54b4 100644 --- a/apps/emqx_dashboard/i18n/emqx_dashboard_i18n.conf +++ b/apps/emqx_dashboard/i18n/emqx_dashboard_i18n.conf @@ -197,4 +197,25 @@ its own from which a browser should permit loading resources.""" zh: "多语言支持" } } + bootstrap_user { + desc { + en: "Initialize users file." + zh: "初始化用户文件" + } + label { + en: """Is used to add an administrative user to Dashboard when emqx is first launched, + the format is: + ``` + username1:password1 + username2:password2 + ``` +""" + zh: """用于在首次启动 emqx 时,为 Dashboard 添加管理用户,其格式为: + ``` + username1:password1 + username2:password2 + ``` +""" + } + } } diff --git a/apps/emqx_dashboard/src/emqx_dashboard_admin.erl b/apps/emqx_dashboard/src/emqx_dashboard_admin.erl index 0650062f8..85f145595 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard_admin.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard_admin.erl @@ -19,6 +19,7 @@ -module(emqx_dashboard_admin). -include("emqx_dashboard.hrl"). +-include_lib("emqx/include/logger.hrl"). -include_lib("stdlib/include/ms_transform.hrl"). -boot_mnesia({mnesia, [boot]}). @@ -50,7 +51,8 @@ -export([ add_default_user/0, - default_username/0 + default_username/0, + add_bootstrap_user/0 ]). -type emqx_admin() :: #?ADMIN{}. @@ -74,6 +76,29 @@ mnesia(boot) -> ]} ]). +%%-------------------------------------------------------------------- +%% bootstrap API +%%-------------------------------------------------------------------- + +-spec add_default_user() -> {ok, map() | empty | default_user_exists} | {error, any()}. +add_default_user() -> + add_default_user(binenv(default_username), binenv(default_password)). + +-spec add_bootstrap_user() -> ok | {error, _}. +add_bootstrap_user() -> + case emqx:get_config([dashboard, bootstrap_user], undefined) of + undefined -> + ok; + File -> + case mnesia:table_info(?ADMIN, size) of + 0 -> + ?SLOG(debug, #{msg => "Add dashboard bootstrap users", file => File}), + add_bootstrap_user(File); + _ -> + ok + end + end. + %%-------------------------------------------------------------------- %% API %%-------------------------------------------------------------------- @@ -272,11 +297,6 @@ destroy_token_by_username(Username, Token) -> %%-------------------------------------------------------------------- %% Internal functions %%-------------------------------------------------------------------- - --spec add_default_user() -> {ok, map() | empty | default_user_exists} | {error, any()}. -add_default_user() -> - add_default_user(binenv(default_username), binenv(default_password)). - default_username() -> binenv(default_username). @@ -290,3 +310,36 @@ add_default_user(Username, Password) -> [] -> add_user(Username, Password, <<"administrator">>); _ -> {ok, default_user_exists} end. + +add_bootstrap_user(File) -> + case file:open(File, [read]) of + {ok, Dev} -> + {ok, MP} = re:compile(<<"(\.+):(\.+)">>), + try + load_bootstrap_user(Dev, MP) + catch + Type:Reason -> + {error, {Type, Reason}} + after + file:close(Dev) + end; + Error -> + Error + end. + +load_bootstrap_user(Dev, MP) -> + case file:read_line(Dev) of + {ok, Line} -> + case re:run(Line, MP, [global, {capture, all_but_first, binary}]) of + {match, Captured} -> + _ = [add_user(Username, Password, <<>>) || [Username, Password] <- Captured], + ok; + _ -> + ok + end, + load_bootstrap_user(Dev, MP); + eof -> + ok; + Error -> + Error + end. diff --git a/apps/emqx_dashboard/src/emqx_dashboard_app.erl b/apps/emqx_dashboard/src/emqx_dashboard_app.erl index 08bfe1d21..5084d76c4 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard_app.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard_app.erl @@ -31,8 +31,13 @@ start(_StartType, _StartArgs) -> case emqx_dashboard:start_listeners() of ok -> emqx_dashboard_cli:load(), - {ok, _} = emqx_dashboard_admin:add_default_user(), - {ok, Sup}; + case emqx_dashboard_admin:add_bootstrap_user() of + ok -> + {ok, _} = emqx_dashboard_admin:add_default_user(), + {ok, Sup}; + Error -> + Error + end; {error, Reason} -> {error, Reason} end. diff --git a/apps/emqx_dashboard/src/emqx_dashboard_schema.erl b/apps/emqx_dashboard/src/emqx_dashboard_schema.erl index 55a1fd38c..4bb9fb6af 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard_schema.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard_schema.erl @@ -54,7 +54,8 @@ fields("dashboard") -> } )}, {cors, fun cors/1}, - {i18n_lang, fun i18n_lang/1} + {i18n_lang, fun i18n_lang/1}, + {bootstrap_user, ?HOCON(binary(), #{desc => ?DESC(bootstrap_user), required => false})} ]; fields("listeners") -> [