如何编写显示 HTML 或重定向到另一个页面的服务

How to write a service that either displays HTML or redirects to another page

在网络编程中,表单提交的常见模式是:

如何在 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 ... *))
);

解决这个问题的正确方法是什么?

谢谢。

我不知道你是否找到了解决方案,因为你的问题现在有点老了,但这是我找到的:

我使用了 https://ocsigen.org/eliom/6.3/manual/server-outputs#redirections

中的 "Registering services that decide what they want to send"

我们的想法是使用 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))
)