Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: разработка для Web > Скрипт авторизации


Автор: shutffl 5.8.2009, 15:40
Доброго времени суток !

Давно стояла проблема написания сайтов с авторизацией. Несколько раз пытался разобраться с CGI::Session, но безрезультатно. Читал и на CPAN, и тут, и просто поиском. Но так и не допер. В связи с этим, решил написать свою систему авторизации для сайта. Все бы ничего, но никак не могу придумать, какиим образом сделать обработку ссылок. Суть в том, что после проверки валидности логина/пароля пользователю присваивается некий personalCode, заносящийся в БД. А при переходе по ссылке с сайта этот код, естественно, не передается. Есть ли способ это исправить или стоит все таки убиться веником, но изучить CGI::Session?

Всем заранее спасибо за ответы.

Автор: ginnie 5.8.2009, 15:49
shutffl, убиваться веником не стоит  smile  А вот изучить CGI::Session будет полезно. На странице http://search.cpan.org/~markstos/CGI-Session-4.41/lib/CGI/Session/Tutorial.pm все, что надо описано. Задавайте вопросы!

Автор: sir_nuf_nuf 5.8.2009, 15:51
shutffl, стоит понять что такое авторизация.
Авторизация (на самом деле аутентификация) - это проверка что пользователь тот, за кого себя выдает.
Результатом авторизации является выдача уникального и длинного идентификатора - id сессии. Заметим, что это идентификатор может (и должен) не быть постоянным, он выдается на время.
Наличие этого идентификатора - как билет в поезд. Дает право.
По сути если ты "угадаешь" либо идентификатор - ты взломаешь аккаунт пользователя.

Этот идентификатор хранится у клиента:
- либо как hidden поле на всех формах
- либо как cookie (Да, вам нужно прочитать про них)

На стороне сервера с этим идентификатором могут быть связана структура данных - сессия. В сессии могут хранится что угодно - id пользователя (не путать с id сессии!!), какие - то временные настройки, все что захотите.

CGI::Session - это просто удобное средство хранения сессий и генерации их ID.  

Как передавать юзеру id сессии - дело ваше. Я предлагаю cookie.


И еще очень рекоменду - осмыслить процесс и разобраться с CGI::Ssession. Очень похоже что ваша система ни от чего не защищает =(

Автор: DaemonSuw 5.8.2009, 15:57
Не особо работал с сессиями - а что мешает записывать его в куки и установить ему deadline, но мой совет послушайте sir_nuf_nuf =)

Автор: gcc 5.8.2009, 16:17
1) там еще есть модуль авторизации, вместе сессиями
2) можете написать свои сессии и авторизацию
3) в MVC Catalyst собрано все сразу...

Автор: shutffl 5.8.2009, 16:57
Спасибо  всем за ответы!

Придется еще раз перечитать.. На счет "ничего не защищает".. На самом деле personalCode выдается на 30 минут; в БД лежит время авторизации пользователя, которое проверяется при переходе. Это-то как раз все предусмотрено. Вот только переход по ссылкам не знаю как сделать. А поле HIDDEN тут не совсем поможет, так как оно учитывается только при Submit формы, а при ссылочной системе переходов это нереально, если я не ошибаюсь. Ну разве что JS тут поможет с onClick, но там я тоже не нашел как параметры передавать методу formName.Submit().

Автор: shutffl 5.8.2009, 17:26
Господа (и дамы, еси таковые тут имеются).. Перечитал, но все равно ничего не понял. Признаю это. Можно примерчик какой или пошаговую интсрукцию. Ну или тупо пример на две-три html-страницы.

Автор: sir_nuf_nuf 5.8.2009, 18:17
shutffl, а чем вас переход по ссылкам смущает ? 
где вы храните этот самый personalCode ? в куках или в hiden полях ?

Автор: gcc 5.8.2009, 18:26
можете посмотреть тут http://phoinix.ucoz.ru/publ/2-1-0-20

но лучше использовать модули готовые...  
есть http://search.cpan.org/~markstos/CGI-Session-4.41/lib/CGI/Session.pm 

authentication и authorizationдальше легко сделать

вот тут вот для каталиста написано как настроить его модули http://search.cpan.org/~hkclark/Catalyst-Manual-5.8000/lib/Catalyst/Manual/Tutorial/05_Authentication.pod 

