2003-11-08 16:29:31 UTC

Вашему вниманию предлагается простенький класс, работающий с файлом .htpasswd — это файл механизма стандартной авторизации веб-сервера Apache, содержащий список пользователей имеющих доступ в какой-либо каталог.

Здесь рассмотрены 2 реализации данной задачи, — с использованием таблицы и с использованием хэша. Автор первой не я, а Павел Титов, опубликовавший данный код на форуме сайта parser.ru, я лишь поправил его для себя и немного упростил. Вторая реализация сделана мной — и тут опять работает правило — всё что вы делаете (или делали), можно сделать проще, т.к. вторая реализация (с хэшем), гораздо элегантнее. Вообщем как всегда, — век живи, век учись.

Краткое описание

При создании объекта класса его конструктору — @init передаётся строка содержащая путь к файлу .htpasswd, конструктор пытается найти файл по указанному пути, если ему это не удаётся, он создаёт новый файл, который потом (при вызове методов класса) и записывается по указанному пути.

Класс имеет следующие методы, которые можно вызывать извне:

  • @setpw — добавление нового пользователя, если пользователь с таким именем уже существует, просто меняется его пароль.
  • @setpwCrypted — то же самое что и выше, но вторым параметром метода передаётся не пароль, а уже его хэш. Мне это нужно для совместного использования с классом авторизации от Михаила Петрушина.
  • @delete — удаление пользователя.

Код класса в реализации с таблицей

##############################
# $Id: htpasswd.p,v 1.19 2004/01/02 12:28:45 egr Exp $
# Класс для работы с .htpasswd
# Идея Pavel Titov (pavel@titov.pp.ru)
# Я маленько усовершенствовал
@CLASS
htpasswd

##############################
# Конструктор
# _tPasswd - таблица пользователь/пароль
# _sFileName - полный путь к файлу .htpasswd (с путём)
@init[sFileName][lHtpass]
$_sFileName[$sFileName]
^try{
	$lHtpass[^file::load[text;$sFileName]]
	$lHtpass[^lHtpass.text.match[\n][g]{^#0A}]
	$_tPasswd[^table::create{login	password^#0A^lHtpass.match[:][g]{	}}]
}{
	^if($exception.type eq file.missing
		|| $exception.type eq parser.runtime
	){
		$exception.handled(1)
		$_tPasswd[^table::create{login	password}]
	}
}

##############################
# Добавление пользователя / изменение пароля
@setpw[sLogin;sPassword][lCrypted]
$lCrypted[^math:crypt[$sPassword;^$apr1^$]]
^setpwCrypted[$sLogin;$lCrypted]

##############################
# Добавление пользователя / изменение пароля
# с передачей не самого пароля а уже его хэша
# Работает просто - если пользователь есть, он сначала удаляется,
# а потом записывается новый, с таким же именем, но другим паролем
# Если пользователя нет, понятно что происходит в этом случае :)
@setpwCrypted[sLogin;sPassword]
^if(^_tPasswd.locate[login;$sLogin]){
	$_tPasswd[^_remove[$_tPasswd;^_tPasswd.line[];1]]
}

^_tPasswd.append{$sLogin	$sPassword}
^_save[]

##############################
# Удаление пользователя
@delete[sLogin]
^if(^_tPasswd.locate[login;$sLogin]){
	$_tPasswd[^_remove[$_tPasswd;^_tPasswd.line[];1]]
}
^_save[]

##############################
# Сохранение .htpasswd
@_save[]
$result[^_tPasswd.menu{${_tPasswd.login}:$_tPasswd.password^#0A}]
^result.save[$_sFileName]
$result[]

##############################
# http://parser.ru/forum/?id=3803
## удаление строк из таблицы
# результат - таблица
# t - имя таблицы
# from - начиная с какой строки удалять (!!! нумерация строк с 1)
# count - сколько строк удалять
# пример: $mytable[^remove[$mytable;1;10]] - удалит первые 10 строк
@_remove[t;from;count]
^if(def $t){
	$result[^t.select((^t.line[]<$from) || (^t.line[]>=$from+$count))]
}

Код класса в реализации с хэшем

Данная версия работает быстрее при использовании файлов .htpasswd с большим количеством записей (пользователей). Правда при количестве пользователей менее десятка, она вряд ли быстрее первой и кушает немного больше пямяти, но на спичках экономить не следует, и этим можно пренебречь.

##############################
# $Id: htpasswd.p,v 1.22 2004/01/12 18:14:15 egr Exp $
# Класс для работы с .htpasswd
# Идея Pavel Titov (pavel@titov.pp.ru)
# Я сильно усовершенствовал реализацию - вместо таблиц используется хэш
@CLASS
htpasswd

##############################
# Конструктор
# Параметр:
# sFileName - полный путь к файлу .htpasswd (вида /path/.htpasswd)
# Поля класса:
# _sFileName - полный путь к файлу .htpasswd (вида /path/.htpasswd)
# _hPasswd - хэш пользователь/пароль
@init[sFileName][lHtpass]
$_sFileName[$sFileName]
^try{
	$lHtpass[^file::load[text;$sFileName]]
	$lHtpass[^lHtpass.text.match[\n][g]{^#0A}]
	$lHtpass[^table::create{login	password^#0A^lHtpass.match[:][g]{	}}]
}{
	^if($exception.type eq file.missing
		|| $exception.type eq parser.runtime
	){
		$exception.handled(1)
		$lHtpass[^table::create{login	password}]
	}
}
$_hPasswd[^lHtpass.hash[login]]

##############################
# Добавление пользователя / изменение пароля
@setpw[sLogin;sPassword][lCrypted]
$lCrypted[^math:crypt[$sPassword;^$apr1^$]]
^setpwCrypted[$sLogin;$lCrypted]

##############################
# Добавление пользователя / изменение пароля
# с передачей не самого пароля а уже его хэша
@setpwCrypted[sLogin;sPassword]
^if(def $sLogin && !^sLogin.match[:]){
	^_hPasswd.add[
		$.[$sLogin][
			$.login[$sLogin]
			$.password[$sPassword]
		]
	]
	^_save[]
}

##############################
# Удаление пользователя
@delete[sLogin]
^if(def $_hPasswd.[$sLogin]){
	^_hPasswd.delete[$sLogin]
	^_save[]
}

##############################
# Сохранение .htpasswd
@_save[]
$result[^_hPasswd.foreach[login;password]{${login}:${password.password}}[^#0A]]
^try{
	^result.save[$_sFileName]
	$result[]
}{
	$exception.handled(1)
	$result[Невозможно записать $_sFileName]
}

Пример вызова

Внимание! — класс не будет работать если вызывать его методы статически. А вообще, использовать его очень просто — сначала создаётся объект класса, а затем вызывается нужный метод:

$oPass[^htpasswd::init[/path/to/.htpasswd]]

# Добавление (изменение пароля) пользователя с передачей
# незашифрованного пароля
^oPass.setpw[$sUserName;$sPasswd]

# Добавление (изменение пароля) пользователя с передачей
# хэша пользовательского пароля, полученного с помощью math:crypt
^oPass.setpwCrypted[$sUserName;$sPasswd]

# Удаление пользователя
^oPass.delete[$sUserName]

Загрузить пример (1-я реализация)

Загрузить пример (2-я реализация)

Примечание: Загружаемые файлы находятся в кодировке UTF-8.

2003-11-08 16:29:31 UTC apache parser snippet web