为什么服务端会知道我是谁-Session解析

314 阅读5分钟

众所周知,每当我们尝试登录至某种网络应用时,总会被提示输入账户密码以进行验证。然而,你们是否曾疑惑过,为何当我们成功完成登录后,服务器竟然能够判断出我们的身份,并据此对我们开放相应的访问权限呢?其实,问题就源于我们在登录过程中所保留在服务器上的 session 以及存在于客户端即我们浏览器内的 cookie。

以我们日常使用的博客平台为例,只要我们成功登录后,无需再次注销登录便可自由评论他人发表的文章。那么,在此过程中,服务器又是如何实现这样的用户权限管理功能呢?接下来便是本堂课程所侧重阐述的主题——session。

在这里插入图片描述 图片来源于网络

在诸多网络应用程序的设计与开发过程中,为了确保用户身份的持续有效及其状态信息的保存与延续,我们常常采用会话 (Session)这种方式来追踪用户的登录状态及其他相关信息。会话是一项在客户端和服务器之间维持数据状态的关键技术手段,它使得服务器得以识别特定使用者并始终保持其登录状态不变。

之前我们已经搭建过了一个servlet应用程序,所以说关于如何搭建一个程序的话,我们这里就不必再阐述了,大家可以直接参考我上一篇讲的文章去进行一个搭建。

Java技术中的经典之作:Servlet的实践运用 juejin.cn/post/731100…

我们首先来看一个session的例子。这里我们新建一个MySession 的类。继承至HttpServlet 类,方便我们后续在Http中进行一个调用。

public class MySession extends HttpServlet {

    /**
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");

        HttpSession session = req.getSession();
        String id = session.getId();

        System.out.println(id);
        System.out.println(session.getAttribute("name"));
        PrintWriter writer = resp.getWriter();
        writer.print("你好");
        writer.close();
    }
}

紧接着我们再新建一个类,继承我们刚刚写的这个类。

@WebServlet(urlPatterns = "/mySession")
public class MySession2 extends MySession {

    /**
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        session.setAttribute("name","masiyi");
        super.doGet(req, resp);
    }
}

之后我们就可以启动浏览器去访问我们的地址。

http://localhost:8080/mySession

在这里插入图片描述

这里就可以看到我们已经成功的在浏览器上看到了你好两个字。

在这里插入图片描述

我们可以看到。刚刚我们访问浏览器的时候,我们在后台已经输出了对应的信息,一个是这个会话的id,一个是我们设置的值

再返回到我们MySession2这个类里面去看一下。

     HttpSession session = req.getSession();
        session.setAttribute("name","masiyi");
        super.doGet(req, resp);

首先我们要知道的是浏览器只要不关我们访问这个地址,它的Session就会是一个Session,我们看刚刚这个类里面我们拿出了他的session之后,给session设置了一个值。之后我们再去调用它父类的doget方法。

        resp.setContentType("text/html;charset=UTF-8");

        HttpSession session = req.getSession();
        String id = session.getId();

        System.out.println(id);
        System.out.println(session.getAttribute("name"));
        PrintWriter writer = resp.getWriter();
        writer.print("你好");
        writer.close();

父类里面拿到sessionID之后进行一个输出,我们再输出我们在子类里面设置的name的值。最后我们拿到PrintWriter 给他返回到浏览器上面去。

我们现在已经看到了。每次发生一次会话的时候,他就会新建一个session。那么大家有没有想过除了我们手动关闭浏览器?而关闭这个session之外,我们可以在代码中手动关闭这个session吗?再想一个问题,我们关闭之后的session。跟之前的session会是一个session吗?所以说我们再次写两个类来验证我们刚刚的问题。

@WebServlet(urlPatterns = "/mySession3")
public class MySession3 extends HttpServlet {

    /**
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(req.getRequestId());
        HttpSession session = req.getSession();
        session.setAttribute("name", "masiyi3");
        //失效
//        session.setMaxInactiveInterval(3);
        //失效
//        session.invalidate();
        String uri = resp.encodeURL("/mySession4");
        resp.sendRedirect(uri);
        System.out.println(uri);
        System.out.println("setAttribute");
        System.out.println(session.getId());
    }
}

  1. session.setMaxInactiveInterval(3);:这行代码用于设置会话的最大非活动时间间隔,单位为秒。在这个例子中,3代表3秒,意味着如果用户在3秒内没有活动(例如没有请求服务器),会话将自动失效。

  2. session.invalidate();:这行代码用于手动使当前会话失效,即立即终止当前会话并清除与之相关的所有数据。通常在用户注销或需要强制用户退出登录时使用。

在这里插入图片描述

当我们在浏览器中访问http://localhost:8080/mySession3这个地址的时候,我们会发现它跳了一下,然后就返回到session4去了,这个时候我们的后台会打印什么呢?我们可以看一下。

在这里插入图片描述

其实我们通过上面的结果知道了。我们在不关闭的情况下,任意重定向跳转之后,他们的section其实还是一个,他们的attribute值是可以相互传递的。

在这里插入图片描述

但是我们手动关闭了这个session之后,我们再次访问老地址,我们就会发现。他们的session其实不是一样的。他们的值也是互不相通的。

读过我前面文章的同学应该知道,我其实正在写一个spring security的入门专栏。所以说这节加上前面的四节其实都是spring security的基础。也就是说你要想了解spring security你必须要了解这五篇文章中所学的知识。所以我把他们全都放在一个项目里面。项目的地址就在 gitee.com/WangFuGui-M…

文章链接
Java技术中的经典之作:Servlet的实践运用juejin.cn/post/731100…
介绍一下傻傻分不清的两个兄弟:过滤器和拦截器之过滤器juejin.cn/post/731160…
介绍一下傻傻分不清的两个兄弟:过滤器和拦截器之拦截器juejin.cn/post/731236…
Java里的线程神器:ThreadLocaljuejin.cn/post/731397…

在后面的spring security的进阶专栏里面。我们会把这五节课的知识全部整合在一起。这就是我写这五节课的目的。如果大家对此有兴趣的话,欢迎关注点赞。加评论。我们spring security的进阶专栏见。

在这里插入图片描述