gpt4 book ai didi

elixir - 如何在phoenix elixir中添加插件路由器

转载 作者:行者123 更新时间:2023-12-04 17:33:36 25 4
gpt4 key购买 nike

我为用户资源创建身份验证,它工作正常,但现在我想使用从 user_controller.ex 到 project_controller.ex 的身份验证功能。

如果我将身份验证私有(private)函数从 user_controller 复制到 project_controller,则身份验证适用于项目资源,但我不想在每个 Controller 中复制此身份验证功能。我需要知道干燥此代码的最佳方法是什么。我认为路由器是添加身份验证插件的好地方,但我需要知道我应该在哪里添加代码。

路由器.ex

defmodule Auth.Router do
use Auth.Web, :router

pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug Auth.Auth, repo: Auth.Repo
end

pipeline :api do
plug :accepts, ["json"]
end

scope "/", Auth do
pipe_through :browser # Use the default browser stack

get "/", PageController, :index
resources "/users", UserController
resources "/sessions", SessionController, only: [:new, :create, :delete]
resources "/projects", ProjectController
end
end

user_controller.ex
defmodule Auth.UserController do
use Auth.Web, :controller

plug :authenticate when action in [:index, :show]

alias Auth.User

plug :scrub_params, "user" when action in [:create, :update]

def index(conn, _params) do
users = Repo.all(User)
render(conn, "index.html", users: users)
end

def new(conn, _params) do
changeset = User.changeset(%User{})
render(conn, "new.html", changeset: changeset)
end

def create(conn, %{"user" => user_params}) do
changeset = User.registration_changeset(%User{}, user_params)

case Repo.insert(changeset) do
{:ok, user} ->
conn
|> Auth.Auth.login(user)
|> put_flash(:info, "#{user.username} created successfully.")
|> redirect(to: user_path(conn, :index))
{:error, changeset} ->
render(conn, "new.html", changeset: changeset)
end
end

def show(conn, %{"id" => id}) do
user = Repo.get!(User, id)
render(conn, "show.html", user: user)
end

def edit(conn, %{"id" => id}) do
user = Repo.get!(User, id)
changeset = User.changeset(user)
render(conn, "edit.html", user: user, changeset: changeset)
end

def update(conn, %{"id" => id, "user" => user_params}) do
user = Repo.get!(User, id)
changeset = User.changeset(user, user_params)

case Repo.update(changeset) do
{:ok, user} ->
conn
|> put_flash(:info, "User updated successfully.")
|> redirect(to: user_path(conn, :show, user))
{:error, changeset} ->
render(conn, "edit.html", user: user, changeset: changeset)
end
end

def delete(conn, %{"id" => id}) do
user = Repo.get!(User, id)
Repo.delete!(user)
conn
|> put_flash(:info, "User deleted successfully.")
|> redirect(to: user_path(conn, :index))
end

defp authenticate(conn, _opts) do
if conn.assigns.current_user do
conn
else
conn
|> put_flash(:error, "You must be login to access that page.")
|> redirect(to: page_path(conn, :index))
|> halt()
end
end
end

模型/user.ex
defmodule Auth.User do
use Auth.Web, :model

schema "users" do
field :username, :string
field :password_hash, :string
field :password, :string, virtual: true

timestamps
end

def changeset(model, params \\ :empty) do
model
|> cast(params, ~w(username), [])
|> validate_length(:username, min: 3, max: 20)

end

def registration_changeset(model, params) do
model
|> changeset(params)
|> cast(params, ~w(password), [])
|> validate_length(:password, min: 6, max: 100)
|> put_pass_hash()
end

defp put_pass_hash(changeset) do
case changeset do
%Ecto.Changeset{valid?: true, changes: %{password: pass}} ->
put_change(changeset, :password_hash, Comeonin.Bcrypt.hashpwsalt(pass))
_ ->
changeset
end
end
end

Controller /auth.ex
defmodule Auth.Auth do
import Plug.Conn
import Comeonin.Bcrypt, only: [checkpw: 2]

def init(opts) do
Keyword.fetch!(opts, :repo)
end

