You are viewing Skygear v1 Documentation.Switch to Skygear v0 Documentation

Record-based ACL

Record-based ACL is useful when users have different access to each record.

Take Google doc as an example, you can only access a doc (a record) when the right is granted to you by the owner.

In Skygear, each record has a _access field, which stores the ACL of that record. You may update the ACL of a record by calling ACL API on the record and save it afterward.

Scroll to the bottom you will find an example of the application of the Record-based ACL.

Now let's have a look at how to set Record-based ACL.

To understand record-based ACL you need basic Skygear ACL concepts. Learn about it here if you haven't.

Record-based ACL of Public

Public ACL (including PublicNoAccess, PublicReadOnly and PublicReadWriteAccess) define the permission unauthenticated users have. You can change the record ACL for Public users as follows:

const secretNote = new Note({ content: 'I am your father' });
const publicNote = new Note({ content: 'Hello world!' });
const acl = new skygear.ACL();

secretNote.setPublicNoAccess();
publicNote.setPublicReadWriteAccess();
acl.setPublicReadOnly();

skygear.publicDB.save(publicNote);
skygear.publicDB.save(secretNote);
skygear.publicDB.setDefaultACL(acl)

Read access

Read access grants users right to query and fetch records, which includes getting all the fields of a record as well as the ACL of the record.

Write access

Write access grants users right to save and delete records, which includes adding, updating and removing all the fields (EXCEPT [reserved columns][doc-reserved-columns]) of a record as well as the ACL of the record.

Record-based ACL By User

Similarly with ACL of Public, you can set the NoAccessForUser, ReadOnlyForUser and ReadWriteAccessForUser) for each records.

Suppose you have three user records: Tak, Benson and Rick. And this is the security setting you want to apply to a note record:

  • Tak has no access to the note.
  • Benson can only read the note.
  • Rick can both read and write the note.
const Note = skygear.Record.extend('note');
const note = new Note({ content: 'demo user acl' });

note.setNoAccessForUser(Tak);
note.setReadOnlyForUser(Benson);
note.setReadWriteAccessForUser(Rick);
skygear.publicDB.save(note).then(...);

// check if users have read access or write access
note.hasReadAccessForUser(Tak); // false
note.hasWriteAccessForUser(Benson); // false

The default ACL in Skygear is public read. So if you didn't assign any ACL to Tak, he will be able to read the note.

Record-based ACL By Role

Similar to ACL by User, suppose you have three roles: Manager, Employee and Visitor. (Learn how to set roles here.)

const Plan = skygear.Record.extend('plan');
const plan = new Plan({ title: 'future goals for company' });

plan.setNoAccessForRole(Visitor);
plan.setReadOnlyForRole(Employee);
plan.setReadWriteAccessForRole(Manager);
skygear.publicDB.save(plan).then(...);

plan.hasReadAccessForRole(Employee); // true
plan.hasWriteAccessForRole(Manager); // true

Working with User and Role

If you are defining the ACL of a record with both specific users and roles, and you want to check if a user has access to a record.

const users = [ /* user records */ ];
const record = /* record */

skygear.auth.fetchUserRole(users).then((results) => {
  for (let user in users) {
    const userRoles = results[user._id];

    const hasReadAccess = record.access.hasReadAccess(user, userRoles);
    const hasWriteAccess = record.access.hasWriteAccess(user, userRoles);
  }
}, (error) => {
  console.log('Unable to fetch user roles', error);
});

Set default ACL for a record type

Instead of setting ACL of each record object as mentioned above, you may set the default ACL of all newly created records of a record type.

const acl = new skygear.ACL();
acl.setReadOnlyForRole(Visitor);

skygear.publicDB.setRecordDefaultAccess(Note, acl);

SDK Default ACL

On top of setting Record Default ACL, you can also change the default ACL settings locally. You may consider this as a convenient method of the SDK.

// giving admin role read write access to all new records
const Admin = new skygear.Role('admin');
acl.setReadWriteAccessForRole(Admin);
skygear.publicDB.setDefaultACL(acl);

After changing the default ACL setting, all records created in the future will automatically have this ACL setting; however, ACL setting for existing records created before this update will remain unchanged.

Record Creation Access

When you call save on skygear cloud database, it may perform create or update.

However, ACL is stored in _access field of a record, and this does not work for create, since the record is not existed yet. Thus, Skygear provide another API for setting ACL for record creation.

skygear.publicDB.setRecordCreateAccess(Note, [ Employee, Manager ]);
skygear.publicDB.setRecordCreateAccess(Plan, [ Manager ]);

// logged in as Employee
const newPlan = new Plan();
skygear.publicDB.save(newPlan).then(() => {
    // You will NOT succeed
}, () => {
    // You will get error here
});

Example: An In-house Collaborative Editing Application

For example, you want to design the security model for an in-house collaborative editing application. Each employee may join a group and create files, only group member have access to the files of the group.

You can define a role for admin, and define default ACL.

const File = skygear.Record.extend('file');
const Group = skygear.Record.extend('group');

const Admin = new skygear.Role('Admin')

const acl = new skygear.ACL();
acl.setPublicNoAccess();
acl.setReadWriteAccessForRole(Admin);

skygear.publicDB.setRecordDefaultAccess(File, acl);

You can define a role for each group.

const groupID = '...';
const GroupMember = new skygear.Role(`group:${groupID}:member`);

When an employee want to join the group, the employee need to request permission from the boss. Then the boss can assign the role to the employee.

// by the boss
const someUsers = [...];
skygear.auth.assignUserRole(someUsers, [GroupMember]).then(...);

When a new file is created, you can set ACL of the file with the role, so the new ACL will apply to the employees who have this role. Moreover, later when a member leave the group, you may simply revoke the user role and the user will no longer have access to the file. The ACL of file can remain unchanged.

// create a referece of an existing group record
const group = new Group({ _id: `group/${groupID}` });
const groupRef = new Skygear.Reference(group);

// create a new file object
const file = new File({
  group: groupRef,
  ... // other attrs
});

// define access rights of the file
file.setPublicNoAccess();
file.setReadWriteAccessForRole(GroupMember);

skygear.publicDB.save(file).then(...);

Now, you want to add a feature that a file can be shared to another employee that is not in the group, but that employee cannot edit the file.

const aFile = /* a file record */;
const aUser = /* a user record */;

aFile.setReadOnlyForUser(aUser);
skygear.publicDB.save(aFile).then(...);

Next Part