So far, the catalog data service uses basic authentication to protect its routes from unknown users; however, a catalog application should allow only few white-listed users to modify the items inside the catalog. To restrict access to the catalog, we will introduce the concept of authorization, that is, a subset of authenticated users, with appropriate permission allowed.
When Passport's done() function is invoked to authenticate a successful login, it takes as an argument a user instance of the user that has been granted authentication. The done() function adds that user model instance to the request object, and, in this way, provides access to it via the request.user property, after successful authentication. We will make use of that property to implement a function performing the authorization check after successful authentication:
function authorize(user, response) {
if ((user == null) || (user.role != 'Admin')) {
response.writeHead(403, { 'Content-Type' :
'text/plain'});
response.end('Forbidden');
return;
}
}
The authorize() function will close the response stream, returning the 403 Forbidden status code, which indicates that the logged-in user is recognized but has insufficient permissions. This revokes access to the resource. This function has to be used in each route that carries out data manipulation.
Here's an example of how a post route implements authorization:
app.post('/v2',
passport.authenticate('basic', { session: false }),
function(request, response) {
authorize(request.user, response);
if (!response.closed) {
catalogV2.saveItem(request, response);
}
}
);
After authorize() is invoked, we check whether the response object still allows writing to its output by checking the value of the closed property of the response object. It will return true once the end function of the response object has been called, which is exactly what the authorize() function does when the user lacks admin permissions. Thus, we can rely on the closed property in our implementation.