17 мая 2011

Compojure, Sessions

Дамы и господа, продолжим наши размышления о Clojure. Значит, если Вы здесь, то, что такое Сlojure Вам объяснять не надо.

Я хочу присоединиться к работе моего друга над небольшим Clojure сайтом. Скачав исходник по ссылке, мы получаем заготовку блога:

  • спроектированного по model-view-controller шаблону.
  • с системой html шаблонов от самого google - closure templates.
  • с системой хранилища данных mysql.

Зависимости у проекта небольшие и разрешаются одной командой: lein deps.

Я уже был готов дать команду:

lein please deploy this site to my home host 

но возник вопрос о механизме доступа к контенту сайта. Так как мир представлен инем и янем, то соответственно при рождении сайта рождаются те, кто хочет его погубить. Надо от них защищаться механизмами авторизации/аутентификации. А их пока нет. 

Приступим:

Создадим модель, которая будет отвечать на запросы контроллеру, касаемо аутентификации, авторизации. Модель нам понадобиться для того, чтобы например поддерживать несколько хранилищ пользовательских данных (своя база, openid, etc).

Создадим наш контроллер, который будет аутентифицировать (это когда логин и пароль вводиться), а также авторизировать (это когда с помощью нашего контроллера будет производится проверка доступности другого контроллера). 

Создадим таблицу содержащую список пользователей.

CREATE TABLE user (   id int(11) NOT NULL AUTO_INCREMENT,   email varchar(512) NOT NULL,   password varchar(512) NOT NULL,   fullname varchar(512),   PRIMARY KEY (id));

Создадим таблицу для хранения прав доступа к контроллерам.

CREATE TABLE user_right (
   user_id int(11) NOT NULL,
   controller varchar(128) NOT NULL,
   method varchar(128) NOT NULL,
 PRIMARY KEY (user_id, controller, method))


Добавим пользователя:


insert into user(email, password, fullname) values ('user@site.com', '1234', 'New User');

Теперь давайте добавим данному пользователю право на метод new контроллера post.


insert into user_right(user_id, controller, method, allow) values ((select id from user where email = 'user@site.com'), 'post', 'new', true);


Теперь давайте создадим модель, которая будет аутентифицировать и авторизировать.

Метод authentication возвращает 0 в случае неуспешной аутентификации и 1 в случае успешной. 

Метод authorisation возвращает 0 в случае отстутсвия доступа к методу контроллера и 1 в противном случае.

Теперь можно было бы перейти к контроллеру, если бы не одно НО. Наша программа не имеет состояния, чистая функциональщина. Для реального же мира состояние нужно. Хранить состояния мы будет в сессии. Доступ к сессии, мы сделаем с помощью ring.middleware.session. ring.middleware модули - это функции-прокси между request/responce и нашим web приложением.

В файле src/*/routes.clj включим дополнительный модуль и добавим прокси функцию.


Механизм работы с сессией таков. Теперь в request появиться ключ :session, который хранит в себе мапу. Если мы в нашем responce добавим в ключ :session добавим мапу, то она нам вернется при следующем request-е. Однако если мы в ключ :session запишем nil, сессия уничтожится.

Не все наши контроллеру обязательно возвращают :session. Поэтому мы сделаем еще одну функцию-прокси, которая будет сохранять мапу сессии, если контроллер не записал в нее nil. Код гораздо проще слов. Навешиваем middleware.



Определяем "сохранялку" сессии:


Для просмотра текущей сессии добавьте следующий путь для приложения:

(GET "/session" {session :session} (str session)) 

Теперь давайте определим контроллер, который будет производить аутентификацию (логин) и авторизацию (есть ли права).


Создадим для него шаблоны:

templates/app/login.soy


 templates/login/index.soy


Теперь давайте определим роуты, по которым будет происходить логин/выход:


Теперь давайте защитим какой-нибудь роут. Например, вот так:

(GET "/posts/new" {session :session} [] (if (= 1 (user-session/authorisation session "post" "new")) (post/new)   (redirect-to "/login")))


Ну теперь выполните:

#lein deps
 lein ring server 

Попробуйте создать пост. Вас перенаправит на страничку login. Залогиньтесь под следующим пользователем user@site.com с паролем 1234. Теперь попробуйте создать пост. Для просмотра сессии, наберите http://127.0.0.1/session .

 Постараюсь подвести итоги:
  • Мы добавили механизм сессии в сайт
  • Мы добавили модель для аутентификации и проверки доступа.
  • Мы создали контроллер, который предоставляет страницу для логина. Кроме того данный контроллер проверяет доступность объекта сайта для пользователя.

Комментариев нет:

Отправить комментарий