Автор: shutffl 5.8.2009, 20:31
Цитата(sir_nuf_nuf @  5.8.2009,  18:17 Найти цитируемый пост)
shutffl, а чем вас переход по ссылкам смущает ? 
где вы храните этот самый personalCode ? в куках или в hiden полях ? 

persenalCode хранится в БД. Смущает тем, что я не знаю, как его передавать.. Разве что к каждой ссылке добавлять, чтобы было что-то типа index.pl?act=addVideo&personalCode=<MD5Hash> . Еще я использую шаблоны и делаю вот так:
Код

<form method="get" action="index.pl">
          <TMPL_IF NAME="fShowAuthForm">
          <div class="authForm">
                          L: <input type="text" name="login" maxlength="20" size="10" />
                          P: <input type="password" maxlength="40" name="password" size="10" />
                          <br />
                          <input type="submit" value="Log In" />
          </div>
          <TMPL_ELSE>
          <p>
          Welcome, <i><TMPL_VAR NAME="login"></i> ! | <a href="index.pl?logout">Log Out</a>
          </p>
          </TMPL_IF>
          <input type="hidden" name="personalCode" value="<TMPL_VAR NAME="personalCode">">
          </form>


GET тут просто для тестирования стоит.

--

Собственно только что попробовал.. Выкрутился добавлением к ссылкам &personalCode=<..> . Теперь дело за малым.. Жаль только, что все ссылки теперь придется к такому виду приводить. Но с другой стороны, тот же CGI::Session вводит CGISESSION, добавляя ее, по умолчанию, в адресную строку (в запрос). Так что не критично в итоге.

Автор: Paul56 5.8.2009, 21:44
а где сам код ?
Вы попробуйте что то выполнить самостоятельно и выложить код сюда.

Автор: sir_nuf_nuf 5.8.2009, 22:42
shutffl, ёклмн. почитайте про http://ru.wikipedia.org/wiki/HTTP-Cookie  и про то как с ними работать в perl http://search.cpan.org/~lds/CGI.pm-3.44/CGI/Cookie.pm


Второй вариант - хранить в hidden полях.
Код

<form action="/bla" method="POST">
  <input type="hidden" name="session_id" value="s1243124njwef2o3r23"/>
  <input type="text" name="bla"/>
</form>



Но вариант с КУКАМИ - НАМНОГО лучше. Они для того и сделаны.

Автор: gcc 5.8.2009, 22:59
вот тут во тя писал http://x0.org.ua/perl/2/session.pm по этой статье http://phoinix.ucoz.ru/publ/2-1-0-20, но лучше модуль использовать CGI::Session

Автор: Alca 6.8.2009, 15:54
Цитата

shutffl, а чем вас переход по ссылкам смущает

Цитата

хранить в hidden полях

А если юзер в адресной строке браузера забивает адрес? Эти приколы разве можно как-то прикрутить?
А если скрипты отключены в настройках браузера?

Добавлено через 2 минуты и 49 секунд
http://forum.vingrad.ru/forum/topic-234498/unread-1.html
http://forum.vingrad.ru/forum/topic-224253/unread-1.html
http://forum.vingrad.ru/forum/topic-231250/unread-1.html
http://forum.vingrad.ru/forum/topic-23902/unread-1.html

Автор: gcc 6.8.2009, 16:17
там есть такая штука как REST для Catalyst видел через Ajax передается сессия, для высоконагруженных сайтов

http://search.cpan.org/search?query=catalyst+rest&mode=all

Автор: Alca 6.8.2009, 16:21
Цитата

через Ajax

Ajax - это же ActiveX?

Автор: gcc 6.8.2009, 16:26
JavaScript

http://ru.wikipedia.org/wiki/AJAX

Автор: Alca 6.8.2009, 16:34
http://ru.wikipedia.org/wiki/XMLHttpRequest

Добавлено @ 16:36
Опера не держит ActiveX, а Лиса - вроде тоже.

Автор: gcc 6.8.2009, 16:37
принято использовать JavaScript

Автор: Alca 6.8.2009, 16:39
Цитата

принято использовать JavaScript

JavaScript можно отключить

Автор: shutffl 7.8.2009, 15:31
Господа, я не пропал и внимательно читаю тред. Не всегда есть время прочитать указанную вами документацию - работы сейчас много, переезд очередной на новое место. Даже осмыслить не всегда получается.

