SpringMVC 07: WEB-INF下的資源訪問 + SpringMVC攔截器
WBE-INF目錄下的資源訪問
-
項目配置和Spring部落格集(指SpringMVC 02)中配置一樣
-
出於對網站資源的安全性保護,放在WBE-INF目錄下的資源不可以被外部直接訪問
-
在WEB-INF/jsp/下新建index.jsp和main.jsp,作為WEB-INF目錄下的資源
-
部署並啟動tomcat,根據2個資源的位置,嘗試直接在地址欄訪問
-
結果如下,兩個資源均訪問不到
- 修改springmvc.xml中視圖解析器如下
<!-- 添加視圖解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置前綴-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 配置後綴-->
<property name="suffix" value=".jsp"/>
</bean>
- 新增控制器:WebInFAction,兩個action方法分別轉發請求WEB-INF下的相應資源
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class WebInfAction {
@RequestMapping("/showIndex")
public String showIndex(){
return "index";
}
@RequestMapping("/showMain")
public String showMain(){
return "main";
}
}
- 分別訪問localhost:8080/showIndex.action和localhost:8080/showMain.action,成功訪問WEB-INF下的資源
- 由於在web.xml中配置了接受處理的請求的格式”*.action”,所以如果請求想要被處理必須以”.action”結尾,修改該請求通配條件為”/”,即對所有請求都接受處理
- 分別訪問localhost:8080/showIndex和localhost:8080/showMain,去掉訪問後綴後,也可以成功訪問WEB-INF下的資源
- 雖然通過action轉發比直接輸入資源地址要安全一些,但是如果直接輸入:localhost:8080/showMain也可以直接訪問到WEB-INF下的資源,所以上述經action方法轉發的方式其實也不安全。
- 我們嘗試增加一個登陸驗證,使得只有登陸成功的用戶才可以訪問到WEB-INF下的main.jsp資源
- webapp/index.jsp:點擊超鏈接,向伺服器請求登陸頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index.jsp</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/showLogin">去登陸</a>
</body>
</html>
- WEB-INF/jsp/新增login.jsp:作為登陸頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>login.jsp</title>
</head>
<body>
<!-- 完成登陸資訊的提交 -->
<h1>登陸</h1>
<form action="${pageContext.request.contextPath}/login" method="post">
用戶名:<input type="text" name="username">
密碼:<input type="password" name="password">
<input type="submit" value="提交">
</form>
<!-- 如果登陸失敗,顯示登陸失敗資訊-->
${msg}
</body>
</html>
- 控制器WebInfAction如下:新增登陸頁面的轉發功能,以及對登陸資訊的驗證判斷功能
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
@Controller
public class WebInfAction {
@RequestMapping("/showIndex")
public String showIndex(){
return "index";
}
@RequestMapping("/showMain")
public String showMain(){
return "main";
}
@RequestMapping("/showLogin")
public String showLogin(){
return "login";//轉發並返回登陸頁面
}
//對登陸資訊進行判斷,用戶資訊符合是轉發跳轉到main.jsp,資訊不符合時,填入登陸失敗的資訊並重新轉發到登陸頁面
@RequestMapping("/login")
public String login(String username, String password, HttpServletRequest request){
if(username.equals("荷包蛋") && password.equals("hebaodan")){
return "main";
}else{
request.setAttribute("msg", "用戶名或密碼錯誤");
return "login";
}
}
}
- 部署並啟動tomcat測試
- 當登陸資訊錯誤時
- 當登陸資訊正確時
- 但是如果直接訪問:localhost:8080/showMain,仍然可以越過登陸,直接訪問WEB-INF下的資源,仍然不安全
SpringMVC攔截器
- 攔截器執行原理
-
攔截器的作用:
-
針對請求和響應進行額外的處理,在請求和響應的過程中添加預處理,後處理和最終處理
-
攔截器執行的時機:
-
preHandle():在請求被處理之前進行操作,即預處理
-
postHandle():在請求被處理之後,但結果還沒有渲染前進行操作,可以改變響應結果,即後處理
-
afterCompletion:所有的請求響應結束後執行善後工作,清理對象,關閉資源,即最終處理
-
攔截器實現的兩種方式:
-
繼承HandlerInterceptorAdapter父類
-
或者實現HandlerInterceptor介面(推薦使用介面方式:java遵循單繼承,不要輕易的去繼承那些非核心業務的父類,否則就無法再繼承其他業務類了,對於某些附加功能,去實現相應介面就可以了,因為允許實現很多介面)
-
攔截器的實現步驟:
-
改造登陸方法,在session中存儲用戶資訊,用於進行許可權驗證
-
開發攔截器的功能,實現HandlerInterceptor介面,重寫preHandle()方法,進行登陸資訊驗證
-
在springmvc.xml文件中註冊攔截器
-
使用攔截器繼續改造上述WEB-INF下資源的安全訪問:
-
WebInfAction中的login方法修改如下:登陸成功後,向session域中存放用戶資訊,用於後續安全驗證
@RequestMapping("/login")
public String login(String username, String password, HttpServletRequest request){
if(username.equals("荷包蛋") && password.equals("hebaodan")){
//如果登陸成功,則設置session資訊
request.getSession().setAttribute("user", username);
return "main";
}else{
request.setAttribute("msg", "用戶名或密碼錯誤");
return "login";
}
}
- 新增登陸攔截器
package com.example.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 登陸攔截器
*/
public class LoginInterceptor implements HandlerInterceptor {
//預處理攔截
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//驗證session資訊,判斷是否登陸成功
if(request.getSession().getAttribute("user") == null){
request.setAttribute("msg", "還未登陸,清先登陸");
//打回登陸頁面(頁面轉發實現頁面跳轉)
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;//驗證資訊未通過
}
return true;//驗證資訊通過,放行
}
}
- 在springmvc.xml中新增對攔截器的註冊
<!-- 配置SpringMVC攔截器-->
<mvc:interceptors>
<!-- 可以配置多個攔截規則,形成攔截鏈-->
<mvn:interceptor>
<!-- 映射要攔截的請求:所有請求-->
<mvn:mapping path="/**"/>
<!-- 設置要放行的請求:有些必備的登陸請求不能攔截-->
<mvn:exclude-mapping path="/showLogin"/>
<mvn:exclude-mapping path="/login"/>
<!-- 配置實現攔截器功能的實現類-->
<bean class="com.example.interceptor.LoginInterceptor"/>
</mvn:interceptor>
</mvc:interceptors>
- 部署並啟動tomcat測試
- 當越過登陸直接訪問WEB-INF下的資源時,未能通過驗證,被打回登陸頁面
- 登陸成功後,新建窗口,直接訪問,此時session域中資訊還未過期,成功通過驗證