Git Product home page Git Product logo

Comments (14)

schrockwell avatar schrockwell commented on September 26, 2024 2

@acrolink I just today released version 2.0.0 on Hex, so you can update your dependency now:

  {:bodyguard, "~> 2.0.0"}

from bodyguard.

acrolink avatar acrolink commented on September 26, 2024 1

@schrockwell

Thank you. I have inserted this into a context file:

  def authorize(action, user, %{post: post}) 
    when action in [:show_post, :update_post, :delete_post] 
    and user.id == post.user_id, do: :ok

But I get a compilation error:

== Compilation error on file lib/app/content/content.ex ==
** (CompileError) lib/app/content/content.ex:29: cannot invoke remote function user.id/0 inside guard
    (stdlib) lists.erl:1353: :lists.mapfoldl/3
    (stdlib) lists.erl:1353: :lists.mapfoldl/3
    (stdlib) lists.erl:1354: :lists.mapfoldl/3
    lib/entre/content/content.ex:27: (module)
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6

Any idea what might be going on here? Thank you.

from bodyguard.

schrockwell avatar schrockwell commented on September 26, 2024 1

Oh I see that's an issue in the README. You'll need to pattern-match on the user IDs in order to use them in the guard clause:

  def authorize(action, %{id: user_id}, %{post: %{user_id: post_user_id}}) 
    when action in [:show_post, :update_post, :delete_post] 
    and user_id == post_user_id, do: :ok

from bodyguard.

lxcodes avatar lxcodes commented on September 26, 2024 1

EDIT: Whoops. Posted late. Sorry @schrockwell if I'm in correct anywhere.

@acrolink Rather new to Elixir and Phoenix, but I believe the entire point is to remove convention like authorize! which assumes there is a current_user and current_policy variable in context of where it is being run. We are re-writing an API current which used doorkeeper, Pundit, and pundit-resources where we have to juggle multiple variables of the same name but were actually different values.

In the second example, the authorize call is almost the same.

@post = Post.find(params[:id])
authorize! :update, @post

versus

post = Repo.get(Post, params[:id])
with :ok <- Bodyguard.permit(Post, :update_post, conn.assigns[:current_user], post: post) do
  # ...
end

In the Ruby example, if I wanted to not have an exception raised, I'd have to rescue and handle. In both cases, there needs to be view configuration to handle either the exception or the error case. In the Ruby case, if I run that authorize! in a background job though, I need to setup extra variables that aren't obvious when writing it. The Bodyguard statement on the other hand would act just the same.

I don't think trying to take access_granted (Rails) and directly apply it to Bodyguard (Phoenix) is the best way to look at things. Again, not the author and just another newb who might be assuming or wrong. I am just trying to explain maybe where the library is coming from.

from bodyguard.

lxcodes avatar lxcodes commented on September 26, 2024 1

@acrolink Maybe cu if you control where the assignment is or just assign to a user variable for line brevity.

user = conn.assigns[:cu]
with :ok <- Bodyguard.permit(Post, :update_post, user, post: post) do

from bodyguard.

lxcodes avatar lxcodes commented on September 26, 2024 1

@acrolink I haven't had time to play with yet, but there is also Bodyguard.Action (https://hexdocs.pm/bodyguard/Bodyguard.Action.html) which might get you closer to having default values for conventions in your application.

from bodyguard.

schrockwell avatar schrockwell commented on September 26, 2024 1

@acrolink Look at this post about overridingaction/2 in your controllers: https://dockyard.com/blog/2016/05/02/phoenix-tips-and-tricks

TLDR you override the action/2 callback so that your controller action signatures now look like:

def show(conn, params, current_user) do
  # Now you can use current_user
end

from bodyguard.

schrockwell avatar schrockwell commented on September 26, 2024

Hi @acrolink - bodyguard 2.0 isn't published on hex yet. Please use this dependency spec in mix.exs in the meantime:

{:bodyguard, github: "schrockwell/bodyguard", branch: "2.0-dev"},

from bodyguard.

acrolink avatar acrolink commented on September 26, 2024

I managed to retrieve the library but I get this error:

(CompileError) lib/project/web/views/session_view.ex:2: module Bodyguard.Controller is not loaded and could not be found

I had added import Bodyguard.Controller though to web.ex under controller and view.

from bodyguard.

schrockwell avatar schrockwell commented on September 26, 2024

Looks like you're referring to the old documentation. Please use the README on the 2.0-dev branch: https://github.com/schrockwell/bodyguard/tree/2.0-dev

from bodyguard.

acrolink avatar acrolink commented on September 26, 2024

I have managed to achieve the desired result where other libraries failed under Phoenix 1.3. Thank you very much. I needed to load the Post first and then pass it to permit function as parameter in order to see if the user owns that Post.

This library is promising, I will test and surely provide ideas. Meanwhile, I guess the coding can be little less verbose. I recommend inspecting this gem for Rails to possibly provide those little modifications to make this library great:

https://github.com/chaps-io/access-granted

with its marvelous:

role :member do
  can :update, Post do |post, user|
    post.author_id == user.id
  end
end

In controller's action one puts only:

  def update
    @post = Post.find(params[:id])
    authorize! :update, @post
...
  end

from bodyguard.

schrockwell avatar schrockwell commented on September 26, 2024

Glad you got it working and thanks for the feedback. The verbosity is actually a design decision brought on by a few things:

  • Phoenix (and Elixir in general) tends to favor explicitness over magic. To me, using a DSL to express authorization rules has never been flexible enough and is always more difficult to mentally unwrap than a pure function
  • Phoenix 1.3 moves away from a model-centric design, and so for a one-to-one mapping between actions and authorization, it makes sense to move the authorization to that context's boundary (authorize update_post) versus at the model level (authorize Repo.update(Post, ...))

Good luck!

from bodyguard.

schrockwell avatar schrockwell commented on September 26, 2024

Nope, you nailed it @al3x-edge. Bodyguard 1.x was a Pundit clone (check out the 1.x branch readme if you're curious), but as the direction for Phoenix changed it was clear to me that wasn't the right way to go.

from bodyguard.

acrolink avatar acrolink commented on September 26, 2024

Passing parameters of any kind to the function gives surely flexibility especially when special and checks need to be done. I will be looking forward to implement this library more thoroughly. BTW verbosity, is there a way to shorten con.assigns.current__user to something shorter that can be accesses anywhere within the application?

from bodyguard.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.