Hi,
Currently I'm using a simple method to handle logins in Hunchentoot - set the user object when the user logs in, and check for it at the beginning of a function whichever needs to have the credentials, or redirect to login page.
However, most of my functions would require the login-check method to be run before they display the page. I'm guessing there should be a way to define a handler which takes all the requests, runs login function and then sends the request to the appropriate handler. Perhaps I should read the documentation more thoroughly, though I'd appreciate any tips which would make it easier.
Thanks, Vamsee.
On 11/22/06, Vamsee Kanakala vamlists@gmail.com wrote:
Hi,
Currently I'm using a simple method to handle logins in Hunchentoot - set the user object when the user logs in, and check for it at the beginning of a function whichever needs to have the credentials, or redirect to login page.
However, most of my functions would require the login-check method to be run before they display the page. I'm guessing there should be a way to define a handler which takes all the requests, runs login function and then sends the request to the appropriate handler. Perhaps I should read the documentation more thoroughly, though I'd appreciate any tips which would make it easier.
If possible, arrange your dispatchers so that public (anonymous-access) dispatchers are at the start of the dispatch table, and restricted dispatchers appear near the end. Then, you can introduce a "dummy dispatcher" between the two groups, that performs the login-check and the redirection to your login page if needed.
For example:
(defun ensure-login (request) "A dummy dispatcher that prevents non-logged-in users from passing." ;; assuming you're using sessions... (and (not-logged-in-p (start-session)) #'(lambda () (redirect "/login"))))
(defun not-logged-in-p (session) ...)
(setq *dispatch-table* (list (create-prefix-dispatcher "/public" 'public-handler) (create-prefix-dispatcher "/login" 'login-handler) #'ensure-login (create-prefix-dispatcher "/admin" 'admin-handler) ;; etc. #'default-dispatcher))
The trick is to have ENSURE-LOGIN return NIL if the user is logged in. You may still want fine-grained access control in some of your handlers, but this approach handles the general case nicely.
Graham
Vamsee Kanakala wrote:
set the user object when the user logs in, and check for it at the beginning of a function
However, most of my functions would require the login-check method to be run before they display the page.
Here's how I do it:
(declaim (special %current-user%))
(defmacro with-current-user (&body body) `(let ((%current-user% (session-value current-user))) (unless %current-user% (redirect "/login")) ,@body))
(defun my-protected-page-handler () (with-current-user (with-html-output-to-string (*standard-output* nil :prologue t) (:html ...
I use this pattern a lot: a session value, a related special variable, and a macro that binds one to the other, taking action if the session value is not set.
By the way, special variables bound by (let) forms are thread-specific, at least on SBCL, so all is well.
You might also find this useful:
(defmacro with-session-values (declarations &body body) "with-session-values ({session-value | (var session-value)}*) declaration* form*" `(let ,(loop for decl in declarations if (listp decl) collect `(,(first decl) (session-value (quote ,(second decl)))) else collect `(,decl (session-value (quote ,decl)))) ,@body))
Toby