理解 Cookie,Session 机制 && 实现用户登录

目录

1. 理解 Cookie 机制和 Session 机制

2.  Cookie 和 Session 的区别

3. Servlet 对于 Cookie 和 Session 提供的 API

4. 实现用户登录

4.1 理解 req.getSession() 

4.2 理解上述代码客户端和服务器交互过程


1. 理解 Cookie 机制和 Session 机制

由于HTTP 协议自身是属于 "无状态" 协议. 也就是说默认情况下 HTTP 协议的客户端和服务器之间的这次通信, 和下次通信之间没有直接的联系.

但是很多时候,一些登录网站, 我们首次登录的时候, 需要输入账号密码, 第二次登录的时候, 服务器就应该能够知道当前用户此次请求是否已经登录过, 服务器如何才能知道呢? 搭配 Cookie 和 Session 就能够让服务器知道了.

1. 浏览器站在安全的角度考虑, 不敢让页面直接来访问文件系统, Cookie 就是浏览器给 HTTP 协议提供的一个持久化存储数据的方案.

2. Cookie 里面存储的是键值对, 不能存储复杂的对象, 只能存储字符串; 并且 Cookie 是按照域名来进行分类存储的.

3.Cookie 数据从哪来, 到哪去? Cookie 数据来自于服务器, 服务器代码想让浏览器存啥, 就返回啥  (通过在 HTTP 响应报文中的 Header 加入 Set-Cookie) ; Cookie 数据又回到服务器去, 每次给服务器发送的 HTTP 请求, 就会带上之前存储的 Cookie 信息 (在请求 Header 中带有 Cookie 属性).

Cookie 的典型应用: 登录网站中保存用户的身份信息

具体实现:

1. 可以让服务器把用户的所有信息通过 Set-Cookie 返回给浏览器, 直接在浏览器保存, 但是这种做法是不推荐的, 一是因为用户可以手动清除 Cookie 数据 , 其次就是敏感的信息通过网络传输不安全.

2. 更典型靠谱的做法是在服务器这边保存用户的详细信息, 使用键值对来进行保存 (Session) ,键是服务器自动生成的一串唯一字符串 (SessionId), 值就是用户的详细信息了, 服务器就可以把这个键通过 Set-Cookie 返回给浏览器了.

 上述流程就类似于去医院看病, 医院就是服务器, 患者就是客户端.

1. 首次去医院的时候, 医院没有这个患者的身份信息, 就要求患者去办理就诊卡.

2. 办理就诊卡就需要提供身份证等信息, 就会在医院的系统中建档 (创建了一个session), 同时医院会给患者一个就诊卡 (包含SessionId) .

3. 后续这个患者去其他科室做检查, 只要刷就诊卡就行了.


2.  Cookie 和 Session 的区别

1. Cookie 是客户端的机制, Session 是服务器的机制.

2. Cookie 和 Session 常常会在一起搭配使用, 但是不是必须要搭配.

3.完全可以用 Cookie 来保存一些数据在客户端. 这些数据不一定是用户身份信息, 也不一定是

token / sessionId ; Session 中的 token / sessionId 也不需要非得通过 Cookie / Set-Cookie 传递 .

3. Servlet 对于 Cookie 和 Session 提供的 API

HttpServletRequest 类中的相关方法
方法
描述
HttpSession getSession()
在服务器中获取会话 . 参数如果为 true, 则当不存在会话时新建会话 ; 参数如果
false, 则当不存在会话时返回 null
Cookie[] getCookies()
返回一个数组 , 包含客户端发送该请求的所有的 Cookie 对象 . 会自动把
Cookie 中的格式解析成键值对 .
HttpServletResponse 类中的相关方法
方法
描述
void addCookie(Cookie cookie) 把指定的 cookie 添加到响应中.
HttpSession 类中的相关方法
一个 HttpSession 对象里面包含多个键值对 . 我们可以往 HttpSession 中存任何我们需要的信息 .
方法
描述
Object getAttribute(String name)
该方法返回在该 session 会话中具有指定名称的对象,如果没
有指定名称的对象,则返回 null.
void setAttribute(String name, Object value)
该方法使用指定的名称绑定一个对象到该 session 会话
boolean isNew() 判定当前是否是新创建出的会话
Cookie 类中的相关方法
每个 Cookie 对象就是一个键值对 .
方法
描述
Object getAttribute(String name)
该方法返回在该 session 会话中具有指定名称的对象,如果没有指定名称的对象,则返回 null.
void setAttribute(String name, Object  value)
该方法使用指定的名称绑定一个对象到该 session 会话
boolean isNew() 判定当前是否是新创建出的会话
Cookie 类中的相关方法
每个 Cookie 对象就是一个键值对 .
方法
描述
String getName()
该方法返回 cookie 的名称。名称在创建后不能改变。 ( 这个值是 Set-
Cooke 字段设置给浏览器的 )
String getValue() 该方法获取与 cookie 关联的值
void setValue(String newValue)
该方法设置与 cookie 关联的值。
1. HTTP Cooke 字段中存储的实际上是多组键值对 . 每个键值对在 Servlet 中都对应了一个 Cookie 对象.
2. 通过 HttpServletRequest.getCookies() 获取到请求中的一系列 Cookie 键值对 .
3. 通过 HttpServletResponse.addCookie() 可以向响应中添加新的 Cookie 键值对 .

