| Statements | Branches | Functions | Lines |
|---|---|---|---|
The authorization component is a flexible and extensible RBAC(role base access control) typescript library. It is designed using the plugin-architecture to allow for developers to easily implement and extend this library. This authorization component currently functions at the route based level.
A role will have a set of Permission. Each Permission will have the following attributes: effect, action, and subject. It could optionally contain a fields attribute. The effect will determine whether the role has ALLOW or DENY access for this permission. An action attribute can only be assigned one of the words from CRUD (CREATE, READ, UPDATE, DELETE). The subject represents the item in which the user wants to perform the action on. The optional fields attribute allows for access restriction to a subject's field (ex: a description would be a field of a Blog in which UPDATE access should be only ALLOW to certain roles).
A route that is being checked for authorization will have a set of Operation. Each Operation will have the following attributes: action and subject. It could optionally contain a field attribute. The action represents the required CRUD word for this route. The subject is what the route performs the action on. If a field is given, then it represents the field of a subject that the action will be performed on.
const guestPermissions: Permissions[] = [
{
effect: 'ALLOW',
action: 'CREATE',
subject: 'Blog'
},
{
effect: 'DENY'
action: 'UPDATE',
subject: 'Subscription'
}
];
const adminPermissions: Permissions[] = [
{
effect: 'ALLOW',
action: 'CREATE',
subject: 'Blog'
},
{
effect: 'ALLOW'
action: 'UPDATE',
subject: 'Subscription'
}
];const permissionsMap: PermissionsMap = {
guest: guestPermissions,
admin: adminPermissions
// Include more roles if needed
};This will map a route with an associated HTTPMethod to a set of Operations that need to be performed by that route.
const blogPostOperations: Operation[] = [
{
action: 'CREATE',
subject: 'Blog'
}
];
const subscriptionPutOperations: Operation[] = [
{
action: 'UPDATE',
subject: 'Subscription'
}
];
const routesMap: RoutesMap = {
'/blog': {
'POST': blogPostOperations
},
'/subscription' {
'PUT': subscriptionPutOperations
}
};const routesIgnored: RoutesIgnored = {
'/blog': {
'GET': true
}
};The StaticPermissionsPlugin is a PermissionsPlugin for the Authorization Service and helps manage the permissions for each role. Permissions defined with this plugin are meant to be static.
//StaticPermissionsPlugin requires a LoggingService to enable logging.
const logger:LoggingService = new LoggingService();
const staticPermissionsPlugin:StaticPermissionsPlugin = new StaticPermissionsPlugin(
mockPermissionsMap,
routesMap,
routesIgnored,
logger
);While the StaticPermissionsPlugin is a reference implementation, you are welcome to implement your own PermissionsPlugin to create more dynamic permissions mapping.
The CASLAuthorizationPlugin is an AuthorizationPlugin for the AuthorizationService and helps determine if a AuthenticatedUser can do a set Operations with their set of Permissions. The CASLAuthorizationPlugin uses CASL, an open-source authorization javascript library.
CASL (pronounced /ˈkæsəl/, like castle) is an isomorphic authorization JavaScript library which restricts what resources a given user is allowed to access. It's designed to be incrementally adoptable and can easily scale between a simple claim based and fully featured subject and attribute based authorization. It makes it easy to manage and share permissions across UI components, API services, and database queries.
const caslAuthorizationPlugin: CASLAuthorizationPlugin = new CASLAuthorizationPlugin();While the CASLAuthorizationPlugin is a reference implementation, you are welcome to implement your own AuthorizationPlugin.
The AuthorizationService is the core service of this library. It requires a PermissionsPlugin and AuthorizationPlugin in order to use it.
const authorizationService:AuthorizationService = new AuthorizationService(
caslAuthorizationPlugin,
staticPermissionsPlugin
);isAuthorizedOnRoute requires a AuthenticatedUser and the route and method they are trying to access. This request will throw an Error if a user is not authorized.
const guestUser:AuthenticatedUser = {
id: 'sampleId',
roles: ['guest']
}
try {
// This states that a guest user is requesting to POST to /blog
authorizationService.isAuthorizedOnRoute(guestUser, '/blog', 'POST');
} catch(err) {
console.log(err);
}Authorization implemented as a middleware is a common use case. This library contains an authorization middleware that integrates with ExpressJS. The middleware expects an AuthenticatedUser to be made availabe to it by using the local variables of ExpressJS.
const app = express();
// This example shows an authorization middleware with no mount path. Authorization will execute every time a request is received
app.use(WithAuth(authorizationService));REQUIRED:The middleware function needs to be mounted at the app level with no path, as it should execute every time a request is received. Click here for more information about ExpressJS middleware.