Skip to content

Instantly share code, notes, and snippets.

@jeffreypriebe
Last active March 17, 2018 09:50
Show Gist options
  • Save jeffreypriebe/5a49e9da48cc2180d84722a6f1c6960e to your computer and use it in GitHub Desktop.
Save jeffreypriebe/5a49e9da48cc2180d84722a6f1c6960e to your computer and use it in GitHub Desktop.
Keystone Admin User Role Permissions

The admin-user-roles-permissions has basic support for handling user permissions in the Keystone admin area.

It is comprised of basic parts:

  1. Additional fields on the user model (mentioned in steps below and also the User.js file)

    • isUserAdmin, isSuperAdmin and isPWD (the last one has permissions to edit any other user always)
    • Simply, each user has the ability to edit self and all users with fewer permissions.
  2. Exposure of these values (via virtuals) to the React admin/src/views/item.js route and to the server side jade templates and express routes.

    • Modification of the React and jade templates to display users according to the permisions.
  3. Selection from mongoose of fields that don't display in the list. (684a79f)

    • This allows hiding of users in the main list without showing the role information used in the selection logic.
  4. Express middleware userHandler (313649e) to end requests to user items that the logged in user isn't allowed.

Running in node v0.12 (since we're working off keystone v0.3). nvm use 0.12

Setup an old Keystone

Install the keystone generator that matches the previous v0.3.x branch (Oct 4, 2015 generator v0.3.9)

npm i git://github.com/keystonejs/generator-keystone.git#3584339

Setup the site with the generator (install yo if not already installed)

yo keystone

The user/roles code expects the default user model called "User"

Replace keystone with the user/roles branch

In node_modules/, remove the existing directory. rm -r keystone/

Clone the git repo inside the node_modules/ directory. git clone [email protected]:jeffreypriebe/keystone.git

Checkout the admin-user-roles-permissions branch. cd keystone git checkout admin-user-roles-permissions

Modify keystone-util in place for compatibly deps

The limax package that keystone-util depends on has an update that isn't compatible with node v0.12, change it to be get the specific version package before installing. cd node_modules/keystone-utils/ and then edit the package.json to change the limax to be 1.1.0 instead of ~1.1.10

Finally, install this keystone (cd ../../) npm i

Modify the User model

Modify the models/User.js file similar to what is shown below.

Note: the roleValue / permissions are output two ways (virtual roleValue and virtual clientOutput) since in v0.3 the browser client-side code of React needs the values to render the item correctly and the server-side needs them to render the list correctly (and also to check permissions on the item route).

Create a few users with some permissions

Simplest test is a user with Can access Keystone (.isAdmin) permission and then a second user with Can access Keystone and Can Manage Users (.isUserAdmin) permission.

Log in with the second user (the User Manager) and you can see the first user (but not the Admin user). If you set the first user to also be a user manager (.isUserAdmin) then the second user will no longer be able to see it.

var keystone = require('keystone');
var Types = keystone.Field.Types;
/**
* User Model
* ==========
*/
var User = new keystone.List('User');
User.add({
name: { type: Types.Name, required: true, index: true },
email: { type: Types.Email, initial: true, required: true, index: true },
password: { type: Types.Password, initial: true, required: true }
},
{ heading: "Permissions", dependsOn: { 'user.isUserAdmin': true } },
{ isAdmin: { type: Boolean, label: 'Can access Keystone', index: true, dependsOn: { 'user.isUserAdmin': true } } },
{ isUserAdmin: { type: Boolean, label: 'Can Manage Users', index: true, dependsOn: { 'user.isSuperAdmin': true } } },
{ isSuperAdmin: { type: Boolean, label: 'Super Administrator', index: true, dependsOn: { 'user.isPWD': true } } },
{ isPWD: { type: Boolean, label: 'Top Level Administrator', dependsOn: { 'user.isPWD': true } } }
);
// Provide access to Keystone
User.schema.virtual('canAccessKeystone').get(function() {
return this.isAdmin;
});
User.schema.virtual('roleValue').get(function() {
var vals = [this.isAdmin, this.isUserAdmin, this.isSuperAdmin, this.isPWD];
var val = 0;
for (var i = 0; i < vals.length; val |= vals[i] << i++);
return val;
});
User.schema.virtual('clientOutput').get(function() {
return {
isAdmin: this.isAdmin,
isUserAdmin: this.isUserAdmin,
isSuperAdmin: this.isSuperAdmin,
isPWD: this.isPWD
};
});
User.schema.pre('save', function (next) {
if (typeof this.isPWD === 'undefined') this.isPWD = false;
if (typeof this.isSuperAdmin === 'undefined') this.isSuperAdmin = this.isPWD;
if (typeof this.isUserAdmin === 'undefined') this.isUserAdmin = this.isSuperAdmin;
if (typeof this.isAdmin === 'undefined') this.isAdmin = this.isUserAdmin;
next();
});
/**
* Registration
*/
var defaultColumns = 'name, email, isAdmin';
User.defaultColumns = defaultColumns;
User.defaultListColumns = String.prototype.concat(defaultColumns, ', isUserAdmin, isSuperAdmin, isPWD');
User.register();
@binhwpo
Copy link

binhwpo commented Mar 17, 2018

Hi. Thanks for this. But I don't get one big point:

Why you guys don't create ONE FIELD: role = "Admin | UserAdmin | SuperAdmin | PWD" instead of making all complications of 4 fields?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment