cookie&session&模拟登陆

cookie

cookie是什么?
cookie是浏览器提供的持久化存储数据的机制

cookie从哪里来?
cookie是从服务器返回给浏览器的,
服务器代码中由程序员决定把啥样的信息保存到客户端这边,通过HTTP响应的Set-cookie 字段,把键值对写回去即可。

cookie到哪里去?
cookie会在后续浏览器访问服务器时带到请求的header中,发给服务器。
为什么要这样?因为服务器不只给一个客户端提供服务,在同一时刻,要处理多个客户端,此时服务器就可以通过cookie中的值,来识别当前客户端是谁,当前客户端的服务提供的什么等(客户端通过cookie让服务器知道他是谁)

cookie存储在哪里?
cookie存储在浏览器(客户端)所在的主机的硬盘中。浏览器会根据域名来分别存储。

例子

cookie的用途非常的广泛,最典型的应用是:标识用户身份信息

例如:网站有登录的功能
要想登录网站,浏览器首先向服务器发送请求,获取网站主页
然后服务器返回网站主页,此时服务器并不知道用户的身份信息。
接着浏览器发送登录请求,针对客户端发送的登录请求,服务器会查询数据库,验证用户信息是否正确,如果正确,则登录成功,【这时网站会把当前用户的身份信息在内存中也保存一份,同时给这个用户分配一个表示身份的身份序号(唯一的)这里的身份序号称为sessionId,服务器使用hash表的结构,将身份序号作为key,身份信息作为value,存储起来。服务器把这些生成的键值对称为session(会话)。】
信息正确,服务器返回登录成功,并返回身份序号,这时浏览器就把身份序号保存在浏览器的cookie中了。
在浏览器的后续请求中,服务器收到cookie中的身份序号,就会查询hash表,判断该用户是谁,如果查到了,就继续执行用户输入的操作,避免重复多次的输入账号密码。如果没有查到,就要求用户重新登录。

服务器把生成的这些键值对称为session(会话),把生成的唯一身份序号称为sessionId

cookie和session之间的关联和区别:

关联:在网站的登录功能中,需要配合使用
区别:

  1. cookie是客户端的存储机制,session是服务器的存储机制
  2. cookie里可以存各种键值对(还可以存别的),session是专门用来保存用户身份信息的。
  3. cookie可以单独使用,不搭配session(实现非登录场景)
  4. session也可以不搭配cookie使用(手机app登录服务器,服务器也需要session,此时就没有cookie的概念)cookie是和浏览器强相关的。
  5. cookie属于HTTP协议中的一个部分,session可以和HTTP无关(TCP,websocket也可以用session)
  6. 一个域名可以有多个cookie,但是只能有一个sessionId(cookie不仅仅可以用来存储身份信息)

模拟登录代码

在这里涉及两个页面

  1. 登录页面login.html
  2. 主页面index.html
    在登录页面点击按钮触发登录请求,Loginservlet在后端验证用户名密码是否正确,如果登录成功,跳转到新的页面index.html,在这个页面中显示用户名字,通过servlet动态构建Indexservlet

涉及两个servlet
3. 处理登录的Loginservlet,判定用户名密码。
4. 构造主页面的Indexservlet

前端代码

login

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>登录</title>
</head>
<body>
    <form action="login" method="post">
        <input type="text" name="username">
        <br>
        <input type="password" name="password">
        <br>
        <input type="submit" value="提交">
    </form>
    
</body>
</html>

抓包检查
在这里插入图片描述

POST http://127.0.0.1:8080/hello_servlet2/login HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Content-Length: 25
Cache-Control: max-age=0
sec-ch-ua: “Google Chrome”;v=“111”, “Not(A:Brand”;v=“8”, “Chromium”;v=“111”
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: “Windows”
Upgrade-Insecure-Requests: 1
Origin: http://127.0.0.1:8080
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://127.0.0.1:8080/hello_servlet2/login.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
/
username=123&password=qwe

后端代码

login

每个会话,是一个键值对,对应到一个客户端。服务器这里可以对应多个客户端,就有多组会话。
在每个会话对象HttpSession 里,还可以存储一些程序员自己定义的数据,也是以键值对的形式组织的

keyvalue
sessionId 123456HttpSession key: “username” value :“zhangsan” key :“age” value :10
sessionId asdfghjkHttpSession key :“username” value :“zhangsan” key: “age” value: 10
sessionId 3456789HttpSession key :“username” value: “wangyu”
  1. 创建会话
HttpSession session = req.getSession(true);

所谓的会话,是一个键值对,key是sessionId,value是HTTPSession对象
每个会话,是一个键值对,对应到一个客户端
每个会话对象里,可以存储一些程序员自定义的数据。
每个客户端登录的时候都有一个这样的键值对(会话),服务器要管理多个这样的会话
服务器可以搞一个哈希表,把这些会话组织起来。

getSession(true) :判定当前请求是否已经有对应的会话了
(拿着请求中的cookie里的sessionId查一下哈希表,没查到创建新会话,插入到哈希表;查到了直接返回查到的结果)
getSession(false):没查到不创建新会话,返回null;查到了直接返回
true 和 false :是否可以创建新的会话。

getSession(true)没查到,创建新会话过程:

  1. 构造一个httpSession对象

  2. 构造唯一的sessionId

  3. 把这个键值对插入哈希表

  4. 把sessionId 设置到响应报文Set-Cookie字段中
    注意:httpSession对象自己也是一个键值对,使用getAttribute setAttribute来存取键值对
    这里的键值对完全是程序员自定义的数据

  5. 把当前的用户名保存到会话中,此处的 HttpSession 对象自己也是一个键值对结构。

session.setAttribute("username", username);
session.setAttribute("password", passwd);
  1. 重定向到主页
resp.sendRedirect("index");
@WebServlet("/login")
public class loginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String passwd = req.getParameter("password");

        //验证用户名密码是否正确,正常情况下,用户名密码用数据库保存,此处直接写死,代码进行判定
        //此处约定用户名 root  admin  密码123
        if (!username.equals("root") && !username.equals("admin")) {
            // 登录失败
            // 重定向到登录页面
            System.out.println("登录失败,用户名错误");
            resp.sendRedirect("login.html");
            return;
        }
        if (!passwd.equals("123")) {
            // 登录失败
            System.out.println("登录失败,密码错误");
            resp.sendRedirect("login.html");
            return;
        }
        // 登录成功
        System.out.println("登录成功");
        //1. 创建会话
        HttpSession session = req.getSession(true);

        //2. 把当前的用户名保存到会话中,此处的 HttpSession 对象自己也是一个键值对结构。
        session.setAttribute("username", username);
        session.setAttribute("password", passwd);
        //3. 重定向到主页
        resp.sendRedirect("index");

    }
}

index

通过重定向,浏览器发起的是GET请求

在login Servlet中重定向是index

resp.sendRedirect("index");

在indexServlet中就需要和上述重定向的页面标注一致

@WebServlet("/index")
@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) {
            System.out.println("用户未登录");
            resp.sendRedirect("login.html");
            return;
        }

        //用户登录了
        //此处可以这样取,前提是前面的登录操作中存了。
        //HttpSession value的值是Object,需要手动强转成String(设定Object就是可以转换成各种理想)
        String username = (String) session.getAttribute("username");
//        String passwd = (String) session.getAttribute("password");
        resp.setContentType("text/html; charset=utf8");
        resp.getWriter().write("welcome~ " + username + " come back");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值