Elixir Phoenix上下文授权(有和没有)

时间:2017-08-13 12:16:55

标签: elixir phoenix-framework

我按照完整的教程解释了如何处理上下文& @chrismccord的身份验证/授权...我利用他的帖子关于将auth从dockyard blog解耦:slight_smile:auth for phoenix contextAdding CMS functions in phoenix context

根据这一点,在我的情况下( CMS ENR ),所有创建的学生都需要一个注册者,注册者通过自己的会话链接到用户(经过身份验证) :学生 - > belongs_to Enroller,Enroller - > belongs_to用户,用户拥有自己的凭据。

resources "/students", StudentController受到保护,这很好。

但现在我想揭露一些事实:如果我们想让学生自己注册怎么办?代码看起来如何?

自我注册或自行注册,而不是由管理员的人做...这将是好的。

这是我做的,但我总是重定向到身份验证页面,结果是: “你必须登录”

  1. 当管理员登录/注册时......他/她可以通过以下方式实现管理任务(创建:学生,登记者,页面等):

    scope "/enr", HelloWeb.ENR, as: :enr do
    
      pipe_through [:browser, :authenticate_user]
      resources "/admissions", AdmissionController
    end
    
  2. 承认任务

    1. 如前所述,如果我们认为范围CMS或(ENR)是管理员部分,我们希望学生通过注册自己公共部分我做了这样的路线:
    2.     scope "/", InsWeb do
              pipe_through :browser # Use the default browser stack
      
              get "/", PageController, :index
              resources "/users", UserController
              resources "/sessions", SessionController, only: [:new, :create, :delete],
                                                    singleton: true
              resources "/admissions", AdmissionController, only: [:new, :create, :show]
            end
      
            scope "/ENR", InsWeb.ENR, as: :enr do
              pipe_through [:browser, :authenticate_user]
      
              resources "/admissions", AdmissionController
            end
      
            defp authenticate_user(conn, _) do
              case get_session(conn, :user_id) do
                nil ->
                  conn
                  |> Phoenix.Controller.put_flash(:error, "Login required")
                  |> Phoenix.Controller.redirect(to: "/")
                  |> halt()
                user_id ->
                  assign(conn, :current_user, Ins.Accounts.get_user!(user_id))
              end
            end
      

      一切似乎都很好我通过公共部分到达了录取页面,但是当我提交表格时====没有......我总是得到“需要登录” 所以不允许学生自行注册......

      1. CMS {EN}我的案例中的AdmissionController.ex范围如下:

          defmodule InsWeb.ENR.AdmissionController do
            use InsWeb, :controller
        
            plug :require_existing_enroller
            plug :authorize_admission when action in [:edit, :update, :delete]
        
            alias Ins.ENR
            alias Ins.ENR.Admission
        
            def index(conn, _params) do
              admissions = ENR.list_admissions()
              render(conn, "index.html", admissions: admissions)
            end
        
            def new(conn, _params) do
              changeset = ENR.change_admission(%Admission{})
              render(conn, "new.html", changeset: changeset)
            end
        
            def create(conn, %{"admission" => admission_params}) do
              case ENR.create_admission(conn.assigns.current_enroller, admission_params) do
                {:ok, admission} ->
                  conn
                  |> put_flash(:info, "Admission created successfully.")
                  |> redirect(to: enr_admission_path(conn, :show, admission))
                {:error, %Ecto.Changeset{} = changeset} ->
                  render(conn, "new.html", changeset: changeset)
              end
            end
        
            def show(conn, %{"id" => id}) do
              admission = 
                id
                |> ENR.get_admission!()
                |> ENR.inc_admission_views()
        
              render(conn, "show.html", admission: admission)
            end
        
            def edit(conn, %{"id" => id}) do
              admission = ENR.get_admission!(id)
              changeset = ENR.change_admission(admission)
              render(conn, "edit.html", admission: admission, changeset: changeset)
            end
        
            def update(conn, %{"id" => id, "admission" => admission_params}) do
              admission = ENR.get_admission!(id)
        
              case ENR.update_admission(conn.assigns.admission, admission_params) do
                {:ok, admission} ->
                  conn
                  |> put_flash(:info, "Admission updated successfully.")
                  |> redirect(to: enr_admission_path(conn, :show, admission))
                {:error, %Ecto.Changeset{} = changeset} ->
                  render(conn, "edit.html", admission: admission, changeset: changeset)
              end
            end
        
            def delete(conn, %{"id" => id}) do
              admission = ENR.get_admission!(id)
              {:ok, _admission} = ENR.delete_admission(conn.assigns.admission)
        
              conn
              |> put_flash(:info, "Admission deleted successfully.")
              |> redirect(to: enr_admission_path(conn, :index))
            end
        
            defp require_existing_enroller(conn, _) do
              enroller = ENR.ensure_enroller_exists(conn.assigns.current_user)
              assign(conn, :current_enroller, enroller)
            end
        
            defp authorize_admission(conn, _) do
              admission = ENR.get_admission!(conn.params["id"])
        
              if conn.assigns.current_enroller.id == admission.enroller_id do
                assign(conn, :admission, admission)
              else
                conn
                |> put_flash(:error, "You can't modify that admission page")
                |> redirect(to: enr_admission_path(conn, :index))
                |> halt()
              end
            end
        
          end
        
      2. 另一个来自 CMS

              defmodule InsWeb.AdmissionController do
                use InsWeb, :controller
        
                alias Ins.ENR
                alias Ins.ENR.Admission
        
                def new(conn, _params) do
                  changeset = ENR.change_admission(%Admission{})
                  render(conn, "new.html", changeset: changeset)
                end
        
                def create(conn, %{"admission" => admission_params}) do
                  case ENR.create_admission(conn.assigns.current_enroller, admission_params) do
                    {:ok, admission} ->
                      conn
                      |> put_flash(:info, "Admission created successfully.")
                      |> redirect(to: enr_admission_path(conn, :show, admission))
                    {:error, %Ecto.Changeset{} = changeset} ->
                      render(conn, "new.html", changeset: changeset)
                  end
                end
        
                def show(conn, %{"id" => id}) do
                  admission = 
                    id
                    |> ENR.get_admission!()
        
                  render(conn, "show.html", admission: admission)
                end
        
              end
        

        任何帮助将不胜感激!谢谢!

        以下是其他内容

        1. /templates/enr/admission/form.html.eex

          <%= form_for @changeset, @action, fn f -> %>
            <%= if @changeset.action do %>
              <div class="alert alert-danger">
                <p>Oops, something went wrong! Please check the errors below.</p>
              </div>
            <% end %>
          
            <div class="form-group">
              <%= label f, :first_name, class: "control-label" %>
              <%= text_input f, :first_name, class: "form-control" %>
              <%= error_tag f, :first_name %>
            </div>
          
            <div class="form-group">
              <%= label f, :last_name, class: "control-label" %>
              <%= text_input f, :last_name, class: "form-control" %>
              <%= error_tag f, :last_name %>
            </div>
          
            <div class="form-group">
              <%= label f, :views, class: "control-label" %>
              <%= number_input f, :views, class: "form-control" %>
              <%= error_tag f, :views %>
            </div>
          
            <div class="form-group">
              <%= submit "Submit", class: "btn btn-primary" %>
            </div>
          <% end %>
          
        2. /templates/enr/admission/new.html.eex

          <h2>New Admission</h2>
          
          <%= render "form.html", Map.put(assigns, :action, enr_admission_path(@conn, :create)) %>
          
          <span><%= link "Back", to: enr_admission_path(@conn, :index) %></span>
          

1 个答案:

答案 0 :(得分:1)

根据您的定义,您的AdmissionController.create操作应该有两种方法:

  1. admission_path(conn, :create) - /admissions
  2. 的POST路线
  3. enr_admission_path(conn, :create) - /ENR/admissions
  4. 的POST路线

    我可以想象,在你的new.eex模板中,form_for方法中使用了第二个,因此每个用户都需要登录。

    我会改用两个控制器。如果它不适合您,您需要做出决定,应该使用哪条路线。这取决于用户是否已登录。