程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> struts2, 注銷賬號後, 通過地址欄訪問action仍然可以登錄的問題(通過浏覽器輸入地址,繞過驗證的問題),struts2action

struts2, 注銷賬號後, 通過地址欄訪問action仍然可以登錄的問題(通過浏覽器輸入地址,繞過驗證的問題),struts2action

編輯:JAVA綜合教程

struts2, 注銷賬號後, 通過地址欄訪問action仍然可以登錄的問題(通過浏覽器輸入地址,繞過驗證的問題),struts2action


不多廢話, 先來問題.

問題: 用struts2結合spring做了一個用戶登錄的, 然後點擊之後可以注銷的例子.

      登錄頁面很簡單, 大概就是像如下這個樣子

  

  登錄的action和注銷的action在strut.xml中為如下配置:

<action name="checkUser" class="checkUserAction" method="execute">       //這裡的class="checkUserAction"是獲取的spring配置文件中的bean
  <result name="login">/WEB-INF/jsp/login/login.jsp</result> //這裡是登錄失敗的話, 會重新返回到登錄頁面 
  <result name="success">/WEB-INF/jsp/list/home.jsp</result> //這裡是登錄成功的話, 會進入到歡迎界面
</action>

<action name="quitUser" class="checkUserAction" method="quitUser"> //注銷的action,注銷成功返回登錄頁面

  <result name="success">/WEB-INF/jsp/login/login.jsp </result>  

</action>



   spring的配置文件如下:

<bean id="administrator" class="pojo.Administrator">
    </bean>
    
    <bean id="checkUserAction" class="action.checkUserAction" scope="prototype">
        <property name="adminer">
            <ref bean="administrator"/>
        </property>
        <property name="adminUserService">
            <ref bean="adminUserServiceImpl"/>
        </property>
    </bean>
checkUserAction的源代碼如下:
public class checkUserAction extends ActionSupport implements ModelDriven<Administrator>{
    Administrator adminer;
    AdminUserService adminUserService;
    @Override
    public String execute() throws Exception {
        String result = adminUserService.findAdministrator(adminer);  //這裡的一行, 是我在將表單提交過來的用戶名密碼和數據庫中的做對比, 如果成功就將這個放入session, 失敗的話就做相應的提示,
        if(!result.equals("success"))
        {
            if(result.equals(AdminUserService.NOT_EXIST))
            {
                ServletActionContext.getRequest().setAttribute("error", "用戶名不存在");
            }
            else if(result.equals(AdminUserService.WRONG_PASSWORD))
            {
                ServletActionContext.getRequest().setAttribute("error", "密碼錯誤");
            }
            return "login";
        }
        ActionContext.getContext().getSession().put("adminUser", adminer);
        return result;    
    }
    
  /*下述為注銷用戶時使用的方法, 將session清空*/ public String quitUser() throws Exception {     ActionContext.getContext().getSession().clear(); return "success"; } ......get和set方法略, 並且模型驅動的部分也略 }

  就是這麼一個簡單的程序, 登錄沒問題, 退出也可以正常退出. 但是這裡我卻發現了一個嚴重的問題,

  就是我在點擊退出之後, 通過在地址欄直接輸入action的地址:"http://localhost:8080/xxx/checkUser" 來繞過通過點擊"登錄"按鈕, 直接訪問的時候, 居然可以正常登錄到歡迎界面!!!

  這個問題困擾了我很久, 在網上也查了很多方法:

  1. 有人說需要建立攔截器, 通過在攔截器中屏蔽不合法的登錄用戶可以做到, 後來我嘗試了不行.

  2. 還有的說要禁止動態訪問, 可我發現我的頁面本身就是默認禁止動態訪問的action中的method的. (只不過人家是直接訪問的action的名字, 不是訪問的action中的method).

  3. 我又查, 看struct2能夠直接屏蔽在地址欄直接輸入action的名字來進行訪問的方法, 似乎也米有這種方法, 也就說地址欄是肯定可以直接輸入action的名字來進行訪問的!

    繼續分析, 我在checkUserAction 中, 加了打印, 直接將用來獲取表單數據的adminer對象(也就是存放用戶名密碼)裡面的數據都打了出來, 居然打出來的值也都是正確的. 然後我就很納悶了, 我明明已經退出登錄了, 通過strut2的標簽<s:debug/>檢查, session裡面確實已經沒有任何東西了, 但是通過地址欄訪問checkUser這個action的時候, 居然那個adminer對象裡面還有值! 而我又不是通過點擊表單的登錄按鈕, 而是通過直接在地址欄訪問action來訪問的頁面, 那麼這個正確的數據到底是誰提交的呢? 然後, 我又把浏覽器的抓包工具打開, 發現我在直接訪問action的時候, 確實裡面也沒有附帶任何的表單(用戶名密碼)信息, 那這個值到底是誰給裝進去的呢?

  我然後, 又懷疑, 是不是模型驅動干了什麼壞事? 是不是模型驅動在我退出的時候, 把用戶名密碼給裝填了進去, 然後發回給了浏覽器, 但是後來看了下模型驅動的源碼, 模型驅動僅僅在action執行之前的時候, 會把獲取到的表單數據, 通過一個模型壓入到值棧中, action執行完之後, 並沒有做任何事情. 而且我還做了這樣的操作, 我在quitUser()的函數中, 在返回"success"之前, 把值棧裡面所有的內容也都給清空了, 然而, 問題依舊!!!

  最後最後, 我才忽然發現了一個問題, 既然通過地址欄直接訪問action地址, 是無法提交表單數據的, 同時session中的數據也清空了, 那只能說明一個問題, 就是這個 adminer對象裡面的值肯定是服務器給賦進去的! 於是自然而然的想到了肯定是spring的問題. 原因: 因為spring在產生action對象時, 應該是多實例的, 就是每有一個請求, 就會產生一個action對象, 這是沒問題的. 但問題是, 我在配置checkUserAction的時候, 沒有把它的屬性adminer對象也給賦值成多實例, 導致了在下一次的action中, spring返回給action使用的adminer對象, 仍然是之前成功登錄過一次的那個adminer對象, 這個對象裡面仍然保存著上一次成功登錄時的用戶名密碼信息, 因此, 直接訪問地址欄的時候, 它直接就用了之前的這個對象去進行驗證了, 那當然是可以通過的了. 這就是問題的根本所在.

  其實經驗證, 我通過地址欄訪問checkUser這個Action, 登錄後的頁面裡面, 打開<s:debug/>開關, 能夠看到每一次訪問之後, session中存的那個adminer對象的值都沒變化過, 就能夠說明這個問題.

  所以, 只需將spring配置文件裡面<bean id="administrator" class="pojo.Administrator" scope="prototype">下面這一行, 將其改為多實例即可.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved