RestaurantCrescのアプリケーションでの実習
|
|
Restaurantのアプリケーションでの実習
それでは前の章でやったRestaurantのアプリケーションで、フォーム・ベースの認証を実習しよう。RestaurantCresc/Masterのページをマスターだけがアクセスできるように設定しよう。設定項目は次のようである。
保護領域の名前 |
Master Only Accessible Pages |
保護するURLパタン |
/Master |
メソッド |
GETおよびPOST |
ロール名 |
RestaurantOwners |
ユーザ名 |
masajuurou |
パスワード |
iyashikei |
そうするとweb.xmlファイルは次のようになる。赤い色で表示された部分が今回追加された部分である。
Tomcat_home\webapps\RestaurantCresc\WEB-INF\web.xml |
<?xml version="1.0"
encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD
Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd"> <web-app> (省略) <taglib> <taglib-uri>
http://java.apache.org/tomcat/examples-taglib </taglib-uri>
<taglib-location>
/WEB-INF/jsp/example-taglib.tld
</taglib-location> </taglib> <security-constraint> <web-resource-collection>
<web-resource-name>Master Only Accessible
Pages</web-resource-name> <!-- Define the context-relative
URL(s) to be protected -->
<url-pattern>/Master</url-pattern> <!-- If you list http methods, only
those methods are protected -->
<http-method>GET</http-method>
<http-method>POST</http-method> </web-resource-collection> <auth-constraint> <!-- Anyone
with one of the listed roles may access this area -->
<role-name>RestaurantOwners</role-name> </auth-constraint> </security-constraint> <!-- Default login configuration uses BASIC
authentication --> <!-- <login-config>
<auth-method>BASIC</auth-method> <realm-name>Example Basic
Authentication Area</realm-name> </login-config> --> <!-- Form-based login is enabled by
default. If you wish to try Basic
authentication, comment out the <login-config> section below
and uncomment the one above. --> <login-config>
<auth-method>FORM</auth-method> <realm-name>Master Only
Accessible Pages</realm-name> <form-login-config> <form-login-page>/HTMLs/security/login.htm</form-login-page>
<form-error-page>/HTMLs/security/error.htm</form-error-page> </form-login-config> </login-config> </web-app> |
アクセス可能ユーザの登録はtomcat-users.xmlファイルで行う。赤で示した行が今回追加されたユーザである。ロール名はweb.xmlで追加されたロールである。
Tomcat_home\conf\tomcat-users.xml |
<tomcat-users> <user name="tomcat"
password="tomcat" roles="tomcat" /> <user name="role1" password="tomcat"
roles="role1" /> <user name="both" password="tomcat"
roles="tomcat,role1" /> <user name="masajyuurou"
password="iyashikei" roles="RestaurantOwners" /> </tomcat-users> |
ログインのページは次のようになる。
Tomcat_home\webapps\RestaurantCresc\HTMLs\security\login.htm |
<HTML> <HEAD><TITLE>RestaulantCresc
Security Gate</TITLE> <META HTTP-EQUIV="cache-control"
CONTENT="no-cache"> <META HTTP-EQUIV="content-type"
CONTENT="SHIFT_JIS"></HEAD> <BODY><H1>レストラン クレス マスター認証</H1> ユーザ名とパスワードを入力してログインボタンを押してください。 <form method="POST"
action="j_security_check">
ユーザ登録名: <input type="text"
name="j_username"><br /> パスワード: <input type="password"
name="j_password"><br />
<input type="reset" value="リセット"> <input
type="submit" value="ログイン"> </form> </BODY></HTML> |
エラー・ページは次のようになる。ここでも再度ログインするためのボタンを用意していることに注意しよう。
Tomcat_home\webapps\RestaurantCresc\HTMLs\security\error.htm |
<HTML> <HEAD><TITLE>RestaulantCresc
Security Gate</TITLE> <META HTTP-EQUIV="cache-control"
CONTENT="no-cache"> <META HTTP-EQUIV="content-type"
CONTENT="SHIFT_JIS"></HEAD> <BODY><H1>レストラン クレス 認証されません</H1> ログインをやり直して下してください。 <form method="GET"
action="../../Master"> <input type="submit" value="再度ログイン"> </form> </BODY></HTML> |
これで設定は終了であるが、サーブレットのセッション管理部分の変更が残っている。RestaurantMasterのセッション状態は次のような遷移をする。従ってセッション状態の識別のためにmasterSessionStageというパラメタがセッションの属性として用意されている。
isNew()メソッドの代りにこのパラメタを使って、セキュリティのあるアプリケーションでもセキュリティ制約の無いアプリケーションでも機能するよう、RestaurantMasterクラスのdoEditメソッドに次のような変更を加える。同様な変更をシェフやウェイトレスのサーブレットに行っておくと、将来セキュリティ制約に変更が出た場合にもそのまま使えることになる。
RestaurantMaster.doEditMenuメソッドの変更部分 |
/** * メニューに価格の設定 */ public void
doEditMenu(HttpServletRequest request, HttpServletResponse response) { try{ //応答ページ作成の準備 response.setContentType("text/html;
charset=Shift_JIS"); response.setHeader("Cache-Control",
"no-cache"); //ブラウザやProxyにキャッシングさせない PrintWriter out = response.getWriter();
out.println("<HTML><HEAD><TITLE>Restaurant
Master</TITLE>"); out.println("<META
HTTP-EQUIV=\"pragma\" CONTENT=\"no-cache\">"); //本ページはキャッシングをさせない
out.println("</HEAD><BODY><H1>本日のメニューの価格設定</H1><PRE>"); //到来要求が最初のものかどうか調べる HttpSession session = request.getSession(); session.setMaxInactiveInterval(3600);
//このセッションのタイムアウトを秒で設定 //メニューのオブジェクトをコンテキストから取得 ServletContext context = getServletContext(); RestaurantMenu menu =
(RestaurantMenu)context.getAttribute("menu"); String masterSessionStage
= (String)session.getAttribute("masterSessionStage"); RestaurantMenuBusyFlag menuBusyFlag =
(RestaurantMenuBusyFlag)context.getAttribute("menuBusyFlag"); String url = "http://" +
request.getRemoteAddr() + ":"
+ request.getServerPort() + request.getRequestURI(); if ((session.isNew() ==
true) || (masterSessionStage == null) || (masterSessionStage ==
"second")) {
session.setAttribute("masterSessionStage", "first"); //セッションのステージは最初 //このメニューを強引に解除する while (menuBusyFlag.isBusyFlagOn()
== true){
menuBusyFlag.freeBusyFlag(); try{
Thread.sleep(250); }catch
(InterruptedException e){} } menuBusyFlag.getBusyFlag(); //それからメニューをビジーに(とは云っても解除したスレッドがすぐこれを解除する可能性あり) //初期画面をクライアントにかえす out.println("単価を記入");
out.println("</PRE>"); String url1 =
response.encodeURL(url); //このメソッドはWTEでは機能しないので現在使っていない if (request.isRequestedSessionIdFromCookie()==false){ url1 = url +
";jsessionid=" + session.getId(); } out.println("<FORM
ACTION=\""+url1+"\" METHOD=\"POST\">");
out.println("<TABLE><TR><TH>アイテム</TH><TH>仕込(残り)数</TH><TH>単価</TH></TR>"); String[] repertory =
menu.repertory; if (repertory != null){
//Chefが未入力! for (int i=0;
i<repertory.length; i++){
Enumeration selections = menu.keys(); while
(selections.hasMoreElements()){
String selection = (String)selections.nextElement();
RestaurantMenuItem menuItem =
(RestaurantMenuItem)menu.getItem(selection);
if (repertory[i] == menuItem.selection){
out.println("<INPUT TYPE=\"hidden\"
NAME=\"Selections\" VALUE=\""+menuItem.selection+"\">");
out.println("<TR><TD>"+menuItem.selection+"</TD><TH>"
+ menuItem.stock + "</TH>");
out.println("<TD><INPUT TYPE=\"text\"
MAXLENGTH=\"5\" NAME=\"Price\" VALUE=\""+menuItem.price+"\"</TD></TR>"); } } } }else {
out.println("<TR><TD>シェフがメニューを未設定です</TD></TR>"); }
out.println("</TABLE></BODY></HTML>");
out.println("</TABLE>"); out.println("<INPUT
TYPE=\"reset\" VALUE=\"リセット\">"); out.println("<INPUT
TYPE=\"submit\" VALUE=\"送信\">");
out.println("</FORM></BODY></HTML>"); } else { //解答画面からの応答、メッセージの情報を保存 //
session.invalidate(); //セッションは1回のみとする場合(その都度認証)
session.setAttribute("masterSessionStage",
"second"); //セッションのステージが2回目であることを属性として記憶 String[] priceString =
request.getParameterValues("Price"); String[] selections =
request.getParameterValues("Selections"); RestaurantMenuItem menuItem; if (selections != null) { for (int i=0; i<priceString.length;
i++){ menuItem =
menu.getItem(selections[i]);
//各menuItemオブジェクトを取得 int itemPrice; try{ itemPrice =
Integer.valueOf(priceString[i]).intValue();
}catch(NumberFormatException numberFormatError){itemPrice = 0;} menuItem.price = itemPrice;
menu.addMenuItem(menuItem); //menuItemオブジェクトをmenuオブジェクトに追加 }
context.setAttribute("menu", menu);
//Contextにmenuオブジェクトをセット } // HTMLボディの出力 out.println("<BODY>本日の設定価格です. 変更は再度入力してください<BR>");
out.println("<TABLE><TR><TH>アイテム</TH><TH>仕込数</TH><TH>単価</TH></TR>"); menu =
(RestaurantMenu)context.getAttribute("menu"); String[] repertory =
menu.repertory; if (repertory != null){
//Chefが未入力! for (int i=0; i<repertory.length; i++){
Enumeration newSelections = menu.keys(); while
(newSelections.hasMoreElements()){
String selection = (String)newSelections.nextElement();
menuItem = (RestaurantMenuItem)menu.getItem(selection);
if (repertory[i] == menuItem.selection){
out.println("<TR><TD>"+menuItem.selection+"</TD><TD
ALIGN=\"right\">" + menuItem.stock +
"</TD><TD ALIGN=\"right\">" + menuItem.price
+ "</TD></TR>");
} } } } else {
out.println("<TR><TD>シェフがメニューを未設定です</TD></TR>"); }
out.println("</TABLE><FORM
ACTION=\""+url+"\" METHOD=\"GET\">"); out.println("<INPUT
TYPE=\"submit\" VALUE=\"設定価格変更\"></FORM></BODY></HTML>"); //このメニューを開放する menuBusyFlag.freeBusyFlag(); } //バッファの明示的吐き出し out.flush(); out.close(); } catch(Throwable theException) { } } |
さて以上の変更が終わったら実際にTomcat(3.x版)を走らせて見よう。Tomcatをスタートさせる前に変更前のRestaurantCrescアプリケーションの入っている.warアーカイブ・ファイルを名前を変えて別のディレクトリに移しておく。
下図がhttp://localhost:8080/RestaurantCresc/MasterというURLをアクセスしたときのログイン画面である。ユーザ名に”masajyuurou”、パスワードに”iyashikei”を入力し、ログイン・ボタンをクリックするとメニューの値段設定の画面がでてくることを確認しよう。
ログイン入力に誤りがあると、下図のようなエラー画面が表示されることも確認しよう。
なお、ブラウザの設定で、クッキーの受付を拒否させるとどうなるかも確認されたい。
これでフォーム・ベースの認証は理解できたと思う。最後に.warファイルを作成してwebappsディレクトリに置く。
添付のRestaurantCresc1.warファイルの使い方は次のとおりである。
1. Tomcatを終了させる。
2. 今までのTomcatHome\webappsディレクトリにあるRestaurantCresc.warファイルは、名前を変更して別のディレクトリに退避させる。
3. 今までのTomactHome\webapps\RestaurantCrescディレクトリとそのなかのファイルを全て削除する。
4. 添付のRestaurantCresc1.warファイルをTomcatHome\webappsディレクトリにダウンロードしたら、そのファイル名をRestaurantCresc.warに変更する。
5. Tomcatをスタートさせる。そうするとTomcatは新規のRestaurantCrescアプリケーションが入った新規のRestaurantCrescディレクトリを作成する。