إدارة الجلسات في جافا – HttpServlet، الكوكيز، إعادة الكتابة لعناوين URL

إدارة الجلسة في تطبيقات الويب Servlet في جافا موضوع مثير للاهتمام للغاية. الجلسة في جافا Servlet يتم إدارتها من خلال طرق مختلفة، مثل الكوكيز، واجهة برمجة التطبيقات لجلسة HTTP، إعادة كتابة عنوان URL إلخ. هذه هي المقالة الثالثة في سلسلة تعليمية حول تطبيقات الويب في جافا، قد ترغب في التحقق من المقالتين السابقتين أيضًا.

  1. دورة تعليمية لتطبيقات الويب في جافا
  2. دورة تعليمية ل Servlet في جافا

إدارة الجلسة في جافا

يهدف هذا المقال إلى شرح إدارة الجلسة في الـ Servlet باستخدام تقنيات مختلفة وبرامج مثالية.

  1. ما هي الجلسة؟

  2. إدارة الجلسة في جافا – الكوكيز

  3. الجلسة في سيرفلت جافا – HttpSession

  4. إدارة الجلسة في سيرفلت جافا – إعادة توجيه عن طريق عنوان URL

  5. ما هي الجلسة؟

    بروتوكول HTTP وخوادم الويب لا يحملان الحالة، ما يعني أنه بالنسبة لخادم الويب، كل طلب هو طلب جديد لمعالجته ولا يمكنهم التعرف على ما إذا كان يأتي من عميل قام بإرسال طلبات سابقًا أم لا. ولكن في بعض الأحيان في تطبيقات الويب، يجب علينا أن نعرف من هو العميل ونعالج الطلب وفقًا لذلك. على سبيل المثال، يجب أن يعرف تطبيق سلة التسوق من يرسل الطلب لإضافة عنصر وفي أي سلة يجب إضافة العنصر، أو من يرسل طلب الخروج بحيث يمكنه تحصيل المبلغ من العميل الصحيح. الجلسة هي حالة تواصلية بين العميل والخادم ويمكن أن تتألف من عدة طلبات واستجابات بين العميل والخادم. نظرًا لأن بروتوكول HTTP وخادم الويب على حد سواء لا يحملان الحالة، الطريقة الوحيدة للحفاظ على جلسة هي عندما يتم تمرير معلومات فريدة عن الجلسة (معرف الجلسة) بين الخادم والعميل في كل طلب واستجابة. هناك عدة طرق يمكننا من خلالها توفير معرف فريد في الطلب والاستجابة.

  6. المصادقة للمستخدم – هذه هي الطريقة الشائعة جدًا حيث يمكن للمستخدم تقديم بيانات اعتماد المصادقة من صفحة تسجيل الدخول ثم يمكننا تمرير معلومات المصادقة بين الخادم والعميل للحفاظ على الجلسة. هذه الطريقة ليست فعالة جدًا لأنها لن تعمل إذا قام نفس المستخدم بتسجيل الدخول من متصفحات مختلفة.

  7. حقل HTML مخفي – يمكننا إنشاء حقل مخفي فريد في HTML وعندما يبدأ المستخدم في التنقل، يمكننا تعيين قيمته فريدة للمستخدم وتتبع الجلسة. لا يمكن استخدام هذه الطريقة مع الروابط لأنها تحتاج إلى تقديم النموذج في كل مرة يتم فيها إرسال طلب من العميل إلى الخادم مع الحقل المخفي. كما أنها ليست آمنة لأنه يمكننا الحصول على قيمة الحقل المخفي من مصدر HTML واستخدامها لاختراق الجلسة.

  8. إعادة كتابة العنوان (URL Rewriting) – يمكننا إلحاق معلمة معرف الجلسة بكل طلب واستجابة لتتبع الجلسة. هذا ممل جدًا لأنه يتعين علينا تتبع هذه المعلمة في كل استجابة والتأكد من أنها لا تتعارض مع معلمات أخرى.

  9. الكوكيز – الكوكيز هي قطعة صغيرة من المعلومات التي يتم إرسالها بواسطة خادم الويب في رأس الاستجابة ويتم تخزينها في ملفات تعريف الارتباط في المتصفح. عندما يقدم العميل طلبًا إضافيًا، يضيف الكوكيز إلى رأس الطلب ويمكننا الاستفادة منه لتتبع الجلسة. يمكننا الحفاظ على جلسة مع الكوكيز ولكن إذا قام العميل بتعطيل الكوكيز، فلن يعمل ذلك.</diy

  10. إدارة الجلسات في جافا – الكوكيز

    يتم استخدام الكوكيز كثيرًا في تطبيقات الويب لتخصيص الاستجابة بناءً على اختيارك أو لتتبع الجلسة. قبل المضي قدمًا إلى واجهة برمجة تطبيقات إدارة الجلسة Servlet، أود أن أوضح كيف يمكننا تتبع الجلسة باستخدام الكوكيز من خلال تطبيق ويب صغير. سنقوم بإنشاء تطبيق ويب ديناميكي ServletCookieExample مع هيكل المشروع كما هو موضح في الصورة أدناه. ملف الوصف التنفيذي web.xml لتطبيق الويب هو:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://java.sun.com/xml/ns/javaee" xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
      <display-name>ServletCookieExample</display-name>
      <welcome-file-list>
        <welcome-file>login.html</welcome-file>
      </welcome-file-list>
    </web-app>
    

    صفحة الترحيب لتطبيقنا هي login.html حيث سنحصل على تفاصيل المصادقة من المستخدم.

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="US-ASCII">
    <title>صفحة تسجيل الدخول</title>
    </head>
    <body>
    
    <form action="LoginServlet" method="post">
    
    اسم المستخدم: <input type="text" name="user">
    <br>
    كلمة المرور: <input type="password" name="pwd">
    <br>
    <input type="submit" value="تسجيل الدخول">
    </form>
    </body>
    </html>
    

    هذا هو LoginServlet الذي يتولى طلب تسجيل الدخول.

    package com.journaldev.servlet.session;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.RequestDispatcher;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * Servlet implementation class LoginServlet
     */
    @WebServlet("/LoginServlet")
    public class LoginServlet extends HttpServlet {
    	private static final long serialVersionUID = 1L;
    	private final String userID = "Pankaj";
    	private final String password = "journaldev";
    
    	protected void doPost(HttpServletRequest request,
    			HttpServletResponse response) throws ServletException, IOException {
    
    		// get request parameters for userID and password
    		String user = request.getParameter("user");
    		String pwd = request.getParameter("pwd");
    		
    		if(userID.equals(user) && password.equals(pwd)){
    			Cookie loginCookie = new Cookie("user",user);
    			//setting cookie to expiry in 30 mins
    			loginCookie.setMaxAge(30*60);
    			response.addCookie(loginCookie);
    			response.sendRedirect("LoginSuccess.jsp");
    		}else{
    			RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html");
    			PrintWriter out= response.getWriter();
    			out.println("<font color=red>إما اسم المستخدم أو كلمة المرور خطأ.</font>");
    			rd.include(request, response);
    		}
    
    	}
    
    }
    

    لاحظ الكوكيز الذي نقوم بتعيينه للاستجابة ثم توجيهه إلى LoginSuccess.jsp، سيتم استخدام هذا الكوكيز هناك لتتبع الجلسة. كما لاحظ أن مهلة الكوكيز مُعينة على 30 دقيقة. في الواقع يجب أن يكون هناك منطق معقد لتعيين قيمة الكوكيز لتتبع الجلسة بحيث لا تتعارض مع أي طلب آخر.

    <%@ page language="java" contentType="text/html; charset=US-ASCII"
    pageEncoding="US-ASCII"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
    <title>صفحة نجاح تسجيل الدخول</title>
    </head>
    <body>
    <%
    String userName = null;
    Cookie[] cookies = request.getCookies();
    if(cookies !=null){
    for(Cookie cookie : cookies){
    if(cookie.getName().equals("user")) userName = cookie.getValue();
    }
    }
    if(userName == null) response.sendRedirect("login.html");
    %>
    <h3>مرحباً <%=userName %>, تم تسجيل الدخول بنجاح.</h3>
    <br>
    <form action="LogoutServlet" method="post">
    <input

  11. الجلسة في سيرفليت جافا – HttpSession

    واجهة Servlet API توفر إدارة الجلسة من خلال واجهة HttpSession. يمكننا الحصول على الجلسة من كائن HttpServletRequest باستخدام الأساليب التالية. تتيح لنا HttpSession تعيين الكائنات كسمات يمكن الوصول إليها في طلبات مستقبلية.

    1. HttpSession getSession() – تُرجع هذه الطريقة دائمًا كائن HttpSession. تُرجع كائن الجلسة المرتبط بالطلب، إذا لم يكن هناك جلسة مرتبطة بالطلب، فإنها تنشئ جلسة جديدة وتُرجعها.
    2. HttpSession getSession(boolean flag) – تُرجع هذه الطريقة كائن HttpSession إذا كان الطلب يحتوي على جلسة ، وإلا فإنها تُرجع قيمة null.

    بعض الأساليب الهامة لـ HttpSession هي:

    1. String getId() – ترجع سلسلة نصية تحتوي على المعرف الفريد المخصص لهذه الجلسة.
    2. Object getAttribute(String name) – ترجع الكائن المرتبط بالاسم المحدد في هذه الجلسة، أو قيمة null إذا لم يتم ربط أي كائن بالاسم. بعض الأساليب الأخرى للعمل مع سمات الجلسة هي getAttributeNames()، removeAttribute(String name) و setAttribute(String name, Object value).
    3. long getCreationTime() – ترجع الوقت عند إنشاء هذه الجلسة، ويتم قياسه بالمللي ثانية من منتصف ليلة 1 يناير 1970 بتوقيت جرينتش. يمكننا الحصول على وقت آخر وصول باستخدام طريقة getLastAccessedTime().
    4. setMaxInactiveInterval(int interval) – تحدد الوقت، بالثواني، بين طلبات العميل قبل أن يلغي محتويات الجلسة هذه. يمكننا الحصول على قيمة فترة انتهاء الجلسة من طريقة getMaxInactiveInterval().
    5. ServletContext getServletContext() – ترجع كائن ServletContext للتطبيق.
    6. boolean isNew() – تُرجع true إذا كان العميل لا يعرف بعد عن الجلسة أو إذا اختار العميل عدم الانضمام إلى الجلسة.
    7. void invalidate() – تبطل هذه الجلسة ثم تلغي ربط أي كائنات مرتبطة بها.

    عند استخدامنا لطريقة HttpServletRequest getSession() وتنشئ طلبًا جديدًا، فإنها تنشئ كائن HttpSession جديدًا وتضيف أيضًا ملف تعريف الارتباط إلى كائن الاستجابة باسم JSESSIONID والقيمة هي معرف الجلسة. يُستخدم هذا الملف التعريفي لتحديد كائن HttpSession في طلبات لاحقة من العميل. إذا تم تعطيل ملفات تعريف الارتباط عند جانب العميل واستخدمنا إعادة الكتابة لعناوين URL ، فإن هذه الطريقة تستخدم قيمة jsessionid من عنوان URL الطلب للعثور على الجلسة المقابلة. يُستخدم ملف تعريف الارتباط JSESSIONID لتتبع الجلسة، لذا يجب أن لا نستخدمه لأغراض تطبيقنا لتجنب أي مشاكل متعلقة بالجلسة. دعنا نرى مثالًا على إدارة الجلسة باستخدام كائن HttpSession. س

  12. إدارة الجلسة في جافا سيرفلت – إعادة توجيه عنوان URL

    كما رأينا في القسم السابق أنه يمكننا إدارة جلسة بواسطة HttpSession ولكن إذا قمنا بتعطيل الكوكيز في المتصفح، فلن يعمل لأن الخادم لن يتلقى كوكي JSESSIONID من العميل. توفر واجهة برمجة تطبيقات سيرفلت دعمًا لإعادة توجيه عناوين URL التي يمكننا استخدامها لإدارة الجلسة في هذه الحالة. الجزء الأفضل هو أنه من وجهة نظر البرمجة، فإنه من السهل جدًا الاستخدام وينطوي على خطوة واحدة فقط – تشفير العنوان URL. شيء آخر جيد مع ترميز عنوان URL لسيرفلت هو أنها طريقة احتياطية وتنشط فقط إذا تم تعطيل كوكيز المتصفح. يمكننا تشفير عنوان URL بواسطة طريقة HttpServletResponse encodeURL() وإذا كان علينا توجيه الطلب إلى مورد آخر ونريد توفير معلومات الجلسة، يمكننا استخدام طريقة encodeRedirectURL(). سنقوم بإنشاء مشروع مماثل للمشروع أعلاه باستثناء أننا سنستخدم طرق إعادة توجيه عناوين URL للتأكد من عمل إدارة الجلسة بشكل جيد حتى إذا تم تعطيل الكوكيز في المتصفح. يبدو هيكل مشروع ServletSessionURLRewriting في eclipse كما في الصورة أدناه.

    package com.journaldev.servlet.session;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.RequestDispatcher;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    /**
     * Servlet implementation class LoginServlet
     */
    @WebServlet("/LoginServlet")
    public class LoginServlet extends HttpServlet {
    	private static final long serialVersionUID = 1L;
    	private final String userID = "admin";
    	private final String password = "password";
    
    	protected void doPost(HttpServletRequest request,
    			HttpServletResponse response) throws ServletException, IOException {
    
    		// get request parameters for userID and password
    		String user = request.getParameter("user");
    		String pwd = request.getParameter("pwd");
    		
    		if(userID.equals(user) && password.equals(pwd)){
    			HttpSession session = request.getSession();
    			session.setAttribute("user", "Pankaj");
    			//setting session to expiry in 30 mins
    			session.setMaxInactiveInterval(30*60);
    			Cookie userName = new Cookie("user", user);
    			response.addCookie(userName);
    			//Get the encoded URL string
    			String encodedURL = response.encodeRedirectURL("LoginSuccess.jsp");
    			response.sendRedirect(encodedURL);
    		}else{
    			RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html");
    			PrintWriter out= response.getWriter();
    			out.println("<font color=red>إما اسم المستخدم أو كلمة المرور غير صحيحة.</font>");
    			rd.include(request, response);
    		}
    
    	}
    
    }
    
    <%@ page language="java" contentType="text/html; charset=US-ASCII"
        pageEncoding="US-ASCII"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
    <title>صفحة تسجيل الدخول الناجحة</title>
    </head>
    <body>
    <%
    //allow access only if session exists
    String user = null;
    if(session.getAttribute("user") == null){
    	response.sendRedirect("login.html");
    }else user = (String) session.getAttribute("user");
    String userName = null;
    String sessionID = null;
    Cookie[] cookies = request.getCookies();
    if(cookies !=null){
    for(Cookie cookie : cookies){
    	if(cookie.getName().equals("user")) userName = cookie.getValue();
    	if(cookie.getName().equals("JSESSIONID")) sessionID = cookie.getValue();
    }
    }else{
    	sessionID = session.getId();
    }
    %>
    <h3>مرحباً <%=userName %>، تم تسجيل الدخول بنجاح. معرف الجلسة الخاص بك=<%=sessionID %></h3>
    <br>
    المستخدم=<%=user %>
    <br>
    <!-- need to encode all the URLs where we want session information to be passed -->
    <a href="<%=response.encodeURL("CheckoutPage.jsp") %>">صفحة الخروج</a>
    <form action="<%=response.encodeURL("LogoutServlet") %>" method="post">
    <input type="submit" value="تسجيل الخروج" >
    </form>
    </body>
    </html>
    

    <%@ page language="java" contentType

هذا كل شيء بالنسبة لإدارة الجلسة في سيرفلت جافا، سننظر في عوامل تصفية سيرفلت والمستمعين وملفات تعريف الارتباط في مقالات المستقبل. التحديث: تحقق من المقالة التالية في السلسلة عامل تصفية سيرفلت.

تحميل المشاريع

Source:
https://www.digitalocean.com/community/tutorials/java-session-management-servlet-httpsession-url-rewriting