0

I'm having trouble figuring out how to exclude certain fields from the associated model from being returned in a query.

I've got a user-membership setup working, using a "users" model, which is associated to the "groups" model via a many-to-many relationship like this:

    users.belongsToMany(models.groups, {through:'group_users'});
    groups.belongsToMany(models.users, {through:'group_users'});

When I do a feathers GET for a specific group record, using a sequelize.include statement , the corresponding users are all returned in a "users" array along with the group.

    {
    id:123,
    name:"testGroup"
    users:[
       {
    id:1,
    firstname:"bob"
    email:"bob@bob.com"
    password:"pass"
       },
    
       {
    id:2,
    firstname:"doug"
    email:"doug@doug.com"
    password:"pass"
       }
    ]

So far so good. Except I want to hide the email and password fields in the returned data...

I have tried setting a defaultScope on the users model to exclude:["password", "email"], and that definitely works, but it also breaks the authentication plugin, so I can't login anymore...

I have tried the hooks-common "protect" method, to protect("password"), and also tried protect("users.password"), but neither had any affect.

How am I 'supposed' to accomplish something like this? Do I have to build a custom 'after' filter hook? Is there a way to accomplish this at the model or class level so that 'most' of the time these fields aren't returned, except when specifically requested?

Thanks!

Ken White
  • 123,280
  • 14
  • 225
  • 444

1 Answers1

0

In the /services folder, go to the groups service you are getting the data from(your groups /GET path not the /users), and in the groups.hook.js add

const { protect } = require("@feathersjs/authentication-local").hooks;

module.exports = {
  after: {
    all: [],
    find: [      
      protect(
        ["users.email"]
        ["users.password"]
      ),
    ],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: [],
  },
};
Youzef
  • 616
  • 1
  • 6
  • 23
  • Thank you very much for your help, Youzef. Unfortunately, it didn't work. At the top level, 'protect' worked fine, but for any of the associated sub-records 'users.password' did not have any affect. I have found a solution using "scopes" based on this article: https://dev.to/a0viedo/handling-sensitive-fields-with-sequelize-js-54lo VERY IMPORTANT to note that the {defaultScopes} definition needs to appear immediately after the fields. When I tried putting it at the end of the definition statements it did nothing, but after the fields it worked fine. Thanks! – David Robert Hoare Nov 30 '22 at 19:05
  • further to above: while that worked, it also removed 'password' from the local-authentication process, which broke the login process. So I had to add to override the findEntity() function in that authentication LocalStrategy, adding specifying a different 'fullDetails' scope that I had also defined in the users model. I must say I'm confused by the lack of documentation on what I think should be a fairly common problem (hiding security fields from associated records...) but maybe I'm trying to do it all wrong... – David Robert Hoare Nov 30 '22 at 21:12