Comments (14)
@acrolink I just today released version 2.0.0 on Hex, so you can update your dependency now:
{:bodyguard, "~> 2.0.0"}
from bodyguard.
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.
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.
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.
@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.
@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.
@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.
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.
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.
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.
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.
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 (authorizeRepo.update(Post, ...)
)
Good luck!
from bodyguard.
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.
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)
- Support dynamic `params` on the `Bodyguard.Plug.Authorize` plug HOT 5
- Add default config for Bodyguard.Plug.Authorize plug options HOT 2
- Thoughts on scope/4 HOT 1
- Return type of Bodyguard.Authorize.init/1 HOT 2
- Why not use {:error, :forbidden} ? HOT 6
- Overriding schema in `scope/4` appears to be broken? HOT 1
- Accept {module, function} config for callback functions HOT 1
- Support for strong parameters? HOT 2
- Overriding plug HOT 1
- Please add example for using plugs with fallback controllers HOT 2
- Anonymous Function Example Broken? HOT 4
- Cut Release? HOT 1
- Compilation warnings on Elixir 1.11 HOT 2
- Need help to maintain bodyguard? HOT 12
- Update deps
- Type spec too restrictive?
- Allow to return `{:ok, data}` from authorize callbacks? HOT 2
- Readme example confusion HOT 1
- Is this project still maintained and/or relevant? HOT 2
- Add LiveView hook HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from bodyguard.