Добавлено через 9 минут и 46 секунд
Цитата(Alca @  6.8.2009,  15:54 Найти цитируемый пост)
А если юзер в адресной строке браузера забивает адрес? Эти приколы разве можно как-то прикрутить?
А если скрипты отключены в настройках браузера?

Эм.. Простите конечно, но.. Ну забил пользователь в адресною строку.. И что дальше-то.. Его автоматом на авторизацию кинет или на обрезанный вариант страницы а-ля guest. И все. Если же он даже после авторизации зайдет, то да, он должен стать гостем, так как personalCode отсутствует. Но таких изврщенцев не так много. В основном все по ссылочкам-кнопочкам тыкают.
Пардон.. А как perl-скрипты можно отключить на стороне клиента?? Браузер выдает итоговую страницу, сгенерированную сервером. Server-Side, однако.

Добавлено через 10 минут и 20 секунд
Цитата(Alca @  6.8.2009,  16:39 Найти цитируемый пост)
JavaScript можно отключить 

ActiveX - тоже !!

Автор: shutffl 7.8.2009, 23:09
Так.. Вроде что-то получилось.

Цель для теста была поставлена следующая:
-- index.pl - стартовая страница сайта с авторизацией
-- afterAuth.pl - тестовая страница для проверки работы сессий.

index.pl
Код

#!/usr/bin/perl

use strict;
use warnings;
use CGI;
use CGI::Carp qw/fatalsToBrowser/;
use CGI::Session qw/-ip_match/;

my $cgi = new CGI;

##############

if ( ($cgi->param("login") ne "") and ($cgi->param("password") ne "") ) {
    if ( ($cgi->param("login") eq "qwe") and ($cgi->param("password") eq "123") ) {
        my $session = new CGI::Session() or die CGI::Session->errstr;
        #my $cookie = $cgi->cookie(-name=>$session->name, -value=>$session->id);

        # Save in session
        #print $session->header(-cookie=>$cookie);
        print $session->header();
        my $pC = "1234567890..32";
        $session->param("pC", $pC);
        $session->expire("+5s");

        # Get from session
        print "Hello, " .$session->param("pC"). "(here name from SQL DB) !!";
        print "<br /><a href=\"afterAuth.pl\">Go</a> to test session page."
    }
    else {
        print $cgi->header();
        print
            $cgi->start_html(),
            $cgi->start_form(-method=>"get", -action=>"index.pl"),
            $cgi->h1("Invalid login and/or password"),
            $cgi->input({-type=>"text", -name=>"login"}),
            $cgi->input({-type=>"password", -name=>"password"}),
            $cgi->submit({-value=>"LogIn", -name=>"loginSubmit"}),
            $cgi->end_form(),
            $cgi->end_html();

    }
}
else {
    print $cgi->header(-title=>"Not auth !!", -charset=>"utf8");

    print
        $cgi->start_html(),
        $cgi->start_form(-method=>"get", -action=>"index.pl"),
        $cgi->input({-type=>"text", -name=>"login"}),
        $cgi->input({-type=>"password", -name=>"password"}),
        $cgi->submit({-value=>"LogIn", -name=>"loginSubmit"}),
        $cgi->end_form(),
        $cgi->end_html();
}


afterAuth.pl
Код

#!/usr/bin/perl

use strict;
use warnings;
use CGI;
use CGI::Carp qw/fatalsToBrowser/;
use CGI::Session qw/-ip_match/;

my $cgi = new CGI;

##############

my $session = CGI::Session->load() or die CGI::Session->errstr;

if ($session->is_expired()) {
    #print $cgi->header();
    #print "Session expired.. <a href=\"index.pl\">Relogin</a>.";
    $session->delete();
}
#if ($session->is_empty()) {
#    $session = $session->new();
#}
if ($session->param("pC") ne "")
{
    print $cgi->header();#-refresh=>"1");

    print "pC: " . $session->param("pC");
}
else
{
    print $cgi->header();
    print "Session expired.. <a href=\"index.pl\">Relogin</a>.";
}



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

Автор: shutffl 9.8.2009, 00:56
Так как комментариев нет, то считаю вопрос закрытым.

Автор: shutffl 9.8.2009, 03:36
Начал переносить на готовый проект и снова непонятки.

