You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Phoenix框架Bodyguard库conn变量报错排查及项目开发指导

Troubleshooting Conn-Related Errors with Bodyguard in Phoenix Post Controller & Next Steps

Let’s break down the most likely causes of your conn-related error in the PostController and walk through what code you’ll need to add to get your Bodyguard setup working properly.

First: Diagnose the Conn Error

The most common culprit here is a mismatch in how you’re calling Bodyguard’s permit/4 function, or missing setup to make the current user available in the conn. Here’s what to check first:

  1. You’re passing conn instead of the current user to Bodyguard.permit
    Bodyguard’s core permit function expects a user struct (not the conn itself) as the third argument. If you wrote something like:

    Bodyguard.permit(PostPolicy, :show, conn, post)
    

    That will throw an error because the policy’s can? function is expecting a user, not a Plug.Conn struct. The correct call should use conn.assigns.current_user:

    with :ok <- Bodyguard.permit(PostPolicy, :show, conn.assigns.current_user, post) do
      # render the post
    end
    
  2. conn.assigns.current_user doesn’t exist
    If you haven’t set up authentication middleware (plugs) to populate conn.assigns.current_user, Bodyguard won’t have a user to check permissions against. Verify that your router’s post routes are using a pipe that includes an auth plug (like :require_authenticated_user), and that this plug correctly fetches the logged-in user from the session and adds it to the conn.

  3. Your PostPolicy doesn’t implement the Bodyguard.Policy behaviour correctly
    Double-check that your policy module defines can?/3 functions that match the right arguments (user, action, resource). For example, a basic PostPolicy should look like this:

    defmodule Bg.PostPolicy do
      @behaviour Bodyguard.Policy
    
      # Allow any logged-in user to view the post list
      def can?(%Bg.Accounts.User{} = user, :index, _), do: true
      # Only allow owners to view/edit/delete their own posts
      def can?(%Bg.Accounts.User{} = user, action, %Bg.Blog.Post{} = post)
          when action in [:show, :update, :delete],
          do: user.id == post.user_id
      # Allow any logged-in user to create posts
      def can?(%Bg.Accounts.User{} = user, :create, _), do: true
      # Deny all other requests by default
      def can?(_, _, _), do: false
    end
    

    If your can? functions expect a conn instead of a user, that’ll also trigger errors.

Next: Code You Need to Add/Complete

Your project is missing a few key pieces to get Bodyguard fully functional:

  • Implement authentication plumbing
    If you haven’t already, you’ll need:

    • A User schema (with fields like email, hashed_password)
    • Registration and session controllers to handle user sign-up/login
    • Auth plugs to set current_user in the conn (Phoenix’s mix phx.gen.auth generator can auto-create all this for you quickly)
    • Update your router to pipe authenticated plugs into post routes, e.g.:
      scope "/", BgWeb do
        pipe_through [:browser, :require_authenticated_user]
      
        resources "/posts", PostController
      end
      
  • Add unauthorized handling
    Bodyguard lets you define how to handle denied requests. Add a handle_unauthorized/1 function to your PostPolicy (or directly in the controller) to return a user-friendly response:

    # In PostPolicy
    def handle_unauthorized(conn) do
      conn
      |> Phoenix.Controller.put_flash(:error, "You don't have permission to do that!")
      |> Phoenix.Controller.redirect(to: Routes.post_path(conn, :index))
    end
    
    # Then in your controller actions, handle the permit result:
    def show(conn, %{"id" => id}) do
      post = Bg.Blog.get_post!(id)
    
      case Bodyguard.permit(PostPolicy, :show, conn.assigns.current_user, post) do
        :ok -> render(conn, :show, post: post)
        {:error, :unauthorized} -> PostPolicy.handle_unauthorized(conn)
      end
    end
    
  • Validate all controller actions
    Make sure every action in PostController (index, create, update, delete) calls Bodyguard.permit with the correct user and resource. For example, the create action would check if the user can create posts before saving:

    def create(conn, %{"post" => post_params}) do
      with :ok <- Bodyguard.permit(PostPolicy, :create, conn.assigns.current_user, nil),
           {:ok, post} <- Bg.Blog.create_post(post_params) do
        conn
        |> put_flash(:info, "Post created successfully.")
        |> redirect(to: Routes.post_path(conn, :show, post))
      else
        {:error, :unauthorized} -> PostPolicy.handle_unauthorized(conn)
        {:error, %Ecto.Changeset{} = changeset} -> render(conn, :new, changeset: changeset)
      end
    end
    

Quick Debug Tip

If you’re still stuck, add IO.inspect(conn.assigns) at the start of your controller action to confirm whether current_user is present. If it’s not, your auth setup is the first thing to fix.

内容的提问来源于stack exchange,提问作者Yash Dani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:46:33