QA@IT

ブラウザの「戻る」ボタンを押したら名前があるセッションを破棄したい

11846 PV

お世話になります。

以下のコードでは、ログインするとデータベースと照合して
IDとPWが一致すれば名前を表示します。
また、一致しなければエラー表示するようになってます。

しかし、ログインしてからブラウザの「戻る」ボタンを押すと
認証画面に戻りますが、名前がセッションに入っているので、
データベースにないIDとPWを打ち込んでも、ログインしてしまいます。

「戻る」ボタンを押しても、セッションの有無にかかわらず認証手続きをする
方法はないでしょうか?
(ブラウザの「戻る」ボタンを押したら名前があるセッションを破棄する)←このような考え方でもいいでしょうか?

どなたかご教授宜しくお願い致します。

環境
Windows7 64bit
eclipse Kepler
tomcat7
struts2.3

jsp

<%@page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<s:if test="#session.USERNAME.length() != 0">
<s:property value="#session.USERNAME"/>社員<br>
<s:form action="logout">
    <s:submit value="ログアウト"/>
</s:form>
</s:if>
<s:else>
ようこそゲスト社員さん<br>
    <s:form action="login">
        <s:textfield label="ユーザーID" name="userid"/><br>
        <s:password label="パスワード" name="pw"/><br>
        <s:submit value="ログイン"/>
    </s:form>
<s:if test="flg1 == true or flg2 == true">
    <font color="red">IDかパスワードが違います。再入力して下さい。</font>
</s:if>
</s:else>

java

public class LoginAction extends ActionSupport implements SessionAware {

    private static final long serialVersionUID = 1L;    