def call(conn, repo) do
user_id = get_session(conn, :user_id)
user = user_id && repo.get(Auth.User, user_id)
assign(conn, :current_user, user)
end

def login(conn, user) do
conn
|> assign(:current_user, user)
|> put_session(:user_id, user.id)
|> configure_session(renew: true)
end

def login_by_username_and_pass(conn, username, given_pass, opts) do
repo = Keyword.fetch!(opts, :repo)
user = repo.get_by(Auth.User, username: username)
cond do
user && checkpw(given_pass, user.password_hash) ->
{:ok, login(conn, user)}
user ->
{:error, :unauthorized, conn}
true ->
{:error, :not_found, conn}
end
end

def logout(conn) do
# configure_session(conn, drop: true)
delete_session(conn, :user_id)
end

end

Controller /project_controller.ex
defmodule Auth.ProjectController do
use Auth.Web, :controller

plug :authenticate when action in [:index, :new, :show]

alias Auth.Project

plug :scrub_params, "project" when action in [:create, :update]

def index(conn, _params) do
projects = Repo.all(Project)
render(conn, "index.html", projects: projects)
end

def new(conn, _params) do
changeset = Project.changeset(%Project{})
render(conn, "new.html", changeset: changeset)
end

def create(conn, %{"project" => project_params}) do
changeset = Project.changeset(%Project{}, project_params)

case Repo.insert(changeset) do
{:ok, _project} ->
conn
|> put_flash(:info, "Project created successfully.")
|> redirect(to: project_path(conn, :index))
{:error, changeset} ->
render(conn, "new.html", changeset: changeset)
end
end

def show(conn, %{"id" => id}) do
project = Repo.get!(Project, id)
render(conn, "show.html", project: project)
end

def edit(conn, %{"id" => id}) do
project = Repo.get!(Project, id)
changeset = Project.changeset(project)
render(conn, "edit.html", project: project, changeset: changeset)
end

def update(conn, %{"id" => id, "project" => project_params}) do
project = Repo.get!(Project, id)
changeset = Project.changeset(project, project_params)

case Repo.update(changeset) do
{:ok, project} ->
conn
|> put_flash(:info, "Project updated successfully.")
|> redirect(to: project_path(conn, :show, project))
{:error, changeset} ->
render(conn, "edit.html", project: project, changeset: changeset)
end
end

def delete(conn, %{"id" => id}) do
project = Repo.get!(Project, id)

# Here we use delete! (with a bang) because we expect
# it to always work (and if it does not, it will raise).
Repo.delete!(project)

conn
|> put_flash(:info, "Project deleted successfully.")
|> redirect(to: project_path(conn, :index))
end


# defp authenticate(conn, _opts) do
# if conn.assigns.current_user do
# conn
# else
# conn
# |> put_flash(:error, "You must be login to access that page.")
# |> redirect(to: page_path(conn, :index))
# |> halt()
# end
# end
end

最佳答案

这是一个相当普遍的模式。首先你需要你的认证插件:

defmodule Auth.Plug.Authenticate do
@behaviour Plug
import Plug.Conn
import Phoenix.Controller, only: [put_flash: 3, redirect: 2]

def init(opts), do: opts

def call(conn, _opts) do
if conn.assigns.current_user do
conn
else
conn
|> put_flash(:error, "You must be login to access that page.")
|> redirect(to: Auth.Router.Helpers.page_path(conn, :index))
|> halt()
end
end
end

然后在您的路由器中,您可以执行以下操作:
defmodule Auth.Router do
use Auth.Web, :router

pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug Auth.Auth, repo: Auth.Repo
end

pipeline :authenticated do
plug Auth.Plug.Authenticate, repo: Auth.Repo
end

pipeline :api do
plug :accepts, ["json"]
end

scope "/", Auth do
pipe_through :browser # Use the default browser stack

get "/", PageController, :index
resources "/sessions", SessionController, only: [:new, :create]
end

scope "/", Auth do
pipe_through [:browser, :authenticated]

resources "/users", UserController
resources "/sessions", SessionController, only: [:delete]
resources "/projects", ProjectController
end
end

关于elixir - 如何在phoenix elixir中添加插件路由器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33219200/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com