🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
>[warning] 通过与一些做测试的朋友交流,发现有一些工作了好几年的朋友,都并不了解Session与Cookie,这里,我用两个例子来给朋友们好好分析分析! > [TOC] ## Session和Cookie相关概念 * Session和Cookie**都是由服务器生成的**。 * Session和Cookie**都是键值对**形式保存,主要用于存储特定的一些状态值。 * **Session保存在服务器**,**Cookie保存在客户端**。通常来说,Session的ID会以Cookie的形式返回给客户端的。 * Session和Cookie都是有**生命周期**的。Cookie的生命周期受到Cookie自身的有效期和客户端的影响,一般来说,浏览器(客户端)是会自动将存活的Cookie封装在请求头里面,向服务器发送。如果Cookie有效期过期或客户端清理了Cookie,则发送的请求中就没有Cookie值;Session的生命周期受到Session自身的有效期和客户端是否关闭的影响。SessionID虽然是已Cookie的形式返回给客户端,但是它是不受客户的Cookie容器的管理,而是和客户端进程有关,即客户端进程不关闭,一般Session在客户端就不会失效。 * Session和Cookie都是有**作用域**的。 <br> >[info]下面我会自己写一个例子来演示 看不懂相关代码的,可以留意一下我关于django方面的教程 ## 实例演示:以Cookie记录用户状态 **创建一个登陆与欢迎页面 `login.html`页面逻辑如下:** ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录Session与Cookie</title> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body> <div class="container"> {% if username %} <h2>欢迎您 :{{ username }}</h2> <a href="/logout/">注销</a> {% else %} <form action="/login_cookie/" method="post"> {% csrf_token %} <div class="form-group"> <label class="sr-only">username</label> <input type="text" class="form-control" name="username" placeholder="用户名"/> </div> <div class="form-group"> <label class="sr-only">Password</label> <input type="password" class="form-control" name="passwd" placeholder="密码"/> </div> <div class="form-group"> <input class="btn btn-primary" type="submit" value="Submit"> </div> </form> {% endif %} </div> <script type="application/javascript" src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script> <script type="application/javascript" src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> </body> </html> ``` **代码解释:** 如果用户已登录,则显示“欢迎您,xx”,并且提供注销按钮; 如果用户未登录,则显示一个登录窗口,让用户输入用户名与密码。 **服务端`login/views.py`代码逻辑如下:** ```python from django.shortcuts import render # Create your views here. def login_cookie(request): # 从Cookie中获取用户名 username = request.COOKIES.get("username", False) response = render(request, 'login.html', locals()) # 如果POST表单,进行登录验证 if request.method == "POST": username = request.POST['username'] pwd = request.POST['passwd'] if username == 'ptqa' and pwd == '4399': response = render(request, 'login.html', locals()) # 设置Cookie response.set_cookie("username", username) return response ``` **代码解释:** 如果是POST方式访问,从提交过来的数据中验证用户是否登录成功,登录成功便`将用户名设置到cookie`,并且返回给客户端,进入欢迎页。 如果是GET方式访问,则`从访问的cookie中获取用户信息`,如果从cookie中能获取到用户名,则认为用户已登录,返回欢迎页。 **step1:** 首次访问http://127.0.0.1:8000/login_cookie/ 可以观察到 Request headers 中没有Cookie,页面处于未登录状态 ![](https://box.kancloud.cn/0fac9b117b8fb30f00a3273c5f075e68_979x547.jpg) **step2:** 登录后(输入账号名ptqa,密码4399)自动跳转首页,此时可以观察到,在Response Headers 中存在Set-Cookie:username=ptqa; Path=/ ![](https://box.kancloud.cn/25cc6c0fd695c27ed3cfc7095e012b17_991x606.jpg) 从这里,我们也可以看见,cookie是在服务端设置的。这时候,客户端接收到服务端设置的cookie后,会保存在浏览器的cookie管理器中,下一次再请求时会自动带上这些cookie,服务端便会知道当前的用户是已经通过了登录校验的用户。如此这般,便能维持了会话的状态了。 **step3:** 此时,刷新页面或新开窗口访问http://127.0.0.1:8000/login_cookie/ 可观察到请求中的Request Headers 中自动带上 Cookie:username=ptqa; 页面处于已登录状态。 ![](https://box.kancloud.cn/58bee489e9e1187cdb2bdce139382ffa_979x554.jpg) **使用JMeter篡改Cookie** 显然,通过cookie的方式验证用户登录容易被破解,如下使用jmeter篡改Cookie值,则同样可以进入已登录状态显示界面,如下 ![](https://box.kancloud.cn/3a075f61a4acd614f93ca6ba8cecbdb7_987x213.jpg) 发送请求后,可以看到,用户已经登录了。 ![](https://box.kancloud.cn/478c0d46e4e59391e7087d9e3605e621_984x466.jpg) ## 实例演示:以Session记录用户状态 **前端登录与欢迎页 `login.html `逻辑如下:** ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录Session与Cookie</title> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body> <div class="container"> {% if username %} <h2>欢迎您 :{{ username }}</h2> <a href="/logout/">注销</a> {% else %} <form action="/login_session/" method="post"> {% csrf_token %} <div class="form-group"> <label class="sr-only">username</label> <input type="text" class="form-control" name="username" placeholder="用户名"/> </div> <div class="form-group"> <label class="sr-only">Password</label> <input type="password" class="form-control" name="passwd" placeholder="密码"/> </div> <div class="form-group"> <input class="btn btn-primary" type="submit" value="Submit"> </div> </form> {% endif %} </div> <script type="application/javascript" src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script> <script type="application/javascript" src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> </body> </html> ``` **代码解释:** 如果用户已登录,则显示“欢迎您,xx”,并且提供注销按钮; 如果用户未登录,则显示一个登录窗口,让用户输入用户名与密码。 **服务端`login/views.py`的处理逻辑如下:** ```python from django.shortcuts import render, redirect # Create your views here. def login_session(request): # 从Session中获取用户名 username = request.session.get('username', False) # 如果POST表单,进行登录验证 if request.method == "POST": username = request.POST['username'] pwd = request.POST['passwd'] if username == 'ptqa' and pwd == '4399': # 设置Session request.session['username'] = username # request.session.set_expiry(300) #会让 Session 在五分钟后过期 # 登录不成功或第一访问就停留在登录页面 return render(request, 'login.html', locals()) def logout(request): if "username" in request.session: del request.session['username'] return redirect("/login_session/") ``` **代码解释:** 如果是POST方式访问,从提交过来的数据中验证用户是否登录成功,登录成功便`将用户名设置到Session中`,并且返回给客户端,进入欢迎页。 如果是GET方式访问,则`从访问的Session中获取用户信息`,如果从Session中能获取到用户名,则认为用户已登录,返回欢迎页。 **step1:** 首次访问http://127.0.0.1:8000/login_session/ 可观察到Request Headers 中并没有sessionId 并且处于未登录状态 ![](https://box.kancloud.cn/badd15de3df051830c2612140c9c2766_963x512.jpg) **step2:** 登录,输入账号ptqa,密码4399 ,在Response Headers 中可以观察到存在 Set-Cookie:sessionid=qigvbt2ckkcc5rydr46dehzjryg0mh41; ![](https://box.kancloud.cn/ebdae352b3ac5dbf5efdf5cd9de2cd6f_964x529.jpg) **step3:** 重新刷新页面或新开窗口,则观察到在Request Headers 中带有Cookie Sessionid,并且处于登录状态。 ![](https://box.kancloud.cn/edacb879f6ad69ab0f1a54b3ba38d77c_996x467.jpg) **使用JMeter篡改Cookie** 显然,这种使用sessonid的方式比较安全,如果篡改sessionid,则无法进行登录。如下: ![](https://box.kancloud.cn/62b2715c63bde66e2717d9e3036c944d_977x167.jpg) 发送请求后,sessionid在服务端验证并不存在,所以依然是未登录的状态。 ![](https://box.kancloud.cn/83101e3a1bfd4be4d2d2c0dab8ed8972_988x393.jpg) <hr style="margin-top:100px"> :-: ![](https://box.kancloud.cn/331f659e8e6cddb0d9f182e00e32803f_258x258.jpg) ***微信扫一扫,关注“python测试开发圈”,获取更多测试开发分享!***