[hunchentoot-devel] A simple way to handle logins?

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
participants (3)
-
Graham Fawcett
-
Toby
-
Vamsee Kanakala