ホームページを制作していると、ある特定の人しか見せたくないとか、会員専用のエリアを作成したいという事がでてきます。
その方法として一番簡単なベーシック認証(BASIC認証)という方法で制限を付ける方法を解説します。
また、単なる制限だけじゃなく、その
ココがポイント
メンバー管理をWEB上で簡単にできるツール
なども使って実現します。
ベーシック認証のお勉強
本当に初心者の方には、難しい話は無しで、
制限したいホームページエリア(フォルダー)の中に、2つのファイルを設置するだけ
で制限がかけられます。※レンタルサーバー屋さんによっては、管理パネルから制限機能が実装されている場合もあります。
※レンタルサーバー屋さんによっては、使えない場合などもあるので最初に調べてみてください。
では、何を設置したらいいのか?
.htaccess (この中に制限事項を記入する。)
と
.htpasswd (この中にアカウントと暗号化パスワードを記入する。)
の2つのファイルを設置するだけで、そのホームページエリアは制限がかけられて下記の様な、ユーザー名とパスワードを要求されるようになり、それを認証されないと先に進めなくなります。
では、この2つのファイルのお勉強は、手抜きをさせていただきまして、下記の参考サイトをご覧ください。
ベーシック認証ができるまでの注意点
たった2つのファイルを設置するだけでベーシック認証が設置できるわけなのですが、なぜかうまく行かないって事がよくあります。
会員管理がどうのこうのっていう次の項目に行く前に、2つのファイルだけで、ちゃんと制限がかけられたかどうかの確認をすることが必要です。
下記に自分がハマったいくつかの事例を記載しておきますので、なぜかうまく行かない場合は参考にしてみてください。
つまづきポイント
.htaccessを設置した途端にサーバーエラーで一切表示ができなくなった。
この場合は、
- .htaccess内の記述がダメ
- ファイルの保存文字コードがダメ
- 転送形式がダメ
くらいを注意してみるといいかもしれません。
.htaccess内の記述がダメ
まったくサーバーエラーの場合は、サーバーによっては記述しちゃいけないコードがあったりする場合があるようです。
ちなみに、私も下記の様なコード
AuthUserFile /var/www/vhosts/domain/member/.htpasswd AuthGroupFile /dev/null AuthName test-Only AuthType Basic require valid-user SiteGuard_User_ExcludeSig sqlinj-22 SiteGuard_User_ExcludeSig url-php-rfi SiteGuard_User_ExcludeSig sqlinj-9
を他のサーバーでは、つかってて問題無かったのですが、今回の実験のサーバーでは、サーバーエラーで何も表示されなくなってしまいました。
それなので、下記の様に書き換えたら表示されたなどという事がありました。
AuthUserFile /var/www/vhosts/domain/member/.htpasswd AuthGroupFile /dev/null AuthName test-Only AuthType Basic require valid-user Options +ExecCGI AddType application/x-httpd-cgi .cgi AddType application/x-httpd-cgi .pl AddType application/x-httpd-cgi .cgi .pl
コードの詳細の意味も理解しないといけないのですが・・・
それから、
AuthUserFile /var/www/vhosts/domain/member/.htpasswd
この部分ですが、絶対パスと言われる場所の指定先なのですが、サーバー屋さんによって違うので注意が必要です。
私が使っているレンタルサーバー屋さんは、管理パネルにログインすると絶対パスを確認できる場所がありました。
ファイルの保存文字コードがダメ
私は、テキストエディターにTeraPadをつかっているので、文字コードを確認しながら保存しています。
しかし、メモ帳などで編集している場合は、文字コードが設定できない場合があります。
.htaccessなどの文字コードの決まりは、
参考
.htaccess の文字コードはUTF-8(BOM無し)、改行コードはLFを設定し、ファイルの最終行には空行を入れる必要があります。ただし .htaccess が日本語などの全角文字を含まず、半角英数字だけである場合は文字コードは Shift-JIS や EUC-JP などでも問題ありません。文字コードや、改行コードが誤っている場合は、500 internal server error が発生するため注意が必要です。
(引用:htaccessの書き方)
私の場合は、半角英数だけなので、Shift-JIS で問題ないようです。
転送形式がダメ
設置するファイルも確認して、ちゃんと.htpasswdないのユーザー名と暗号パスワードも設置したのに、なぜかサーバーエラーになってダメな場合があります。
その場合は、転送形式を疑って見る事も一つです。
私は、ファイル転送にFFFTPを使っていますが、確認してみると、転送設定が、バイナリーモードになっている場合があります。
通常は、自動切り替えなのですが、なんかの拍子にバイナリーモードで転送されている場合があます。
ココに注意
アスキーモードにして転送しなおしたら回復
したって事も何度かありました。
メンバー(会員)をWEB上で行う方法
相当前に、拾ってきたCGIコードなので、作者が誰だかわかりません。わかったらリンク貼らせて頂きます。
さて、ベーシック認証で、メンバー(会員)管理を行いたい場合に便利なCGIツールがあります。
CGIコードは、制限したい場所以外にも設置できますが、今回は同じフォルダー内においています。
ファイル説明
.htaccess
.htpasswd
conf.pl (設定ファイル)
delete.cgi (メンバー削除用)
regist.cgi (メンバー追加用)
pwd.html (管理パネル表示HTML)
私は、ログイン履歴も同時に設置しています。
log.cgi (ログイン履歴用)制限ページに(※1)のコードをHTMLのヘッダーに埋め込んでください。
show.cgi (ログイン履歴閲覧用)直接このCGIにアクセスすると閲覧できる。
log.txt (ログイン履歴データ)
CGIコードは実行させるのに、属性を775に変更しないと動作しません。
※サーバー屋さんによって違う場合があります。
※サーバー屋さんによって、最初の「#!/usr/bin/perl」が違う場合があります。
log.txtなどの書き込み専用ファイルは、属性を666に変更しないと書き込めない場合があります。
今回は、CGIコードの詳細説明は省かせていただきます。
サーバーへの設置が終わったらさっそく管理パネルである、pwd.htmlにアクセスしましょう。
その前に、
ココに注意
.htpasswd内の設定がされてないと、管理パネルにも入れません
ので注意してください。
ベーシック認証を済ませると管理パネルに行けると思います。
上の画像の、メンバーと表示と削除「クリック」と押すと、既に、.htpasswdに登録されているユーザーが確認することができます。そこからメンバーを削除することも可能です。
登録は、上のメンバー登録から簡単に追加ができます。
いちいち、.htpasswdに手動でパスワードを設定して、サーバーに転送する手間が、この管理パネルのお陰でWEB上から自由に管理することができるようになりました。
同時にアクセスログを設置
私は、ベーシック認証で誰が入室しているのかを知りたかったので同時にアクセスログを設置しました。
その場合、入室した最初のトップページのHTMLに下記のコードを埋め込まないとログはとれませんので注意してください。
<!--######ベーシック認証ログをとる########// --> <SCRIPT LANGUAGE="JavaScript"> <!-- document.write('<IMG SRC="log.cgi?'); document.write(document.referrer); document.write('" HEIGHT="1" WIDTH="1">'); // --> </SCRIPT>
ログが取れたら、直接 show.cgi にアクセスするとログを閲覧することができます。
このログをみると、だれが何時に入室したのが分かるのでイイですね。
コードの内容
とりあえず、コードをアップしておきますが、みなさんが御利用のサーバーによってちょっとだけ設定が分かる場合がありますので御注意くださいませ。慣れている方なら簡単に設置できると思います。
●conf.pl
# 設定ファイル $use = 1; # 0:htpasswdを使用する その他の値:perlのcrypt関数を使用する (この場合, $htpasswdの設定は無効になります.) $htpasswd = "/var/www/vhosts/domain/member/.htpasswd"; # htpasswdまでのフルパス $file = "/var/www/vhosts/domain/member/.htpasswd"; # htpasswdの生成するパスワードファイル $file_temp = "$file.temp"; # $fileを作成する際のテンポラリファイル
●delete.cgi
#!/usr/bin/perl require 'conf.pl'; print "Content-type: text/html\n\n"; print " <!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\"> <html> <head> <meta http-equiv=\"Content-Type\" content=\"text/html; charset=euc-jp\"> <title>メンバー登録</title> </head> <body text=\"#000000\" link=\"#ff0000\" vlink=\"#ffaaaa\" alink=\"#ffaaaa\" bgcolor=\"#ffffff\"> "; if ($request_method eq "GET") { $buffer = $ENV{'QUERY_STRING'}; } else { $size_of_form_infomation = $ENV{'CONTENT_LENGTH'}; read (STDIN, $buffer, $size_of_form_infomation); } @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $FORM{$name} = $value; } $user = $FORM{'user'}; $action = $FORM{'action'}; if ($action eq 'delete' && $user ne '') { open(IN, $file); open(OUT, ">$file_temp"); flock(OUT, 2); while($temp = <IN>) { @data = split(/:/, $temp); if ($data[0] ne $user) { print OUT $temp; } } flock(OUT, 8); close(OUT); close(IN); unlink($file); rename($file_temp,$file); print "$userを削除しました.<br>"; } else { print "削除したいユーザーを選択してボタン押してください<br><hr>\n"; print "<form action=\"delete.cgi\" method=\"POST\">\n"; print "<input type=\"hidden\" name=\"action\" value=\"delete\">\n"; print "<input type=\"submit\" value=\"選択したユーザーを削除\">\n"; print "<table border=\"2\">\n"; print "<tr align=\"center\"><td>チェック</td><td>登録されてるユーザー</td></tr>\n"; if (-e $file) { open(IN, $file); while($temp = <IN>) { @data = split(/:/, $temp); $user = $data[0]; print "<tr align=\"center\"><td><input type=\"radio\" name=\"user\" value=\"$user\"></td><td>$user</td></tr>\n";} } else { print "<tr><td></td><td>まだ誰も登録されてません.</td></tr>\n"; } print "</table>\n"; print "<input type=\"submit\" value=\"選択したユーザーを削除\">\n"; print "</form>\n"; } print "<a href=\"pwd.html\">もどる</a>"; print "<br>"; print "<br>"; print "<a href=\"https://union.joybb.jp\">ページへGO!</a>"; print "\n</body>\n</html>";
●regist.cgi
#!/usr/bin/perl require 'conf.pl'; print "Content-type: text/html\n\n"; print " <!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\"> <html> <head> <meta http-equiv=\"Content-Type\" content=\"text/html; charset=euc-jp\"> <title>メンバー登録</title> </head> <body text=\"#000000\" link=\"#ff0000\" vlink=\"#ffaaaa\" alink=\"#ffaaaa\" bgcolor=\"#ffffff\"> "; if ($request_method eq "GET") { $buffer = $ENV{'QUERY_STRING'}; } else { $size_of_form_infomation = $ENV{'CONTENT_LENGTH'}; read (STDIN, $buffer, $size_of_form_infomation); } @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $FORM{$name} = $value; } $user = $FORM{'user'}; $password = $FORM{'password'}; if ($user eq '' || $user =~ /\s/) { print "ユーザー名に空白文字が含まれているか未入力です.<br>\n"; print "<a href=\"pwd.html\">もどる</a>"; print "\n</body>\n</html>"; exit(0); } if ($password eq '' || $password =~ /[^A-Za-z0-9]/) { print "パスワードに空白文字が含まれているか未入力です.<br>\n"; print "<a href=\"pwd.html\">もどる</a>"; print "\n</body>\n</html>"; exit(0); } if (-e $file) { open(IN, $file); while ($temp = <IN>) { @data = split(/:/, $temp); if ($data[0] eq $user) { print "登録できません.<br>そのユーザー名はすでに登録されてます.<br>"; print "<a href=\"pwd.html\">もどる</a>"; print "\n</body>\n</html>"; exit(0); } } close(IN); $user =~ s/([;<>\*\|`&\$!#\(\)\[\]\{\}:'"])/\\$1/g; $password =~ s/([;<>\*\|`&\$!#\(\)\[\]\{\}:'"])/\\$1/g; $file =~ s/([;<>\*\|`&\$!#\(\)\[\]\{\}:'"])/\\$1/g; $htpasswd =~ s/([;<>\*\|`&\$!#\(\)\[\]\{\}:'"])/\\$1/g; if ($use == 0) { system("$htpasswd", "-b", "$file", "$user", "$password"); } else { &htpasswd; } } else { if ($usr == 0) { system("$htpasswd", "-cb", "$file", "$user", "$password"); } else { &htpasswd; } } print "$userを登録しました.<br>"; print "<a href=\"pwd.html\">もどる</a>"; print "\n</body>\n</html>"; sub htpasswd { local( $salt_paire, $salt1, $salt2, $salt); $salt_paire = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; srand(time/$$); $salt1 = int( rand(63) ); srand(time|$$); $salt2 = int( rand(63) ); $salt1 = substr( $salt_paire, $salt1, 1); $salt2 = substr( $salt_paire, $salt2, 1); $salt = "$salt1$salt2"; $passwd = crypt($password, $salt); open(OUT, ">>$file"); flock(OUT, 2); print OUT "$user\:$passwd\n"; flock(OUT, 8); close(OUT); }
●pwd.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=euc-jp"> <title>メンバー管理</title> </head> <body text="#000000" link="#ff0000" vlink="#ffaaaa" alink="#ffaaaa" bgcolor="#ffffff"> ●メンバー登録<br> <form action="regist.cgi" method="POST"> ユーザー名<input type="text" name="user" size="20"><br> パスワード<input type="text" name="password" size="20"><br> <input type="submit" value="ユーザー登録"> </form> 登録したいユーザー名とパスワードを入力してボタンを押してください.<br> 注意! ユーザー名, パスワード, どちらも半角の英数だけしか使えません. <hr> ●メンバーの表示と削除<br> <a href="delete.cgi">クリック</a> </body> </html>
●log.cgi
#!/usr/bin/perl # 最大記録数 $max = 8000; # ログファイル名 $logfile = "./log.txt"; # --設定完了-- open (IN,"$logfile"); @LINES = <IN>; close (IN); $data = shift(@LINES); ($count,$date,$ip) = split(/,/,$data); $addr = $ENV{'REMOTE_ADDR'}; $userid = $ENV{'REMOTE_USER'}; $host = $ENV{'REMOTE_HOST'}; if ($host eq '' || $host eq $addr) {$host = gethostbyaddr(pack('C4',split(/\./,$addr)),2) || $addr;} if($host ne "$ip"){ &date; $count++; unshift(@LINES,"$data"); unshift(@LINES,"$count,$now,$userid,$host,$ENV{'QUERY_STRING'},\n"); $number = @LINES; if($number > $max){ pop(@LINES); } open (OUT,">$logfile"); print OUT (@LINES); close (OUT); } exit; # 日付を取得 sub date{ $ENV{'TZ'} = "JST-9"; ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime(time); @wday_array = ('日','月','火','水','木','金','土'); $now = sprintf("%d/%d(%s)%02d:%02d",$mon +1,$mday,$wday_array[$wday],$hour,$min,); }
●show.cgi
#!/usr/bin/perl # ↑先頭のパスはプロバイダによって異なります # データファイル名 $logfile = "./log.txt"; # ページのタイトル $title = 'アクセスログ'; # BODYタグ (HTML書式) $body = '<BODY BGCOLOR="#FFFFFF" TEXT="#555555" LINK="#6666DD" ALINK="#552222" VLINK="#888888">'; # フォントサイズ(○ptまたは、○%と指定) $font_size = '11pt'; # フォントの高さ(100%がデフォルト。大きくすると見やすい) $height = '115%'; # リンクの最大文字数(http://・・・ をどこまで表示するか。あまり長いと表示が崩れる) $max = '35'; # テーブル上部に表示するコメント(タグ使用可)。何も表示しないなら「$comment = '';」にする $comment = '<FONT COLOR="#7777FF">トップページのアクセスログです</FONT><BR>'; # テーブルの幅 $table_width = '95%'; # ---------設定はここまで---------- # 記事の表示 print "Content-type: text/html\n\n"; print <<EOM; <html> <head> <META http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> <STYLE TYPE="text/css"> <!-- body,tr,td,th { font-size: $font_size; line-height: $height; } --> </STYLE> <title>$title</title> </head> $body <CENTER> $comment <BR> EOM # 記事の読み込み # open (IN,"$logfile") || &error('file'); @LINES = <IN>; close (IN); print <<EOM; <TABLE BORDER="1" WIDTH="$table_width"> <TR bgcolor="#DDDDFF" ALIGN="CENTER"><TD><B>Count</B></TD><TD><B>Date</B></TD><TD><B>User</B></TD><TD><B>host</B></TD><TD><B>Link</B></TD></TR> EOM foreach(@LINES){ ($count,$date,$userid,$ip,$link) = split(/,/); if($ip eq''){$ip = '-';} if($date eq''){$date = '-';} if($link eq''){$link = 'Bookmark';} elsif (length($link) > $max) { $link2 = substr($link,0,$max); $link = "<A HREF=\"$link\" target=\"_top\">$link2...</A>"; } else{$link = "<A HREF=\"$link\" target=\"_top\">$link</A>";} print "<TR ALIGN=\"CENTER\"><TD>$count</TD><TD>$date</TD><TD>$userid</TD><TD>$ip</TD><TD>$link</TD></TR>\n"; } print <<EOM; </TABLE> </CENTER> </BODY> </HTML> EOM exit;
log.txt は空のファイルなので中身は何もありません。
以上で終了です。
お疲れさまでした。