This is a personal blog post that is primarily intended for tracking my own learning rather than provided to the Alfresco Community for educational purposes. However if you find it useful, informative or have any comments on it then please comment below.
Most of the web development work that I've done for Alfresco has been on a Java web-server stack (i.e. Tomcat, Spring, Surf, Aikau) and doesn't give me a lot of practical opportunities to keep up with modern web development. Therefore I've decided to work through the creation of a web client based on Node.js to experiment, learn and hopefully feed that knowledge back into Alfresco.
Rather than picking up any of the readily available CLIs or tooling I wanted to go right back to basics to understand how everything works. The first thing I needed to do was get a server up and running that I could use to access data from an Alfresco Repository.
I've created a new personal GitHub repository for this project and will tag it at each stage of the development process. To see the code created at the point at which this post was written you should clone the repository and checkout the Blog1 tag.
Before starting I did some research into what authentication modules were available for Node.js and found that the most popular one seemed to be Passport.js. I found a number of useful blog posts during my search such as these:
- Beer Locker: Building a RESTful API with Node - Passport - Scott Smith
- Authentication Using PassportJS - Danial Khosravi's Blog
...but the one I found most useful was this one: Create an App in VueJS 2
Although predominantly about VueJS it contains some really useful information on using Passport.js.
The main problem I had with all of these blog posts is that they were either describing how to setup local authentication (i.e. authenticating against a local database) or using 3rd party authentication (such as Facebook or Google) via redirection.
The solution I was looking for was to take the user credentials provided on login and verify them against an Alfresco Repository. There is a login WebScript supporting HTTP POST provided on the Alfresco Repository at /service/api/login that will return a "ticket" attribute that can be appended as a request parameter to all subsequent REST API calls for authentication.
The solution I implemented was to use the "LocalStrategy" and use the "http" module for Node to make an XHR request to the Alfresco Repository when authentication is required. The asynchronous nature of the request was not a problem because the LocalStrategy instance provides a "done" callback that is used to provide the authenticated user information.
The next important thing to handle was the serialization and de-serialization of this user data. It was important to store the ticket value on the user object so that we would have access to it later so I took the approach of simply creating a map of username to ticket (although to be perfectly honest due to the single threaded nature of Node.js I'm not actually sure that a map is required - perhaps someone can verify this!).
The last thing to implement was a simple proxy for REST API requests. This was achieved by configuring the Express Router. My configuring a URL endpoint of "/proxy/alfresco" (to match what Alfresco Share currently provides) I was then able to create a simple proxy handler that would append the remainder of the requested URL in a call to "/alfresco/service" on the Alfresco Repository (being sure to also append the session ticket!).
It is necessary to define routers for every HTTP method that you want to support (so far I've just added GET, POST, PUT and DELETE) and ensure that request parameters and/or body is passed on to the repository.
Essentially this is a hugely simplified implementation of one of the many capabilities that Surf offers. It should also be possible to support multiple endpoints (i.e. for an Activiti server perhaps?) assuming that the user credentials are the same.
I also need to look further into any potential security issues around this implementation (this blog post provides a useful reference) so I wouldn't be rushing to push an approach like this into production. However, for my purposes this is a sufficient first step in building an Node.js based client for Alfresco.
Now that I'm able to access data from the Alfresco repository the next step will be to start building out an application using that data.