index.pl
Код

#!/usr/bin/perl

use strict;
use warnings;
use CGI;
use CGI::Session ( "-ip_match" );
use DBI;
use CGI::Carp qw/fatalsToBrowser/;
use HTML::Template;
use Digest::MD5 qw/md5_hex/;

require "modules/dbConfig.pl";
require "modules/dbFunctions.pl";

# Vars
my $cgi = new CGI;

my $session = CGI::Session->load() or die CGI::Session->errstr();

# Templates
my $tmplMainTop = new HTML::Template(filename=>"templates/mainTop.template", associate=>$session);
my $tmplMainLeft = new HTML::Template(filename=>"templates/mainLeft.template", associate=>$session);
my $tmplMainCenter = new HTML::Template(filename=>"templates/mainCenter.template", associate=>$session);
my $tmplMainBottom = new HTML::Template(filename=>"templates/mainBottom.template", associate=>$session);
my $tmplMainCenterNews = new HTML::Template(filename=>"templates/mainCenterNews.template", associate=>$session);
my $tmplMainCenterVideos = new HTML::Template(filename=>"templates/mainCenterVideos.template", associate=>$session);

#print $cgi->header(-title=>"text/html", -charset=>"utf8");

# DataBase
my $dbConn = DBI->connect("DBI:Pg:dbname=$dbConfig::dbName", $dbConfig::dbUser, $dbConfig::dbPassword) or die DBI->errstr();

# Session check
if ($session->is_expired()) {
  $session->delete();
  $tmplMainTop->param(afterAuth=>0);
}

# If wanna log in
if ( ($cgi->param("login") ne "") and ($cgi->param("password") ne "") ) {
  my $md5Password = md5_hex($cgi->param("password"));
  my ($rows, $sth) = &dbFunctions::doSelect($dbConn, "SELECT password FROM as_users WHERE \"login\"='".$cgi->param("login")."'");
  if ($rows == 1) {
    my $password = &dbFunctions::getUserPassword($sth);
    if ( $md5Password eq $password ) {
      print $session->header();
      my $personalCode = md5_hex($cgi->param("login") . localtime(time));
      my ($authorId, $groupId);
      ($rows, $sth) = &dbFunctions::doSelect($dbConn, "SELECT id FROM as_users WHERE \"login\"='".$cgi->param("login")."'");
      if ($rows == 1) {
        $authorId = &dbFunctions::getAuthorId($sth);
      }
      ($rows, $sth) = &dbFunctions::doSelect($dbConn, "SELECT \"idGroup\" FROM as_users WHERE \"login\"='".$cgi->param("login")."'");
      if ($rows == 1) {
        $groupId = &dbFunctions::getGroupId($sth);
      }
      $session = new CGI::Session or die CGI::Session->errstr();
      print $session->header(-type=>"text/html", -charset=>"utf8");
      $session->param("personalCode", $personalCode);
      $session->param("login", $cgi->param("login"));
      $session->param("authorId", $authorId);
      $session->param("groupId", $groupId);
      $session->expire("+30m"); # 30 minutes session
      $tmplMainTop->param(afterAuth=>1);
    }
  }
}

if ($session->id() eq "") {
  print $cgi->header();
}

# Action check
if ($cgi->param("a") eq "logout") {
  $session->delete();
  $cgi->header(-refresh=>"");
}

# Page creation
print $tmplMainTop->output();
print $tmplMainLeft->output();
print $tmplMainCenter->output();
print $tmplMainBottom->output();

# DataBase
$dbConn->disconnect();


В результате получаю страницу со следующим кодом:
Код

Set-Cookie: CGISESSID=90847fc6c7b6c918da575e6b3c863598; path=/
Date: Sun, 09 Aug 2009 00:31:49 GMT
Content-Type: text/html; charset=utf8

<html>
  <head>
    <title>


Где косяк??

Автор: shutffl 9.8.2009, 04:04
Сам же и нашел.. Второй раз написал print $session->header();

 Теперь следующее.. associate=>$session не хочет работать. То есть в шаблоне написано 
Код

<TMPL_VAR NAME="login">

, а не ставляется. Так же пробовал писать 
Код

<TMPL_VAR login>

как в примере из документации CGI::Session.

Автор: shutffl 9.8.2009, 05:04
Разобрался..

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)