    @Action("login")
    public String execute() throws SQLException {

        ResultSet rs = null;
        PreparedStatement stmt = null;
        Connection connection = null;
        String idstr = "";
        String pwstr = "";
        int userid_length = 0;
        int pw_length = 0;
        try{
        String sql = "SELECT * FROM certification WHERE userid = ? AND pw = ?";
        Class.forName("com.mysql.jdbc.Driver").newInstance();
        connection = DriverManager.getConnection("jdbc:mysql://localhost/JavaServlet?useUnicode=true&amp;characterEncoding=UTF-8","admin","adminpass");
        stmt = connection.prepareStatement(sql);
        stmt.setString(1,getUserid());
        stmt.setString(2,getPw());
        rs = stmt.executeQuery();
        rs.beforeFirst();
        while (rs.next()) { 
            idstr = rs.getString("userid");
            pwstr = rs.getString("pw");
            userid_length = idstr.length();
            pw_length = pwstr.length();
            String namestr = rs.getString("name");      
            session.put("USERNAME", namestr);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            rs.close();
            stmt.close();
            connection.close();
        }
        if (userid_length == 0){
            flg1 = true;
        }
        if (pw_length == 0){
            flg2 = true;
        }
        return "success";
    }

    private Map<String, Object> session;
    public void setSession(Map<String, Object> session) {
        this.session = session;
    }
    private String userid;
    @RequiredStringValidator(message="入力してください")
    public String getUserid() {
        return this.userid;
    }
    public void setUserid(String userid) {
        this.userid = userid;
    }
    private String pw;
    @RequiredStringValidator(message="入力してください")
    public String getPw() {
        return this.pw;
    }
    public void setPw(String pw) {
        this.pw = pw;
    }
    private boolean flg1;
    public boolean getFlg1() {
        return this.flg1;
    }
    public void setFlg1(boolean flg1) {
        this.flg1 = flg1;
    }
    private boolean flg2;
    public boolean getFlg2() {
        return this.flg2;
    }
    public void setFlg2(boolean flg2) {
        this.flg2 = flg2;
    }
}

回答

自己解決致しました。

今回の「戻る」ボタンを押してもセッションの有無にかかわらず認証手続きをする方法に
対する対処法は、ネットで調べると次の3つがあるそうです。

http://www.atmarkit.co.jp/fjava/javafaq/servlet/servlet08.html

(1)ブラウザにBackボタンを表示しないようにする
(2)ブラウザのキャッシュが無効になるように制御する
(3)Backボタンで画面が戻されても、不整合が起こらないようにアプリケーションを設計する

(1)はクライアントのブラウザの設定(JavaScriptの動作を許可してない)によったり、F5ボタンを押されると意味がない
(2)はクライアントのブラウザの設定によっては動作しない
   具体的には認証画面のjspコードに以下を記述する
   <%
     response.setHeader("Pragma","no-cache");
     response.setHeader("Cache-Control","no-cache");
     response.addHeader("Cache-Control","no-store");
    response.setDateHeader("Expires", 0);
  %>
(3)これを採用しました

結果、以下になりました。

名前の入ったセッションを破棄すると、
後の他のアプリに影響を及ぼすので、
違う名前のセッションに名前を渡してから、
元のセッション(USERNAME)を破棄しました。
後の他のアプリでは違う名前のセッション(USER)を利用しました。

コードは以下です。

<%@page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<s:if test="#session.USERNAME.length() != 0">
<s:property value="#session.USERNAME"/>社員<br>
<s:form action="logout">
    <s:submit value="ログアウト"/>
</s:form>
<% String str = (String)session.getAttribute("USERNAME"); %>
<c:remove var="USERNAME" scope="session"/>
<% session.setAttribute("USER",str); %>
</s:if>
<s:else>
ようこそゲスト社員さん<br>
    <s:form action="login">
        <s:textfield label="ユーザーID" name="userid"/><br>
        <s:password label="パスワード" name="pw"/><br>
        <s:submit value="ログイン"/>
    </s:form>
<s:if test="flg1 == true or flg2 == true">
    <font color="red">IDかパスワードが違います。再入力して下さい。</font>
</s:if>
</s:else>

ご迷惑おかけしました。
ありがとうございました。

編集 履歴 (2)

ログイン処理を実行したら、直前のセッションはクリアすればいいんじゃない?

session.remove("USERNAME");
// http://docs.oracle.com/javase/7/docs/api/java/util/Map.html#remove(java.lang.Object)

とか

session.clear()
// http://docs.oracle.com/javase/7/docs/api/java/util/Map.html#clear()

とかで

編集 履歴 (0)
  • alice-asahina様、早速のご回答ありがとうございます。
    長くなるので、回答起こします。
    宜しくお願いいたします。
    -
  • alice-asahina様、自己解決致しました。 長くなるので、回答起こします。 今回は自己解決ですので、自分の回答にAcceptさせてください。 -

alice-asahina様、早速のご回答ありがとうございます。

「ログイン処理を実行したら、直前のセッションはクリアすれば」というアドバイス戴き、
早速、
ビルドパスの編成にjstl.jarとstandard.jarを加え
jsp

<%@page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<s:if test="#session.USERNAME.length() != 0">
<s:property value="#session.USERNAME"/>社員<br>
<s:form action="logout">
    <s:submit value="ログアウト"/>
</s:form>
<c:remove var="USERNAME" scope="session"/>
</s:if>
<s:else>
ようこそゲスト社員さん<br>
    <s:form action="login">
        <s:textfield label="ユーザーID" name="userid"/><br>
        <s:password label="パスワード" name="pw"/><br>
        <s:submit value="ログイン"/>
    </s:form>
<s:if test="flg1 == true or flg2 == true">
    <font color="red">IDかパスワードが違います。再入力して下さい。</font>
</s:if>
</s:else>

としましたところ、
ブラウザの「戻る」ボタンを押して、
データベースにないIDとPWを打ち込んでも、ログインしませんでした。

しかし、予想はしていたのですが、
セッションを破棄してしまうと、
この後のコードで"USERNAME"のセッションを利用するので、
アプリ上エラーになってしまいます。
今、考え中なのですが、
どのような考え方で、
「戻る」ボタンを押しても、セッションの有無にかかわらず認証手続きをする
方法をとればよいのでしょうか。
よろしかったらヒントをください。

編集 履歴 (1)
ウォッチ

この質問への回答やコメントをメールでお知らせします。