I don’t like web apps and apps for my Android phone and iPad having more information on users (like me!) than they need to support their functionality. I wrote a “practice” Clojurescript web app a few months ago that allows me to make notes on all of my devices. Really simple, but it does no more and no less than what I wanted for my own use. (You can play with it here.)
Recently I updated this to allow anonymous use with persistent user ID across all devices. If you hit the default web app URI you will notice a link at the bottom of the page that a user (you!) can copy and email to yourself. Open the email on your other devices, bookmark the URI, and optionally make a desktop icon link (this is what I do on my Galaxy S III, which is where I most often use this app).
This setup process is a little tedious: using my laptop I created a new account as a test using the root application URI, copied the URI listed at the bottom of the page, and it took a couple of minutes to set up my iPad and phone with the same (new) anonymous account.
One alternative is using authentication using Twitter, Google, Facebook, and/or Yahoo as I have implemented on several customer projects. Easy, but for many types of apps, it annoys me to make users identify themselves. Another alternative is having users create an account name and password, and perhaps this is better alternative.
I would appreciate comments on how other developers handle user login for anonymous applications.
If you are interested, here are the bits of code I use to implement this. I check for a cookie in the user’s request using:
(def cookie-name "focustestapp") (defn check-auth [request] (let [id (:value ((:cookies request) cookie-name))] (or id (str (java.util.UUID/randomUUID)))))
I pass the generated or existing cooking to the Clojurescript code for the single page web app and the “login URI” is displayed for the user to reuse. All of the user’s data is set to the client side app using the route for /edn. I also have routes for updating/deleting/archiving notes; the client always passes back the user’s unique auth token.
(def index-page (slurp "resources/public/index.html"))
(compojure/defroutes routes
(compojure/GET "/" request (let [id (check-auth request)]
{:body index-page :cookies {cookie-name id}))
(compojure/GET "/edn" request (let [id (check-auth request)
data (all-foci-for-user id)]
:body (pr-str data)}))
(compojure/GET "/update" request (update-data ((:query-params request) "s")))
....
(route/resources "/"))
By the way, it is just about trivial to pass data back and forth between client side Clojurescript and server side Clojure code. In the route for /edn one time and then just deltas of changed data flow between client and server. Notice the call to (pr-str data) to serialize the data returned to the client. On the client side, require [clojure.edn :as reader] and read the response like:
(defn edn-to-clojure-data [s]
(let [data (reader/read-string s)]
(d/log "raw string for edn data data= " data)
data))
Sending data from the client to the server is also pleasantly easy. In this example (assuming a require for [goog.net.XhrIo :as xhr]) I am using GET:
(xhr/send (str "/update?s=" data) handle-ajax-response "GET" ""))
