Comments (27)
hey,
I've got no working example. Which version of feathers do you use? Is it generated by @feathersjs/cli
or how do you organize it? If you like, share your authentication.js
or just some parts.
from feathers-casl.
Thank you for your reply (it's my first issue request on Github).
I use Feathers 4.5.11, I tried to set Feathers-casl up on a stock and fresh CLI generated app (with NeDB).
So the basic authentication.js file is
const { AuthenticationService, JWTStrategy } = require('@feathersjs/authentication');
const { LocalStrategy } = require('@feathersjs/authentication-local');
const { expressOauth } = require('@feathersjs/authentication-oauth');
module.exports = app => {
const authentication = new AuthenticationService(app);
authentication.register('jwt', new JWTStrategy());
authentication.register('local', new LocalStrategy());
app.use('/authentication', authentication);
app.configure(expressOauth());
};
If, in the same file, I register "authentication" service and hooks that lets trig authentication.hooks.js
const { AuthenticationService, JWTStrategy } = require('@feathersjs/authentication');
const { LocalStrategy } = require('@feathersjs/authentication-local');
const { expressOauth } = require('@feathersjs/authentication-oauth');
const hooks = require('./services/authentication/authentication.hooks'); // require authentication.hooks
module.exports = app => {
const authentication = new AuthenticationService(app);
authentication.register('jwt', new JWTStrategy());
authentication.register('local', new LocalStrategy());
app.use('/authentication', authentication);
app.service('authentication').hooks(hooks); //register authentication service and hooks
app.configure(expressOauth());
};
is that the good way to do it ?
from feathers-casl.
Yep, that's definitely a way.
You should have at least a folder with src/services/users
containing users.service.js
and users.hooks.js
. Since the authentication is just another service (like all the other services), I handle it the exact same way.
Your authentication.js
file is pretty much the same as users.service.js
, so I renamed the authentication.js
file in authentication.service.js
and followed the same way as in users.service.js
to register the hooks.
After this setup your after:create
hook in authentication.hooks.js
does not get called? If so, what does your authentication.hooks.js
look like?
from feathers-casl.
So, I renamed (just to follow your logic) ./src/authentication.js in authentication.service.js and move it to ./src/services/authentication/
Authentication service hooks are now called. ability and rules props are present in POST authentication response.
authentication.abilities.js and authentication.hooks.js are exactly de same as your example (copy/past) in your "Getting Started" section.
the only last thing I did is to add authorize() hook to tasks.hooks.js
const { authenticate } = require('@feathersjs/authentication').hooks;
const { authorize } = require('feathers-casl').hooks;
module.exports = {
before: {
all: [authenticate('jwt')],
find: [
authorize({ checkAbilityForInternal: true }) // make sure this hook runs always last
],
get: [
authorize({ checkAbilityForInternal: true }) // make sure this hook runs always last
],
create: [
authorize({ checkAbilityForInternal: true }) // make sure this hook runs always last
],
update: [
authorize({ checkAbilityForInternal: true }) // make sure this hook runs always last
],
patch: [
authorize({ checkAbilityForInternal: true }) // make sure this hook runs always last
],
remove: [
authorize({ checkAbilityForInternal: true }) // make sure this hook runs always last
]
},
after: {
all: [
authorize({ checkAbilityForInternal: true }), // make sure this hook runs always first
],
find: [],
get: [],
create: [],
update: [],
patch: [],
remove: []
},
error: {
all: [],
find: [],
get: [],
create: [],
update: [],
patch: [],
remove: []
}
};
from feathers-casl.
So is there anything left?^^
from feathers-casl.
If not, you could close the issue then. I won't add an example for now, but will keep it in my mind for later.
Do you know of the feathers slack group? It's a better place for general questions. http://slack.feathersjs.com/ :)
from feathers-casl.
Maybe it's a misunderstanding of CASL, but if I do a GET/READ (find) request on tasks service, I still have all tasks. not only tasks owned by the current authenticated user (use id : 75RYYlBKLp2HyAeF) .
{
"total": 2,
"limit": 10,
"skip": 0,
"data": [
{
"text": "my task 1",
"userId": "75RYYlBKLp2HyAeF",
"_id": "3ZLQN4eiLCQzsPjk"
},
{
"text": "my task 2",
"userId": "foobar",
"_id": "fwracLtabKpi2GX2"
}
]
}
Should it not be "filtered" by
can('manage', 'tasks', { userId: user.id });
PS: Thank you for the feathers slack channel.
from feathers-casl.
Please post all your rules and what is the output of console.log(user.id)
?
In a hook right before the authorize()
-hook, what is the output of console.log(context.params.user)
and console.log(context.params.ability)
?
from feathers-casl.
Here is the authentication.abilites.js
const { AbilityBuilder, createAliasResolver, makeAbilityFromRules } = require('feathers-casl');
// don't forget this, as `read` is used internally
const resolveAction = createAliasResolver({
update: 'patch', // define the same rules for update & patch
read: ['get', 'find'], // use 'read' as a equivalent for 'get' & 'find'
delete: 'remove' // use 'delete' or 'remove'
});
const defineRulesFor = (user) => {
// also see https://casl.js.org/v5/en/guide/define-rules
const { can, cannot, rules } = new AbilityBuilder();
console.log(user.id) //debug purpose
if (user.role && user.role.name === 'SuperAdmin') {
// SuperAdmin can do evil
can('manage', 'all');
return rules;
}
if (user.role && user.role.name === 'Admin') {
can('create', 'users');
}
can('read', 'users');
can('update', 'users', { id: user.id });
cannot('update', 'users', ['roleId'], { id: user.id });
cannot('delete', 'users', { id: user.id });
can('manage', 'tasks', { userId: user.id });
can('create-multi', 'posts', { userId: user.id })
return rules;
};
const defineAbilitiesFor = (user) => {
const rules = defineRulesFor(user);
return makeAbilityFromRules(rules, { resolveAction });
};
module.exports = {
defineRulesFor,
defineAbilitiesFor
};
console.log(user.id)
returned undefined
and in tasks.hooks.js
const { authenticate } = require('@feathersjs/authentication').hooks;
const { authorize } = require('feathers-casl').hooks;
module.exports = {
before: {
all: [authenticate('jwt')],
find: [
(context) => {
console.log(context.params.user) //debug purpose
console.log(context.params.ability) //debug purpose
},
authorize({
checkAbilityForInternal: true,
}) // make sure this hook runs always last
],
//[...]
context.params.user
returned
{
email: '[email protected]',
password: '$2a$10$tTeAjaao60c0f7n1zIrlOubu6pNpRnckYFI37drSOmjYebVmfkrte',
firstname: 'Alex',
lastname: 'Auss',
active: true,
_id: '75RYYlBKLp2HyAeF'
}
and context.params.user
returned undefined
I just publish a repo with my files :
https://github.com/alxblog/feathers-casl-example
from feathers-casl.
multiple problems here:
- you use
_id
, notid
- if
context.params.ability
is undefined, soauthorize()
will be skipped at all
Please set some breakpoints here and there and see how it goes. First of all check the hook inauthentication.hooks.js
, then yourauthentication.abilities.js
.
from feathers-casl.
did you find the error? What was the problem?
If there's anything left, let me know.
from feathers-casl.
I'd also be interested in solving this. I have the same problem, although I am authenticating with Auth0 tokens and apparently authentication.hooks.js
never gets called again after I initially authenticated. Every subsequent request only contains an access token that gets validated and then the appropriate user
object is added to params. This way the abilities remain unset, except for the initial authentication.
I was under the impression I am just using this wrong somehow. Is the create
hook in authentication.hooks.js
meant to be invoked on every request to add abilities or couldn't I just add the abilities in an extra hook after authenticate('auth0')
? In the latter case, I'd need to add this for every service using CASL which is not mentioned in the docs.
from feathers-casl.
FYI, if I add this in my service's before
hook, it works:
all: [
authenticate('auth0'),
context => {
const { user } = context.params
if (user) context.params.ability = defineAbilitiesFor(user)
return context
}
]
from feathers-casl.
This is what is recommended to do in the docs
But in the after hook of the authentication service.
feathers-casl by default looks for context.params.ability in the authorize-hook and connection.ability in the channels.
You want to authorize users who are authenticated first with @feathers/authentication.
We can add hooks to the /authentication service to populate things to context.params and connection under the hood.
We use this here to put ability on these objects, which makes it available to all hooks after the authenticate(...)-hook.
This way we can define rules in just one place:
// src/services/authentication/authentication.hooks.js
const { defineAbilitiesFor } = require('./abilities');
module.exports = {
after: {
create: [
context => {
const { user } = context.result;
if (!user) return context;
const ability = defineAbilitiesFor(user);
context.result.ability = ability;
context.result.rules = ability.rules;
return context;
}
],
},
};
from feathers-casl.
Yes, but this hook is never called during a request for a resource from a service other than authentication
. Thus, the abilities
prop stays undefined
.
from feathers-casl.
Maybe this is specific to my authentication strategy and other strategies are using the create
hook of authentication
? Not sure if the create
hook is meant to be called on every request.
from feathers-casl.
It's not. It's only called on feathersClient.authenticate(...)
. My use case is, that defineAbilitiesFor()
populates all permissions, that are available for that user.
Why do you want to run defineAbilitiesFor
on every request?
from feathers-casl.
Well, I guess I am just using it wrong. The thing that bothers me is that if I make a find
request for a service:
- The
authenticate('auth0')
hook inbefore.all
validates the token and adds auser
toparams
. - Next in line is the
authorize({ adapter: 'feathers-mongoose' })
hook inbefore.find
, but that one skips becauseabilities
is not set.
Sorry if I'm being stupid here, but I don't see how the abilities get enforced on the request result here.
from feathers-casl.
What's your transport? express.js or socket.io?
from feathers-casl.
That's express. Thanks for the quick response, btw.
from feathers-casl.
Unfortunately it's not working for express the way it's stated in the docs. I noticed that a few days ago. There should be a note in the docs and a recommended way for express.
@dasantonym Are you up to add that to the docs in any way? Any help would be appreciated.
from feathers-casl.
I see, alright then, at least I can stop worrying about my sanity. Thanks for the clarification and sure, I'll add the relevant info to the docs. I'll open a pull request and you can check if I got everything right.
from feathers-casl.
Nice. Thanks in advance and sorry for the confusion!
Greets from Rostock to Mainz :)
from feathers-casl.
Hehe, never mind and hallo nach Rostock!
from feathers-casl.
Ah, actually one more question: In my hook I am only adding the ability
prop to params and not the rules
. It works, but are the rules needed there?
from feathers-casl.
The rules
aren't used on the server anywhere. In my application (mainly socket.io), the rules
get populated to the authResult and therefore are in the response on the client side. I use vue
along with @casl/vue
to use the permissions on the client side, which is pretty useful for UX (disabling/enabling buttons). I also have rules like: can('view', 'dashboard')
stored in my db. The example for vue.js is also in the docs.
from feathers-casl.
Alright, thanks for clarifying, I hadn't looked at the Vue integration yet at all. Very nice!
from feathers-casl.
Related Issues (20)
- Documentation Difficulties
- Channels: function with initial Channel | Channel[] | Connection[] for calculations before feathers-casl
- new util to update connections
- new flag for hook: `useOptionsOverParamsAbility`
- Next version for feathers 5 HOT 3
- Nest JS authorization with CASL doesn't work as expected HOT 1
- You're not allowed to get on 'users' HOT 3
- AbilityBuilder expected 1 arguement, but got 0 HOT 3
- Is the anonymous channel needed anymore? HOT 7
- Remove ability on logout
- remove: No record found for id HOT 5
- Missing resource results in "You are not allowed to get X" message HOT 3
- [Question] Custom adapter HOT 1
- How can we express an ltree condition with feathers-casl? HOT 1
- [email protected] - error with 'feathers-utils' is a CommonJS module HOT 2
- Support for casl v6 ? HOT 2
- Documentation contains non-existent reference to @casl/ability -> makeAbilityFromRules HOT 3
- Documentation section 'add-abilities-to-hooks-context': wrong import file reference
- Ability to have multiple "stages" for permissions?
- find rule with restricted field not working HOT 2
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 feathers-casl.