CromwellCMS / Cromwell

WordPress-like CMS for Next.js websites
https://cromwellcms.com
MIT License
699 stars 96 forks source link

feat: add roles and permission based auth #194

Closed eilrix closed 1 year ago

eilrix commented 2 years ago

This PR is basically a refactor of CMS authentication system to permission-based (previously role-based).

Now a user can have many or no roles. DB won't allow removing a role until it's used (foreign key constraint). But it can be removed via RoleRepository. While it's possible to modify roles manually in DB, changes won't be reflected immediately since we don't query roles table on every request (server restart needed). Plugin authors need to use API client or RoleRepository to create/update roles.

All admin panel pages are now tied to permissions. For example, product page requires read_products permission, etc. But note that some read permissions are not used on the server for public entities. For example, products have to be served without auth, so read_products is not required to have to get the data.

Permissions are not entity, since they aren't stored in DB. They are only stored in memory and registered dynamically. Permissions served from REST API: getRestApiClient().getPermissions() For a plugin it's possible to register new permission via registerPermission Permissions can be used for controllers/resolvers simply by passing a string to the decorator example Note that a permission used in decorator must also be registered via registerPermission

Role is an entity. I haven't added admin edit page for roles, but it can be created as any other entity page. It has all basic graphql methods and can be queried via getGraphQLClient().getRoles({ pageSize: 1000 }); Permissions of a role stored as string, it's easy to modify to any value.

Custom entities now have granular permissions. For example, different users can manage only their (different) custom entities. Permission edit of custom entities aren't in admin panel, but it can be modified via plugin. For example you can register custom entity:

registerCustomEntity({
  entityType: 'my_entity_name',
  listLabel: 'My entities',
  "permissions": {
                "read": "read_my_entity1",
                "update": "update_my_entity1"
   },
  columns: [
    {
      name: 'my_field',
      label: 'My field',
      type: 'Simple text'
    }
  ]
});

Note that by default (as before) custom entities are public to read. But if you add read permission it will be no longer public. To update your custom entity add update_my_entity1 to permission array of a role of your user.