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);       //Contextmenuオブジェクトをセット

      }

        // 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)

  {

  }

}

 

さて以上の変更が終わったら実際にTomcat3.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ディレクトリを作成する。

 

 

前節     目次     次節