4. 实现用户登录

此处的用户登录就简单原则实现,主要是理解 Cookie 和 Session 的机制.

1. 有一个主页 : 使用 Servlet 动态生成

2. 有一个登录页 : 静态页面

登录页这里可以输入用户名和密码, 服务器这边验证正确性, 如果用户名和密码都正确就跳转到主页, 并 在主页显示当前用户的身份信息和当前用户的登录后的访问次数. (登录成功后就不必在登陆了)

客户端代码:

服务器代码:

验证用户名密码的 Servlet

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf8");
        // 读取请求中的参数, 判定当前用户的身份信息是否正确.
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if(username == null || username.equals("") || password == null || password.equals("")) {
            resp.getWriter().write("用户名或密码不完整! 登陆失败!");
            return;
        }
        // 验证用户名密码是否正确
        if(!username.equals("zhangsan") || !password.equals("123")) {
            resp.getWriter().write("用户名或密码错误! 登陆失败!");
            return;
        }
        // 登陆成功, 创建一个 会话 (session), 把用户信息, 填写到 session 中
        // 下次访问, 就可以直接从哈希表中查询出来
        HttpSession session = req.getSession(true);
        session.setAttribute("username", "zhangsan");
        // 先取出来判断, 为 null 登陆次数才设为 0
        Integer visitCount = (Integer) session.getAttribute("visitCount");
        if(visitCount == null) {
            // 登录次数初始为 0
            session.setAttribute("visitCount", 0);
        } else{
            // 不做任何处理
        }
        // 让页面跳转到登录页面,这里的重定向跳转, 是 GET 请求
        resp.sendRedirect("index");
    }
}

主页 Servlet

@WebServlet("/index")
public class IndexServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 要做的工作, 就是把当前的用户信息, 给展示到页面上
        HttpSession session = req.getSession(false);
        if(session == null) {
            // 用户未登录, 则跳转到登录页面, 要求用户重新登陆
            resp.sendRedirect("login.html");
            return;
        }
        // 已经登陆成功, 就获取到 会话 中的数据
        // 由于 getAttribute 返回的是 Object, 所以需要强转
        String username  = (String) session.getAttribute("username");
        Integer visitCount = (Integer) session.getAttribute("visitCount");
        visitCount = visitCount + 1;
        session.setAttribute("visitCount", visitCount);
        // 显示用户和访问次数
        resp.setContentType("text/html;charset=utf8");
        resp.getWriter().write("当前用户为: " + username + " 访问次数: " + visitCount);
    }
}

4.1 理解 req.getSession() 

下图是用户登录一次后,后续访问服务器的操作, 只要服务器不重启, session 的哈希表就会一直存在.

理解 Cookie,Session 机制 && 实现用户登录_第1张图片

 如果是未登录状态,输入用户名和密码后, 则是创建一个新的 session 对象, 然后存储用户的身份信息.

4.2 理解上述代码客户端和服务器交互过程

结合 fiddler 抓包进行理解:

第一次请求: 获取到 login.html 页面

初始情况下请求中没有 Cookie,响应中也没有 Set-Cookie

请求报文

理解 Cookie,Session 机制 && 实现用户登录_第2张图片

 第二次请求: 输入用户名密码, 点击登录

此次请求中也没有 Cookie ,但是响应报文中会带有 Set-Cookie. Set-Cookie 中 key 的名字叫做 JSESSIONID (Servlet 自动生成的), value 就是一串很长的十六进制数字, 是由服务器生成的 sessionId.

响应报文

理解 Cookie,Session 机制 && 实现用户登录_第3张图片

 第三次请求: 登录成功之后, 自动重定向访问主页

此时请求中带有 Cookie, 这个 Cookie就是上次 Set-Cookie 中的内容,  只要不重启服务器, 后续再反复请求, 请求中就都会带有这个 Cookie 了.

理解 Cookie,Session 机制 && 实现用户登录_第4张图片


你可能感兴趣的:(JavaEE初阶,1024程序员节,servlet,java)