网站源码在哪里,厦门公司注册程序注册程序,家具设计师招聘,定边网站建设一、Cookie
1.1 定义
HTTP Cookie#xff08;也称为 Web Cookie、浏览器 Cookie 或简称 Cookie#xff09;是服务器发送到 用户浏览器并保存在浏览器上的一小块数据#xff0c;它会在浏览器之后向同一服务器再次发 起请求时被携带并发送到服务器上。通常#xff0c;它用于…一、Cookie
1.1 定义
HTTP Cookie也称为 Web Cookie、浏览器 Cookie 或简称 Cookie是服务器发送到 用户浏览器并保存在浏览器上的一小块数据它会在浏览器之后向同一服务器再次发 起请求时被携带并发送到服务器上。通常它用于告知服务端两个请求是否来自同一浏览器如保持用户的登录状态、记录用户偏好等。
1.2 工作原理
当用户第一次访问网站时服务器会在响应的 HTTP 头中设置 Set-Cookie 字段用于发送 Cookie 到用户的浏览器。浏览器在接收到 Cookie 后会将其保存在本地通常是按照域名进行存储。在之后的请求中浏览器会自动在 HTTP 请求头中携带 Cookie 字段将之前保存的 Cookie 信息发送给服务器。
Cookie一般分为两种一个是内存级的Cookie只要关闭浏览器Cookie就会自动销毁另一个是文件级的Cookie即关闭浏览器Cookie仍然有效
会话 CookieSession Cookie在浏览器关闭时失效。持久 CookiePersistent Cookie带有明确的过期日期或持续时间 可以跨多个浏览器会话存在。如果 cookie 是一个持久性的 cookie那么它其实就是浏览器相关的特 定目录下的一个文件。但直接查看这些文件可能会看到乱码或无法读取的内容 因为 cookie 文件通常以二进制或 sqlite 格式存储。一般我们查看直接在浏览器对应的选项中直接查看即可。
1.3 认识Cookie
HTTP 存在一个报头选项Set-Cookie, 可以用来进行给浏览器设置 Cookie 值。在 HTTP 响应头中添加客户端如浏览器获取并自行设置并保存 Cookie。
1.3.1基本格式
//简单示例
Set-Cookie: namevalue
其中 name 是 Cookie 的名称value 是 Cookie 的值。//完整示例
Set-Cookie: usernamepeter; expiresThu, 18 Dec 2024 12:00:00
UTC; path/; domain.example.com; secure; HttpOnly
时间格式必须遵守 RFC 1123 标准具体格式样例
Tue, 01 Jan 2030 12:34:56 GMT 或者 UTC(推荐) GMT和UTC的区别 1. 计算方式GMT 基于地球的自转和公转而 UTC 基于原子钟。 2. 准确度由于 UTC 基于原子钟它比基于地球自转的 GMT 更加精确。 在实际使用中GMT 和 UTC 之间的差别通常很小大多数情况下可以互换使用。但 在需要高精度时间计量的场合如科学研究、网络通信等UTC 是更为准确的选择。 关于其他可选属性的解释
expires[要验证]设置 Cookie 的过期日期/时间。如果未指定此属 性则 Cookie 默认为会话 Cookie即当浏览器关闭时过期。path[要验证]限制 Cookie 发送到服务器的哪些路径。默认 为设置它的路径。domain[了解即可]指定哪些主机可以接受该 Cookie。默 认为设置它的主机。secure[了解即可]仅当使用 HTTPS 协议时才发送 Cookie。这有助于防止 Cookie 在不安全的 HTTP 连接中被截获。HttpOnly[了解即可]标记 Cookie 为 HttpOnly意味着该 Cookie 不能被客户端脚本如 JavaScript访问。这有助于防止跨站脚本攻击XSS。
注意事项
每个 Cookie 属性都以分号;和空格 分隔。名称和值之间使用等号分隔。如果 Cookie 的名称或值包含特殊字符如空格、分号、逗号等则需要 进行 URL 编码。如果设置了 expires 属性则 Cookie 将在指定的日期/时间后过期。如果没有设置 expires 属性则 Cookie 默认为会话 Cookie即当浏览器关闭时过期。
1.3.2 测试浏览器自动写入Cookie
当我们第一次使用浏览器访问服务器时浏览器会将Cookie信息自动保存起来当我们再次访问浏览器会将保存的Cookie信息添加到请求报头中返回给服务器服务器接收到请求后会解析HTTP请求头中的cookie字段根据Cookie中的信息如用户ID、会话ID等服务器可以识别出用户的身份和状态从而提供相应的服务。
class HttpServer
{
public:std::string GetWeekDayName(int day){std::vectorstd::string Week {Sun, Mon, Tue, Wed, Thu, Fri, Sat};return Week[day];}std::string GetMonthName(int month){std::vectorstd::string Months {Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};return Months[month];}std::string ExpireTimeUseRfc1123(int t){time_t timeout time(nullptr) t; // 获取未来t秒的时间戳struct tm *tm gmtime(timeout);char timebuffer[1024];// 时间格式如: expiresThu, 18 Dec 2024 12:00:00 UTCsnprintf(timebuffer, sizeof(timebuffer), %s, %02d %s %d %02d:%02d:%02d UTC,GetWeekDayName(tm-tm_wday).c_str(),tm-tm_mday,GetMonthName(tm-tm_mon).c_str(),tm-tm_year1900,tm-tm_hour,tm-tm_min,tm-tm_sec);return timebuffer;}std::string HandlerHttpRequest(std::string reqstr){std::cout --------------------------------------- std::endl;std::cout reqstr;std::cout --------------------------------------- std::endl;HttpRequest req;req.DeSerialize(reqstr);HttpResponse resp;resp.AddCode(200, _code_to_desc[200]);//测试Cookie自动被写入resp.AddHeader(Set-Cookie,usernamezhangsan;);resp.AddBodyText(htmlh1helloworld/h1/html);std::string respstr resp.Serialize();return respstr;}private:std::unordered_mapstd::string, std::string _mine_type;std::unordered_mapint, std::string _code_to_desc;std::unordered_mapstd::string, func_t _service_list;
}; 1.3.3 测试写入Cookie过期时间 std::string HandlerHttpRequest(std::string reqstr){std::cout --------------------------------------- std::endl;std::cout reqstr;std::cout --------------------------------------- std::endl;HttpRequest req;req.DeSerialize(reqstr);HttpResponse resp;resp.AddCode(200, _code_to_desc[200]);// 测试写入Cookie过期时间//设置Cookie在30秒后过期resp.AddHeader(Set-Cookie, usernamezhangsan; expiresExpireTimeUseRfc1123(30);); resp.AddBodyText(htmlh1helloworld/h1/html);std::string respstr resp.Serialize();return respstr;} 1.3.4 测试路径path
我们将Cookie的可用路径设置为 /a/b ,则当浏览器第一次访问服务器时浏览器会自动保存Cookie在之后的访问中只有我们访问的路径设置为/a/b,浏览器才会将Cookie信息返回给服务器 std::string HandlerHttpRequest(std::string reqstr){std::cout --------------------------------------- std::endl;std::cout reqstr;std::cout --------------------------------------- std::endl;HttpRequest req;req.DeSerialize(reqstr);HttpResponse resp;resp.AddCode(200, _code_to_desc[200]);//测试路径pathresp.AddHeader(Set-Cookie,usernamezhangsan; path/a/b);resp.AddBodyText(htmlh1helloworld/h1/html);std::string respstr resp.Serialize();return respstr;} 单独使用Cookie的安全问题 现在浏览器保存的是我们的测试数据如果写入的数据是用户的私密数据例如用户名密码的等由于Cookie是保存在客户端的那这些数据就有可能被别人非法获取造成用户的私密信息泄露那如何才能解决这个问题呢于是就引入了Session
二、Session
2.1 定义
HTTP Session 是服务器用来跟踪用户与服务器交互期间用户状态的机制。由于 HTTP 协议是无状态的每个请求都是独立的因此服务器需要通过 Session 来记住用户的信息。
2.2 工作原理
1. 当用户首次访问网站时服务器会为用户创建一个唯一的 Session ID并通过 Cookie 将其发送到客户端。
2. 客户端在之后的请求中会携带这个 Session ID服务器通过 Session ID 来识 别用户从而获取用户的会话信息。
3. 服务器通常会将 Session 信息存储在内存、数据库或缓存中。
2.3 安全性
单独使用cookie不安全的原因是将用户的隐私信息直接保存在了客户端容易被盗取与 Cookie 相似由于 Session ID 是在客户端和服务器之间传递的因此也存在被窃取的风险。 但是一般虽然 Cookie 被盗取了但是用户只泄漏了一个 Session ID私密信息暂时没有被泄露的风险 Session ID 便于服务端进行客户端有效性的管理比如异地登录。 可以通过 HTTPS 和设置合适的 Cookie 属性如 HttpOnly 和 Secure来增强安全性
2.4 用途
用户认证和会话管理存储用户的临时数据如购物车内容实现分布式系统的会话共享通过将会话数据存储在共享数据库或缓存中
2.5 模拟Session行为
session.hpp
Session对象用来保存用户的基本信息SessionManager类维护了当前所有的session对象可以通过sessionid来索引session对象
#pragma once
#include string
#include time.h
#include stdlib.h
#include sys/types.h
#include unistd.h
#include memory
#include unordered_map
#include Log.hppclass Session
{
public:Session(const std::string username, const std::string passward): _username(username), _passward(passward){_create_time time(nullptr); // 获取时间戳就行了后面实际需要就转化就转换一下}std::string Username(){return _username;}private:// 用户的信息std::string _username;std::string _passward;std::string _create_time;// 还可以定义其他的用户信息例如浏览记录等等
};using session_ptr std::shared_ptrSession;
class SessionManager
{
public:SessionManager(){srand(time(nullptr));}~SessionManager(){}std::string AddSession(session_ptr s){uint32_t randomid rand() time(nullptr); // 随机数时间戳实际有形成sessionid的库比如boost uuid库或者其他第三方库等std::string sessionid std::to_string(randomid);_sessions.insert(std::make_pair(sessionid, s));return sessionid;}session_ptr GetSession(std::string sessionid){if (_sessions.find(sessionid) _sessions.end())return nullptr;elsereturn _sessions[sessionid];}private:std::unordered_mapstd::string, session_ptr _sessions; // sessionid索引session对象
}; 如果检测到sessionid是空的话说明这个用户是第一次访问服务器通过登录的信息生成一个session对象并将其插入到sessionmanager中维护起来获取一个sessionid通过cookie的方式发送给客户端
当该用户后再次访问时通过它的sessionid就可以识别他的身份进行业务处理假设别人在另一台设备上登陆了该用户的账号那就可以结合具体业务例如跟据用户的使用偏好、是否异地登录等等检测是否为非法登录若是我们在进行人脸识别登验证不通过则直接在后台删除它的sessionid让其失效即可 std::string HandlerHttpRequest(std::string reqstr){std::cout --------------------------------------- std::endl;std::cout reqstr;std::cout --------------------------------------- std::endl;HttpRequest req;req.DeSerialize(reqstr);HttpResponse resp;static int number 0;if (req.Url() /login) // 模拟登录{std::string sessionid req.Sessionid();if (sessionid.empty()) // 说明客户端第一次访问服务器,那就给客户端形成一个sessionid发送给他{std::string user user- std::to_string(number);session_ptr s std::make_sharedSession(user, 123456);sessionid _session_manager-AddSession(s);LOG(DEBUG, %s 被添加, sessionid是: %s\n, user.c_str(), sessionid.c_str());resp.AddHeader(Set-Cookie, sessionid sessionid);}}else{std::string sessionid req.Sessionid();if (!sessionid.empty()){session_ptr s _session_manager-GetSession(sessionid);// 这个地方有坑一定要判断服务器端session对象是否存在因为可能测试的时候// 浏览器还有历史sessionid但是服务器重启之后session对象没有了.if (s ! nullptr){LOG(DEBUG, %s 正在活跃.\n, s-Username().c_str());}else{LOG(DEBUG, cookie : %s 已经过期, 需要清理\n, sessionid.c_str());}}}resp.AddCode(200, _code_to_desc[200]);resp.AddBodyText(htmlh1helloworld/h1/html);std::string respstr resp.Serialize();return respstr;}