Как написать сервис, который либо отображает HTML, либо перенаправляет на другую страницу
В веб-программировании общий шаблон для отправки форм:
- Если форма действительна, перенаправьте на другую страницу ( Post / Redirect / Get).
- Если форма недействительна, перезапустите форму (возможно, включая сообщения об ошибках на этот раз).
Как я могу выразить это в Ocsigen?
Я читал документацию, но не мог понять, как выполнить эту простую (и очень распространенную) задачу.
Пример использования:
Предположим, у меня есть форма входа в систему, которая защищает от несанкционированного доступа к панели администратора (страница, доступ к которой должен иметь только администратор). Если пользователь вводит правильные учетные данные в форме входа в систему, пользователь должен быть перенаправлен на панель администратора. Если учетные данные неверны, пользователь должен быть перенаправлен обратно в форму входа. До сих пор я успешно реализовал эту функциональность.
Тем не менее, я в растерянности, когда дело доходит до реализации следующего: если пользователь уже вошел в систему и пытается получить доступ к форме входа в систему, пользователь должен быть перенаправлен в административную панель. Кроме того, если пользователь не вошел в систему и пытается получить доступ к панели администратора, пользователь должен быть перенаправлен в форму входа.
Ниже мой код до того места, где я застрял:
(* Secret login credentials. *)
let username = "admin"
let password = "123456"
(* Create Eliom services. *)
let login_form_service = Eliom_service.create
~path:(Eliom_service.Path ["login"])
~meth:(Eliom_service.Get Eliom_parameter.unit)
()
let login_service = Eliom_service.create_attached_post
~fallback:login_form_service
~post_params:Eliom_parameter.(string "user" ** string "pass")
()
let admin_panel_service = Eliom_service.create
~path:(Eliom_service.Path ["admin-panel"])
~meth:(Eliom_service.Get Eliom_parameter.unit)
()
let session_username : string option Eliom_reference.eref =
Eliom_reference.eref ~scope:Eliom_common.default_session_scope None
(* Register Eliom services. *)
let () = Eliom_content.Html.D.(
Eliom_registration.Html.register
~service:login_form_service
(fun () () -> Lwt.return
(Eliom_tools.D.html
~title:"Login"
(body [h1 [pcdata "Login"];
Form.post_form
~service:login_service
(fun (user, pass) ->
[fieldset
[label [pcdata "Username: "];
Form.input ~input_type:`Text
~name:user
Form.string;
br ();
label [pcdata "Password: "];
Form.input ~input_type:`Password
~name:pass
Form.string;
br ();
Form.input ~input_type:`Submit
~value:"Login"
Form.string
]]) ()])));
Eliom_registration.Redirection.register
~service:login_service
(fun () (user, pass) ->
if user = username && pass = password then (
Eliom_reference.set session_username (Some username);
Lwt.return (Eliom_registration.Redirection admin_panel_service))
else
Lwt.return (Eliom_registration.Redirection login_form_service));
Eliom_registration.Html.register
~service:admin_panel_service
(fun () () ->
(* Admin panel html here ... *))
);
Каков правильный метод решения этой проблемы?
Спасибо.
1 ответ
Я не знаю, нашли ли вы решение, так как ваш вопрос уже устарел, но вот что я нашел:
Я использовал "Регистрация служб, которые решают, что они хотят отправить" с https://ocsigen.org/eliom/6.3/manual/server-outputs
Идея состоит в том, чтобы зарегистрировать ваши сервисы в Eliom_registration.Any, это позволяет обработчику, подключенному к сервису, на лету решить, какой тип ответа предоставить, используя соответствующую функцию отправки.
(* Secret login credentials. *)
let username = "admin"
let password = "123456"
(* Create Eliom services. *)
let login_form_service = Eliom_service.create
~path:(Eliom_service.Path ["login"])
~meth:(Eliom_service.Get Eliom_parameter.unit)
()
let login_service = Eliom_service.create_attached_post
~fallback:login_form_service
~post_params:Eliom_parameter.(string "user" ** string "pass")
()
let admin_panel_service = Eliom_service.create
~path:(Eliom_service.Path ["admin-panel"])
~meth:(Eliom_service.Get Eliom_parameter.unit)
()
let session_username : string option Eliom_reference.eref =
Eliom_reference.eref ~scope:Eliom_common.default_session_scope None
let login_panel () = Eliom_content.Html.D.(
Eliom_tools.D.html
~title:"Login"
(body [
h1 [pcdata "Login"];
Form.post_form
~service:login_service
(fun (user, pass) ->
[fieldset
[label [pcdata "Username: "];
Form.input ~input_type:`Text
~name:user
Form.string;
br ();
label [pcdata "Password: "];
Form.input ~input_type:`Password
~name:pass
Form.string;
br ();
Form.input ~input_type:`Submit
~value:"Login"
Form.string
]]) ()])
)
let admin_panel () = Eliom_content.Html.F.(
Eliom_tools.F.html
~title:"Fake Admin Panel"
(body [h1 [pcdata "Fake Admin Panel"];])
)
(* Some helper functions *)
let admin_credentials ~user_is_admin ~user_is_not_admin =
let%lwt usr = Eliom_reference.get session_username in
if usr = Some username then user_is_admin ()
else user_is_not_admin ()
let send_redirection service =
Eliom_registration.Redirection.send (Eliom_registration.Redirection service)
let send_page page =
Eliom_registration.Html.send page
(* Register Eliom services. *)
let () = Eliom_content.Html.D.(
Eliom_registration.Any.register
~service:login_form_service
(fun () () ->
admin_credentials
~user_is_admin:(fun () -> send_redirection admin_panel_service)
~user_is_not_admin:(fun () -> send_page (login_panel ()))
);
Eliom_registration.Redirection.register
~service:login_service
(fun () (user, pass) ->
if user = username && pass = password then (
let%lwt _ = Eliom_reference.set session_username (Some username) in
Lwt.return (Eliom_registration.Redirection admin_panel_service))
else
Lwt.return (Eliom_registration.Redirection login_form_service));
Eliom_registration.Any.register
~service:admin_panel_service
(fun () () ->
admin_credentials
~user_is_admin:(fun () -> send_page (admin_panel ()))
~user_is_not_admin:(fun () -> send_redirection login_form_service))
)