Dead simple role and group management.
Install the core packages
npm i -S roles-client roles-server
Install the server transport
npm i -S roles-rest-express
Install the data store
npm i -S roles-redis
Install the React component
npm i -S roles-react
To begin you'll need to initialize Roles by calling Roles.init both on the client and the server. To Roles.init you provide an options object and an object implementing the userIsInRole and userIsInGroup functions. Below is an example of their implementation using fetch.
Browser
import Roles from 'roles-client';
Roles.init({
path: '/roles' // This is the default
}, {
async userIsInRole(role, group) {
const res = await (await fetch(`${process.env.AUTH_SERVER}${Roles.options.path}/userIsInRole`, {
method: 'POST',
body: JSON.stringify({
role,
group,
}),
})).json();
return res.inRole;
},
async userIsInGroup(group) {
const res = await (await fetch(`${process.env.AUTH_SERVER}${Roles.options.path}/userIsInGroup`, {
method: 'POST',
body: JSON.stringify({
group,
}),
})).json();
return res.inGroup;
},
});Similar to the initialization of Roles on the client, the first paramter of Roles.init is an options object, the second parameter is a data store. In the following example it comes from roles-redis. There is also a third parameter providing an object with a findUserById function. This is used in order to find and verify the existence of userIds passed to Roles's functions. You must provide this function.
Finally on the server, you need to create the REST routes for roles, this is done by using app.use(rolesExpress(Roles)).
Server
import express from 'express';
import bodyParser from 'body-parser';
import Roles from 'roles-server';
import rolesExpress from 'roles-rest-express';
import RolesRedis from 'roles-redis';
Roles.init({
path: '/roles' // This is the default
}, new RolesRedis({
port: 6379,
}), {
findUserById: userId => Accounts.findUserById(userId),
});
const PORT = 3010;
const app = express()
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(rolesExpress(Roles));
app.listen(PORT, () => console.log( // eslint-disable-line no-console
`API Server is now running on http://localhost:${PORT}`,
));Assign a user to some roles and a group. If the provided roles or group do not exist they will be created.
await Roles.addUserToRoles(userId, ['create', 'read', 'update', 'delete'], 'admin')You can check if a user belongs to a role or a group.
await Roles.addUserToRoles(userId, ['create', 'read', 'update', 'delete'], 'admin')
await Roles.userIsInRole(userId, 'create', 'admin') // Returns true
await Roles.userIsInRole(userId, ['create', 'bad-role'], 'admin') // Returns false
await Roles.userIsInGroup(userId, 'admin') // Returns trueTo remove a user from roles or a group
await Roles.addUserToRoles(userId, ['create', 'read', 'update', 'delete'], 'admin')
// Remove the user from roles
await Roles.removeUserFromRoles(userId, ['create', 'read', 'update'], 'admin')
await Roles.userIsInRole('delete', 'admin') // Returns true
await Roles.userIsInGroup(userId, 'admin') // Returns true
// Remove the user from group and all the roles in that group
await Roles.removeUserFromGroup(userId, 'admin')
await Roles.userIsInGroup(userId, 'admin') // Returns falseNote: if you omit a group parameter in API calls the default group will be used.
The roles-react package provides some useful component called RoleCheck. This lets you do role checking within your React components. Below the covers RoleCheck is calling Roles.userIsInRole and Roles.userIsInGroup based on the props you pass it. group is always required, roles are optional and can be a string or an array of strings.
import RoleCheck from 'roles-react';
const Example = () =>
<div>
Anyone can see this.
<RoleCheck roles="view-example" group="admin">
Only users which pass the role check can see this.
</RoleCheck>
</div>To use with react-router pass ({ children }) => RoleCheck as the component prop of a Route. This will only render the Route's children if the role check passes.
const adminRoutes = () => (
<Route component={({ children }) => <RoleCheck roles="manage" group="user">{children}</RoleCheck>}>
<Route path="/admin" />
</Route>
)Client
init(options: Object, transport: Object) : void
userIsInRole(roles: String | [String], group: String) : Promise<Boolean>
userIsInGroup(group: String) : Promise<Boolean>Server
type Role = {
role: String
roleId: String
group: String
groupId: String
}
type AllRoles = {
[groupId: String]: {
groupId: String
group: String
roles: {
[roleId: String] : {
roleId: String
role: String
}
}
}
}
type UserRoles = {
[roleId: String] : {
role: String
group: String
groupId: String
}
}
type UserGroups = {
[groupId: String]: String
}
addUserToRoles(userId: String | [String], roles: String | [String], group: String) : Promise<Boolean>
createRole(role: String, group: String) : Promise<Role>
deleteGroup(group: String) : Promise<void>
deleteRole(role: String, group: String) : Promise<void>
findById(roleId: String) : Promise<Role>
getAll() : Promise<AllRoles>
getGroupsForUser(userId: String): Promise<UserGroups>
getRolesForUser(userId: String): Promise<UserRoles>
getUsersInGroup(group: String): Promise<[String]>
getUsersInRole(role: String, group: String): Promise<[String]>
init(options: Object, store: Object, userResolver: Object) : void
removeUserFromGroup(userId: String | [String], group: String) : Promise<Boolean>
removeUserFromRoles(userId: String | [String], roles: String | [String], group: String) : Promise<Boolean>
roleExists(role: String, group: String): Promise<Boolean>
userIsInGroup(group: String) : Promise<Boolean>
userIsInGroup(userId: String, group: String) : Promise<Boolean>
userIsInRole(userId: String, role: String, group: String) : Promise<Boolean>