溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

HttpServletRequest中的安全管理方法是什么

發(fā)布時間:2021-12-17 13:45:47 來源:億速云 閱讀:131 作者:iii 欄目:大數(shù)據(jù)

本篇內(nèi)容主要講解“HttpServletRequest中的安全管理方法是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“HttpServletRequest中的安全管理方法是什么”吧!

Spring Security 中對 HttpServletRequest 請求進行了封裝,重寫了 HttpServletRequest 中的幾個和安全管理相關(guān)的方法,想要理解 Spring Security 中的重寫,就要先從 HttpServletRequest 開始看起。

有小伙伴可能會說,HttpServletRequest 能跟安全管理扯上什么關(guān)系?今天就來和大家捋一捋,我們不講 Spring Security,就來單純講講 HttpServletRequest 中的安全管理方法。

1.HttpServletRequest

在 HttpServletRequest 中,我們常用的方法如:

  • public String getHeader(String name);

  • public String getParameter(String name);

  • public ServletInputStream getInputStream()

這些常見的方法可能大家都有用過,還有一些不常見的,和安全相關(guān)的方法:

public String 
getRemoteUser();
public boolean isUserInRole(String role);
public java.security.Principal getUserPrincipal();
public boolean authenticate(HttpServletResponse response)
           throws IOException, ServletException;
public void login(String username, String password) throws ServletException;
public void logout() throws ServletException;

前面三個方法,在之前的 Servlet 中就有,后面三個方法,則是從 Servlet3.0 開始新增加的方法。從方法名上就可以看出,這些都是和認證相關(guān)的方法,但是這些方法,我估計很多小伙伴都沒用過,因為不太實用。

在 Spring Security 框架中,對這些方法進行了重寫,進而帶來了一些好玩并且方便的特性,這個在后面的文章中再和大家分享。

要理解 Spring Security 中的封裝,就得先來看看,不用框架,這些方法該怎么用!

2.實踐出真知

我們創(chuàng)建一個普普通通的 Web 項目,不使用任何框架(后面的案例都基于此),然后在 doGet 方法中打印出 HttpServletRequest 的類型,代碼如下:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
   System.out.println("request.getClass() = " + request.getClass());
}

代碼運行打印結(jié)果如下:

request.getClass() = 
class org.apache.catalina.connector.RequestFacade

HttpServletRequest 是一個接口,而 RequestFacade 則是一個正兒八經(jīng)的 class。

HttpServletRequest 是 Servlet 規(guī)范中定義的 ServletRequest,這相當(dāng)于是標(biāo)準(zhǔn)的 Request;但是在 Tomcat 中的 Request 則是 Tomcat 自己自定義的 Request,自定義的 Request 實現(xiàn)了 HttpServletRequest 接口并且還定義了很多自己的方法,這些方法還是 public 的,如果直接使用 Tomcat 自定義的 Request,開發(fā)者只需要向下轉(zhuǎn)型就能調(diào)用這些 Tomcat 內(nèi)部方法,這是有問題的,所以又用 RequestFacade 封裝了一下,以至于我們實際上用到的就是 RequestFacade 對象。

那么毫無疑問,HttpServletRequest#login 方法具體實現(xiàn)就是在 Tomcat 的 Request#login 方法中完成的。經(jīng)過源碼追蹤,我們發(fā)現(xiàn),登錄的數(shù)據(jù)源是由 Tomcat 中的 Realm 提供的,注意這個 Realm 不是 Shiro 中的 Realm。

Tomcat 中提供了 6 種 Realm,可以支持與各種數(shù)據(jù)源的對接:

  • JDBCRealm:很明顯,這個 Realm 可以對接到數(shù)據(jù)庫中的用戶信息。

  • DataSourceRealm:它通過一個 JNDI 命名的 JDBC 數(shù)據(jù)源在關(guān)系型數(shù)據(jù)庫中查找用戶。

  • JNDIRealm:通過一個 JNDI 提供者1在 LDAP 目錄服務(wù)器中查找用戶。

  • UserDatabaseRealm:這個數(shù)據(jù)源在 Tomcat 的配置文件中 conf/tomcat-users.xml。

  • MemoryRealm:這個數(shù)據(jù)源是在內(nèi)存中,內(nèi)存中的數(shù)據(jù)也是從 conf/tomcat-users.xml 配置文件中加載的。

  • JAASRealm:JAAS 架構(gòu)來實現(xiàn)對用戶身份的驗證。

如果這些 Realm 無法滿足需求,當(dāng)然我們也可以自定義 Realm,只不過一般我們不這樣做,為啥?因為這這種登錄方式用的太少了!今天這篇文章純粹是和小伙伴們開開眼界。

如果自定義 Realm 的話,我們只需要實現(xiàn) org.apache.catalina.Realm 接口,然后將編譯好的 jar 放到 $CATALINA_HOME/lib 下即可,具體的配置則和下面介紹的一致。

接下來我和大家介紹兩種配置方式,一個是 UserDatabaseRealm,另一個是 JDBCRealm。

2.1 基于配置文件登錄

我們先來定義一個 LoginServlet:

@WebServlet(urlPatterns = 
"/login")
public class LoginServlet extends HttpServlet {
   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       doPost(req, resp);
   }

   @Override
   protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       String username = req.getParameter("username");
       String password = req.getParameter("password");
       try {
           req.login(username, password);
       } catch (ServletException e) {
           req.getRequestDispatcher("/login.jsp").forward(req, resp);
           return;
       }
       boolean login = req.getUserPrincipal() != null && req.isUserInRole("admin");
       if (login) {
           resp.sendRedirect("/hello");
           return;
       } else {
           req.getRequestDispatcher("/login.jsp").forward(req, resp);
       }
   }
}

當(dāng)請求到達后,先提取出用戶名和密碼,然后調(diào)用 req.login 方法進行登錄,如果登錄失敗,則跳轉(zhuǎn)到登錄頁面。

登錄完成后,通過獲取登錄用戶信息以及判斷登錄用戶角色,來確保用戶是否登錄成功。

如果登錄成功,就跳轉(zhuǎn)到項目應(yīng)用首頁,否則就跳轉(zhuǎn)到登錄頁面。

接下來定義 HelloServlet:

@WebServlet(urlPatterns = 
"/hello")
public class HelloServlet extends HttpServlet {
   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       doPost(req,resp);
   }

   @Override
   protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       Principal userPrincipal = req.getUserPrincipal();
       if (userPrincipal == null) {
           resp.setStatus(401);
           resp.getWriter().write("please login");
       } else if (!req.isUserInRole("admin")) {
           resp.setStatus(403);
           resp.getWriter().write("forbidden");
       }else{
           resp.getWriter().write("hello");
       }
   }
}

在 HelloServlet 中,先判斷用戶是否已經(jīng)登錄,沒登錄的話,就返回 401,已經(jīng)登錄但是不具備相應(yīng)的角色,就返回 403,否則就返回 hello。

接下來再定義 LogoutServlet,執(zhí)行注銷操作:

@WebServlet(urlPatterns = 
"/logout")
public class LogoutServlet extends HttpServlet {
   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       doPost(req,resp);
   }

   @Override
   protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       req.logout();
       resp.sendRedirect("/hello");
   }
}

logout 方法也是 HttpServletRequest 自帶的。

最后再簡單定義一個 login.jsp 頁面,如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
   <title>Title</title>
</head>
<body>
<form action="/login" method="post">
   <input type="text" name="username">
   <input type="text" name="password">
   <input type="submit" value="登錄">
</form>
</body>
</html>

所有工作都準(zhǔn)備好了,接下來就是數(shù)據(jù)源了,默認情況下加載的是 conf/tomcat-users.xml 中的數(shù)據(jù),找到 Tomcat 的這個配置文件,修改之后內(nèi)容如下:

<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users>
   <role rolename="admin"/>
   <user username="javaboy" password="123" roles="admin"/>
</tomcat-users>

配置完成后,啟動項目進行測試。登錄用戶名是 javaboy,登錄密碼是 123,具體的測試過程我就不再演示了。

2.2 基于數(shù)據(jù)庫登錄

如果想基于數(shù)據(jù)庫登錄,我們需要先準(zhǔn)備好數(shù)據(jù)庫和表,需要兩張表,user 表和 role 表,如下:

CREATE TABLE `user` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `username` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
 `password` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE `role` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `username` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
 `role_name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

然后向表中添加兩行模擬數(shù)據(jù):

HttpServletRequest中的安全管理方法是什么

HttpServletRequest中的安全管理方法是什么

接下來,找到 Tomcat 的 conf/server.xml 文件,修改配置,如下:

<Realm className="org.apache.catalina.realm.LockOutRealm">
 <Realm  className="org.apache.catalina.realm.JDBCRealm" debug="99"
       driverName="com.mysql.jdbc.Driver"
       connectionURL="jdbc:mysql://localhost:3306/basiclogin"
       connectionName="root" connectionPassword="123"
       userTable="user" userNameCol="username"    
       userCredCol="password"
       userRoleTable="role" roleNameCol="role_name" />
</Realm>

在這段配置中:

  • 指定 JDBCRealm。

  • 指定數(shù)據(jù)庫驅(qū)動。

  • 指定數(shù)據(jù)庫連接地址。

  • 指定數(shù)據(jù)庫連接用戶名/密碼。

  • 指定用戶表名稱;用戶名的字段名以及密碼字段名。

  • 指定角色表名稱;以及角色字段名。

配置完成后,再次登錄測試,此時的登錄數(shù)據(jù)就是來自數(shù)據(jù)庫的數(shù)據(jù)了。

3.優(yōu)化

前面的 HelloServlet,我們是在代碼中手動配置的,要是每個 Servlet 都這樣配置,這要搞到猴年馬月了~

所以我們對此可以在 web.xml 中進行手動配置。

首先我們創(chuàng)建一個 AdminServlet 進行測試,如下:

@WebServlet(urlPatterns = 
"/admin/hello")
public class AdminServlet extends HttpServlet {
   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       resp.getWriter().write("hello admin!");
   }
}

然后在 web.xml 中進行配置:

<security-constraint>
   <web-resource-collection>
       <web-resource-name>admin</web-resource-name>
       <url-pattern>/admin/*</url-pattern>
   </web-resource-collection>
   <auth-constraint>
       <role-name>admin</role-name>
   </auth-constraint>
</security-constraint>
<security-role>
   <role-name>admin</role-name>
</security-role>

這個配置表示 /admin/* 格式的請求路徑,都需要具有 admin 角色才能訪問,否則就訪問不到,這樣,每一個 Admin 相關(guān)的 Servlet 就被保護起來了,不用在 Servlet 中寫代碼判斷了。

到此,相信大家對“HttpServletRequest中的安全管理方法是什么”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI