[{"data":1,"prerenderedAt":1109},["ShallowReactive",2],{"navigation_docs":3,"-web-dev-security-cookie-session-authentication":352,"-web-dev-security-cookie-session-authentication-surround":1104},[4,54,83,116,125,161,179,200],{"title":5,"path":6,"stem":7,"children":8},"Ai","/ai","ai",[9,12,42,46,50],{"title":10,"path":6,"stem":11},"AI 技術探索","ai/index",{"title":13,"path":14,"stem":15,"children":16,"page":41},"Rag","/ai/rag","ai/RAG",[17,21,25,29,33,37],{"title":18,"path":19,"stem":20},"BM25 演算法深入解析：從 TF-IDF 到現代搜尋引擎的核心技術","/ai/rag/bm25-deep-dive-from-tf-idf-to-rag","ai/RAG/bm25-deep-dive-from-tf-idf-to-rag",{"title":22,"path":23,"stem":24},"Dense Retrieval（向量檢索）深入解析","/ai/rag/dense-retrieval-deep-dive","ai/RAG/dense-retrieval-deep-dive",{"title":26,"path":27,"stem":28},"RAG（Retrieval-Augmented Generation）原理與實作入門","/ai/rag/rag-intro-principles-and-implementation","ai/RAG/rag-intro-principles-and-implementation",{"title":30,"path":31,"stem":32},"RAG Retrieval Strategy 深入解析","/ai/rag/rag-retrieval-strategy-deep-dive","ai/RAG/rag-retrieval-strategy-deep-dive",{"title":34,"path":35,"stem":36},"Reciprocal Rank Fusion（RRF）教學：打造更穩定的檢索融合策略","/ai/rag/rrf-reciprocal-rank-fusion-guide","ai/RAG/rrf-reciprocal-rank-fusion-guide",{"title":38,"path":39,"stem":40},"TF-IDF（Term Frequency–Inverse Document Frequency）深入解析","/ai/rag/tf-idf-deep-dive","ai/RAG/tf-idf-deep-dive",false,{"title":43,"path":44,"stem":45},"Docus AI 功能完整實作指南","/ai/docus-ai-implementation","ai/docus-ai-implementation",{"title":47,"path":48,"stem":49},"llms.txt 是什麼？在 Nuxt 中控制 AI 與搜尋引擎爬蟲的新方式","/ai/llms-txt","ai/llms-txt",{"title":51,"path":52,"stem":53},"MCP（Model Context Protocol）是什麼？用「AI 的 USB-C」理解模型如何安全連接工具與資料","/ai/mcp_concept","ai/mcp_concept",{"title":55,"path":56,"stem":57,"children":58,"page":41},"Data Analysis","/data-analysis","data-analysis",[59,63,67,71,75,79],{"title":60,"path":61,"stem":62},"Exploratory Data Analysis（EDA）資料探索分析入門","/data-analysis/exploratory-data-analysis-eda","data-analysis/exploratory-data-analysis-eda",{"title":64,"path":65,"stem":66},"PR-AUC 深入解析：不平衡分類問題的重要評估指標","/data-analysis/pr-auc-for-imbalanced-classification","data-analysis/pr-auc-for-imbalanced-classification",{"title":68,"path":69,"stem":70},"ROC-AUC 深入解析：理解分類模型的判斷能力","/data-analysis/roc-auc-complete-guide","data-analysis/roc-auc-complete-guide",{"title":72,"path":73,"stem":74},"SHAP（SHapley Additive exPlanations）模型解釋方法深入解析","/data-analysis/shap-model-interpretation-complete-guide","data-analysis/shap-model-interpretation-complete-guide",{"title":76,"path":77,"stem":78},"Social Network Analysis（SNA）深入解析","/data-analysis/social-network-analysis-sna","data-analysis/social-network-analysis-sna",{"title":80,"path":81,"stem":82},"Time-based Split：為什麼時間序列資料不能使用 Random Split？","/data-analysis/time-based-split-vs-random-split","data-analysis/time-based-split-vs-random-split",{"title":84,"path":85,"stem":86,"children":87,"page":41},"MachineLearning","/machine_learning","machine_learning",[88,92,96,100,104,108,112],{"title":89,"path":90,"stem":91},"Confusion Matrix（混淆矩陣）完整解析","/machine_learning/confusion-matrix","machine_learning/confusion-matrix",{"title":93,"path":94,"stem":95},"Decision Tree 模型完整教學：從原理到 Python 實作","/machine_learning/decision-tree-complete-guide","machine_learning/decision-tree-complete-guide",{"title":97,"path":98,"stem":99},"為什麼 Decision Tree 在 Tabular Data 上常常勝過 Deep Learning？","/machine_learning/decision-tree-vs-deep-learning-on-tabular-data","machine_learning/decision-tree-vs-deep-learning-on-tabular-data",{"title":101,"path":102,"stem":103},"LightGBM 模型入門：理解高效能的 Gradient Boosting 演算法","/machine_learning/lightgbm-intro-for-tabular-data","machine_learning/lightgbm-intro-for-tabular-data",{"title":105,"path":106,"stem":107},"Logistic Regression（Logit 回歸）完整教學","/machine_learning/logistic-regression-complete-guide","machine_learning/logistic-regression-complete-guide",{"title":109,"path":110,"stem":111},"為什麼模型訓練需要 Train / Validation / Test Dataset？","/machine_learning/train-validation-test-dataset","machine_learning/train-validation-test-dataset",{"title":113,"path":114,"stem":115},"XGBoost 原理與實務教學","/machine_learning/xgboost-complete-guide","machine_learning/xgboost-complete-guide",{"title":117,"path":118,"stem":119,"children":120,"page":41},"Network","/network","network",[121],{"title":122,"path":123,"stem":124},"DNS 設定入門：CNAME vs A Record 完整解析","/network/dns-cname-vs-a-record-guide","network/dns-cname-vs-a-record-guide",{"title":126,"path":127,"stem":128,"children":129},"Nuxt","/nuxt","nuxt",[130,133,137,141,145,149,153,157],{"title":131,"path":127,"stem":132},"Nuxt 實戰指南","nuxt/index",{"title":134,"path":135,"stem":136},"Abstraction Layer 與 Adapter 的差別，一次搞懂設計角色","/nuxt/adapter_abstraction_layer","nuxt/adapter_abstraction_layer",{"title":138,"path":139,"stem":140},"Nuxt 4 全面理解 — 專案檔案結構解析","/nuxt/directory_structure","nuxt/directory_structure",{"title":142,"path":143,"stem":144},"Nuxt 前端 build 流程完整解析","/nuxt/frontend_build","nuxt/frontend_build",{"title":146,"path":147,"stem":148},"Nitro 是什麼？從 Nuxt 專案到 Server 與 Edge 的關鍵引擎","/nuxt/nitro","nuxt/nitro",{"title":150,"path":151,"stem":152},"深入理解 Nuxt 的 .nuxt 與 .output：為什麼部署時一定要分清楚？","/nuxt/nuxt_and_output","nuxt/nuxt_and_output",{"title":154,"path":155,"stem":156},"Nuxt 中 dev、build、preview 的差異一次搞懂","/nuxt/nuxt_dev_build_preview","nuxt/nuxt_dev_build_preview",{"title":158,"path":159,"stem":160},"Nuxt Image vs \u003Cimg>：為什麼 Nuxt 3 專案幾乎都該用 \u003CNuxtImg>？","/nuxt/nuxt_image","nuxt/nuxt_image",{"title":162,"path":163,"stem":164,"children":165},"Python 程式開發","/python","python/index",[166,167,171,175],{"title":162,"path":163,"stem":164},{"title":168,"path":169,"stem":170},"如何在 FastAPI 中調用記憶體 Buffer 回傳圖片 (附實例)","/python/memory_buffer","python/memory_buffer",{"title":172,"path":173,"stem":174},"Python 單元測試教學：如何為你的程式撰寫 Test","/python/python-unit-testing-unittest-pytest","python/python-unit-testing-unittest-pytest",{"title":176,"path":177,"stem":178},"如何使用 uv 取代 pip：改善 Python 專案的開發流程","/python/uv","python/uv",{"title":180,"path":181,"stem":182,"children":183,"page":41},"Statistic","/statistic","statistic",[184,188,192,196],{"title":185,"path":186,"stem":187},"卡方檢定（Chi-Square Test）入門教學","/statistic/chi-square-test-intro","statistic/chi-square-test-intro",{"title":189,"path":190,"stem":191},"常見抽樣方法（Sampling Methods）教學：Stratified、Quota、Convenience、Systematic、Simple Random","/statistic/common-sampling-methods-guide","statistic/common-sampling-methods-guide",{"title":193,"path":194,"stem":195},"Cramér’s V 指標介紹：如何衡量兩個類別變數之間的關聯","/statistic/cramers-v-for-categorical-association","statistic/cramers-v-for-categorical-association",{"title":197,"path":198,"stem":199},"Mann–Whitney U 與 Kolmogorov–Smirnov（KS）檢定：非參數統計檢定的入門指南","/statistic/mann-whitney-u-and-ks-test-intro","statistic/mann-whitney-u-and-ks-test-intro",{"title":201,"path":202,"stem":203,"children":204},"WebDev","/web_dev","web_dev",[205,208,234,248,282,312,334],{"title":206,"path":202,"stem":207},"Web 前端開發","web_dev/index",{"title":209,"path":210,"stem":211,"children":212},"瀏覽器與渲染","/web_dev/browser","web_dev/browser/index",[213,214,218,222,226,230],{"title":209,"path":210,"stem":211},{"title":215,"path":216,"stem":217},"瀏覽器儲存空間完整解析：Cookie、localStorage、IndexedDB 到 Cache Storage","/web_dev/browser/browser-storage-comprehensive-guide","web_dev/browser/browser-storage-comprehensive-guide",{"title":219,"path":220,"stem":221},"DOM (Document Object Model) 深入解析","/web_dev/browser/dom","web_dev/browser/dom",{"title":223,"path":224,"stem":225},"Service Worker Request Flow 深入解析","/web_dev/browser/service-worker-request-flow","web_dev/browser/service-worker-request-flow",{"title":227,"path":228,"stem":229},"CSR、SSR 與 SSG 是什麼？前端渲染策略完整比較","/web_dev/browser/ssr_csr_ssg","web_dev/browser/ssr_csr_ssg",{"title":231,"path":232,"stem":233},"Virtual DOM 深入解析：為什麼它能優化前端效能？","/web_dev/browser/virtual_dom","web_dev/browser/virtual_dom",{"title":235,"path":236,"stem":237,"children":238},"圖形技術","/web_dev/graphics","web_dev/graphics/index",[239,240,244],{"title":235,"path":236,"stem":237},{"title":241,"path":242,"stem":243},"為什麼 Three.js 專案幾乎都選擇 CSR？從 SSR 問題談起","/web_dev/graphics/threejs_csr","web_dev/graphics/threejs_csr",{"title":245,"path":246,"stem":247},"WebGL 是什麼？為什麼前端 3D 幾乎都靠它？","/web_dev/graphics/webgl","web_dev/graphics/webGL",{"title":249,"path":250,"stem":251,"children":252},"架構與配置","/web_dev/infrastructure","web_dev/infrastructure/index",[253,254,258,262,266,270,274,278],{"title":249,"path":250,"stem":251},{"title":255,"path":256,"stem":257},"Zeabur + K3s + Nuxt 部署架構完整解析","/web_dev/infrastructure/k3s-zeabur","web_dev/infrastructure/K3s-zeabur",{"title":259,"path":260,"stem":261},"ECS vs Docker vs Kubernetes：從部署堆疊理解三層架構","/web_dev/infrastructure/ecs-docker-kubernetes-stack","web_dev/infrastructure/ecs-docker-kubernetes-stack",{"title":263,"path":264,"stem":265},"ECS vs VPS 是什麼？從部署網站的角度一次搞懂差別","/web_dev/infrastructure/ecs-vs-vps","web_dev/infrastructure/ecs-vs-vps",{"title":267,"path":268,"stem":269},"Zeabur 內網服務連線完整入門指南","/web_dev/infrastructure/k3s-internal-networking","web_dev/infrastructure/k3s-internal-networking",{"title":271,"path":272,"stem":273},"使用 Microservices 架構設計系統的優勢解析","/web_dev/infrastructure/microservices-architecture-advantages","web_dev/infrastructure/microservices-architecture-advantages",{"title":275,"path":276,"stem":277},"Nginx 入門教學：從反向代理到與 Kubernetes 的架構比較","/web_dev/infrastructure/nginx-intro","web_dev/infrastructure/nginx-intro",{"title":279,"path":280,"stem":281},"YAML 配置是什麼？為什麼現代開發都在用它","/web_dev/infrastructure/yaml-configuration","web_dev/infrastructure/yaml-configuration",{"title":283,"path":284,"stem":285,"children":286},"網絡與通訊","/web_dev/network","web_dev/network/index",[287,288,292,296,300,304,308],{"title":283,"path":284,"stem":285},{"title":289,"path":290,"stem":291},"HTTP Request 結構完整解析：從 Request Line 到 Header 一次看懂","/web_dev/network/http-request-structure","web_dev/network/http-request-structure",{"title":293,"path":294,"stem":295},"OSI 模型（Open Systems Interconnection Model）完整解析","/web_dev/network/osi-model","web_dev/network/osi-model",{"title":297,"path":298,"stem":299},"RESTful API 設計原則與實務解析","/web_dev/network/restful-api","web_dev/network/restful-api",{"title":301,"path":302,"stem":303},"RESTful API 五大設計原則深入解析","/web_dev/network/restful-api-principles","web_dev/network/restful-api-principles",{"title":305,"path":306,"stem":307},"Server-Sent Events (SSE) 深入解析與實作教學","/web_dev/network/sse-introduction","web_dev/network/sse-introduction",{"title":309,"path":310,"stem":311},"WebSocket 入門教學：從概念到 Node.js 實作","/web_dev/network/websocket-introduction","web_dev/network/websocket-introduction",{"title":313,"path":314,"stem":315,"children":316},"認證與安全","/web_dev/security","web_dev/security/index",[317,318,322,326,330],{"title":313,"path":314,"stem":315},{"title":319,"path":320,"stem":321},"使用 Cookie 與 Session 建立使用者驗證（完整新手教學）","/web_dev/security/cookie-session-authentication","web_dev/security/cookie-session-authentication",{"title":323,"path":324,"stem":325},"JWT 驗證機制完整解析：從登入流程到實務應用","/web_dev/security/jwt-authentication","web_dev/security/jwt-authentication",{"title":327,"path":328,"stem":329},"Secret Key 簽名是什麼？從零理解資料簽名的本質","/web_dev/security/secret-key-signing","web_dev/security/secret-key-signing",{"title":331,"path":332,"stem":333},"SSH（Secure Shell）是什麼？從遠端登入到安全通道的核心概念","/web_dev/security/ssh","web_dev/security/ssh",{"title":335,"path":336,"stem":337,"children":338},"SEO 與規範","/web_dev/seo","web_dev/seo/index",[339,340,344,348],{"title":335,"path":336,"stem":337},{"title":341,"path":342,"stem":343},"Canonical URL 是什麼？用生活化方式搞懂前端 SEO 的基本保命符","/web_dev/seo/canonical_link","web_dev/seo/canonical_link",{"title":345,"path":346,"stem":347},"robots.txt 是什麼？SEO 的第一道守門員","/web_dev/seo/robot_txt","web_dev/seo/robot_txt",{"title":349,"path":350,"stem":351},"Nuxt SEO 中的 Meta 與 SEO 工具是如何運作的？","/web_dev/seo/seo","web_dev/seo/seo",{"id":353,"title":319,"body":354,"description":1092,"extension":1093,"links":1094,"meta":1095,"navigation":721,"path":320,"seo":1102,"stem":321,"__hash__":1103},"docs/web_dev/security/cookie-session-authentication.md",{"type":355,"value":356,"toc":1070},"minimark",[357,361,370,373,376,381,388,398,409,416,418,422,425,430,433,468,471,482,492,496,499,524,531,536,549,551,555,558,562,569,573,579,583,589,605,609,616,620,630,634,644,646,649,652,678,683,685,689,692,695,857,861,998,1000,1004,1007,1032,1052,1054,1057,1063,1066],[358,359,319],"h1",{"id":360},"使用-cookie-與-session-建立使用者驗證完整新手教學",[362,363,364,365,369],"p",{},"在多數網站中，「登入系統」其實是在解決一個非常核心的問題：",[366,367,368],"strong",{},"HTTP 本身不會記得使用者是誰","。當你登入後重新整理頁面，網站仍然知道你是誰，這背後並不是 HTTP 幫你記住，而是我們額外設計了一套機制。",[362,371,372],{},"要理解登入驗證，我們必須先理解 HTTP 的特性。",[374,375],"hr",{},[377,378,380],"h2",{"id":379},"為什麼-http-需要額外的驗證機制","為什麼 HTTP 需要額外的驗證機制？",[362,382,383,384,387],{},"HTTP（HyperText Transfer Protocol）是一種 ",[366,385,386],{},"stateless（無狀態）協定","。所謂無狀態，意思是：",[389,390,391,395],"ul",{},[392,393,394],"li",{},"每一個 request 都是獨立的。",[392,396,397],{},"Server 不會自動記住前一次的請求內容。",[362,399,400,401,405,406],{},"舉例來說，當你發送 ",[402,403,404],"code",{},"GET /profile"," 時，Server 並不會知道你是不是剛剛登入成功的那個人。對 Server 而言，這只是一個新的請求。因此，我們需要一種方法來讓 Server 辨認：",[366,407,408],{},"這個 request 是來自同一個使用者。",[362,410,411,412,415],{},"傳統 Web 應用最常見的做法，就是 ",[366,413,414],{},"Cookie + Session","。",[374,417],{},[377,419,421],{"id":420},"先理解-cookie-與-session-的分工","先理解 Cookie 與 Session 的分工",[362,423,424],{},"很多人會把 Cookie 和 Session 混為一談，但它們其實是兩個不同的角色。",[426,427,429],"h3",{"id":428},"cookie存在瀏覽器的小資料","Cookie：存在瀏覽器的小資料",[362,431,432],{},"Cookie 是由 Server 設定，並儲存在瀏覽器中的小型資料。當 Server 回應時，可以送出：",[434,435,440],"pre",{"className":436,"code":437,"language":438,"meta":439,"style":439},"language-javascript shiki shiki-themes github-dark","Set-Cookie: sessionId=abc123\n","javascript","",[402,441,442],{"__ignoreMap":439},[443,444,447,451,455,459,462,465],"span",{"class":445,"line":446},"line",1,[443,448,450],{"class":449},"s95oV","Set",[443,452,454],{"class":453},"snl16","-",[443,456,458],{"class":457},"svObZ","Cookie",[443,460,461],{"class":449},": sessionId",[443,463,464],{"class":453},"=",[443,466,467],{"class":449},"abc123\n",[362,469,470],{},"瀏覽器會自動儲存這個 Cookie。之後只要發送同一個網域的請求，瀏覽器就會自動附帶：",[434,472,476],{"className":473,"code":474,"language":475,"meta":439,"style":439},"language-makefile shiki shiki-themes github-dark","Cookie: sessionId=abc123\n","makefile",[402,477,478],{"__ignoreMap":439},[443,479,480],{"class":445,"line":446},[443,481,474],{},[362,483,484,485,488,489,415],{},"也就是說：",[366,486,487],{},"Cookie 的責任是「把識別碼帶回 Server」。"," 它本身通常不存放敏感資料，而是存放一個 key，例如 ",[402,490,491],{},"sessionId",[426,493,495],{"id":494},"session存在-server-的登入狀態","Session：存在 Server 的登入狀態",[362,497,498],{},"Session 則是存在 Server 端的資料儲存機制。例如在 Server 中有一個 session store：",[434,500,504],{"className":501,"code":502,"language":503,"meta":439,"style":439},"language-css shiki shiki-themes github-dark","abc123 → { userId: 42 }\n","css",[402,505,506],{"__ignoreMap":439},[443,507,508,511,515,518,521],{"class":445,"line":446},[443,509,510],{"class":449},"abc123 → { ",[443,512,514],{"class":513},"sDLfK","userId",[443,516,517],{"class":449},": ",[443,519,520],{"class":513},"42",[443,522,523],{"class":449}," }\n",[362,525,526,527,530],{},"當 Server 收到 ",[402,528,529],{},"sessionId=abc123"," 時，就可以查詢這個 session store，找到對應的使用者資訊。",[362,532,533],{},[366,534,535],{},"一句話理解關係：",[389,537,538,543],{},[392,539,540,542],{},[366,541,458],{}," 負責攜帶 sessionId",[392,544,545,548],{},[366,546,547],{},"Session"," 負責儲存使用者資料",[374,550],{},[377,552,554],{"id":553},"登入流程完整解析login-lifecycle","登入流程完整解析（Login Lifecycle）",[362,556,557],{},"現在我們用實際情境，走一遍完整的登入流程。",[426,559,561],{"id":560},"step-1使用者送出登入表單","Step 1：使用者送出登入表單",[362,563,564,565,568],{},"瀏覽器發送 ",[402,566,567],{},"POST /login","，並附帶帳號密碼。",[426,570,572],{"id":571},"step-2server-驗證帳密","Step 2：Server 驗證帳密",[362,574,575,576,578],{},"Server 會查詢資料庫、驗證密碼，並取得對應的 ",[402,577,514],{},"（例如 42）。",[426,580,582],{"id":581},"step-3建立-session","Step 3：建立 Session",[362,584,585,586,588],{},"Server 產生一個隨機的 ",[402,587,491],{},"（例如 abc123），並儲存在 Server 的 session store 中：",[434,590,591],{"className":501,"code":502,"language":503,"meta":439,"style":439},[402,592,593],{"__ignoreMap":439},[443,594,595,597,599,601,603],{"class":445,"line":446},[443,596,510],{"class":449},[443,598,514],{"class":513},[443,600,517],{"class":449},[443,602,520],{"class":513},[443,604,523],{"class":449},[426,606,608],{"id":607},"step-4server-設定-cookie","Step 4：Server 設定 Cookie",[362,610,611,612,615],{},"Server 在 HTTP 回應中加入 ",[402,613,614],{},"Set-Cookie: sessionId=abc123","。瀏覽器會自動儲存，使用者無須操作。",[426,617,619],{"id":618},"step-5之後的請求","Step 5：之後的請求",[362,621,622,623,626,627,415],{},"當使用者訪問 ",[402,624,625],{},"/profile"," 時，瀏覽器會自動附帶 ",[402,628,629],{},"Cookie: sessionId=abc123",[426,631,633],{"id":632},"step-6server-查詢-session","Step 6：Server 查詢 Session",[362,635,636,637,639,640,643],{},"Server 收到請求後，讀取 Cookie 中的 ",[402,638,491],{},"，並查詢 session store 找到 ",[402,641,642],{},"userId: 42","，從而辨認出使用者身份。",[374,645],{},[377,647,648],{"id":648},"用一個直覺心智模型理解",[362,650,651],{},"你可以把這整件事情想成：",[653,654,655,658,665,672,675],"ol",{},[392,656,657],{},"登入成功",[392,659,660,661,664],{},"Server 建立一張「",[366,662,663],{},"會員卡","」（session）",[392,666,667,668,671],{},"把",[366,669,670],{},"卡號","（sessionId）放進 Cookie",[392,673,674],{},"瀏覽器之後每次都帶著卡號",[392,676,677],{},"Server 查卡號辨認身份",[362,679,680],{},[366,681,682],{},"重要的是：真正的登入資料在 Server，瀏覽器只負責帶識別碼。",[374,684],{},[377,686,688],{"id":687},"nodejs-簡化範例概念示範","Node.js 簡化範例（概念示範）",[362,690,691],{},"下面用最簡單的方式模擬 Session 概念：",[426,693,694],{"id":694},"登入路由",[434,696,700],{"className":697,"code":698,"language":699,"meta":439,"style":439},"language-js shiki shiki-themes github-dark","const sessionStore = {};\n\napp.post(\"/login\", (req, res) => {\n  const sessionId = \"abc123\"; // 實務上會是隨機字串\n  sessionStore[sessionId] = {\n    userId: 42,\n  };\n  res.setHeader(\"Set-Cookie\", `sessionId=${sessionId}`);\n  res.send(\"ok\");\n});\n","js",[402,701,702,716,723,761,782,792,803,809,836,851],{"__ignoreMap":439},[443,703,704,707,710,713],{"class":445,"line":446},[443,705,706],{"class":453},"const",[443,708,709],{"class":513}," sessionStore",[443,711,712],{"class":453}," =",[443,714,715],{"class":449}," {};\n",[443,717,719],{"class":445,"line":718},2,[443,720,722],{"emptyLinePlaceholder":721},true,"\n",[443,724,726,729,732,735,739,742,746,749,752,755,758],{"class":445,"line":725},3,[443,727,728],{"class":449},"app.",[443,730,731],{"class":457},"post",[443,733,734],{"class":449},"(",[443,736,738],{"class":737},"sU2Wk","\"/login\"",[443,740,741],{"class":449},", (",[443,743,745],{"class":744},"s9osk","req",[443,747,748],{"class":449},", ",[443,750,751],{"class":744},"res",[443,753,754],{"class":449},") ",[443,756,757],{"class":453},"=>",[443,759,760],{"class":449}," {\n",[443,762,764,767,770,772,775,778],{"class":445,"line":763},4,[443,765,766],{"class":453},"  const",[443,768,769],{"class":513}," sessionId",[443,771,712],{"class":453},[443,773,774],{"class":737}," \"abc123\"",[443,776,777],{"class":449},"; ",[443,779,781],{"class":780},"sAwPA","// 實務上會是隨機字串\n",[443,783,785,788,790],{"class":445,"line":784},5,[443,786,787],{"class":449},"  sessionStore[sessionId] ",[443,789,464],{"class":453},[443,791,760],{"class":449},[443,793,795,798,800],{"class":445,"line":794},6,[443,796,797],{"class":449},"    userId: ",[443,799,520],{"class":513},[443,801,802],{"class":449},",\n",[443,804,806],{"class":445,"line":805},7,[443,807,808],{"class":449},"  };\n",[443,810,812,815,818,820,823,825,828,830,833],{"class":445,"line":811},8,[443,813,814],{"class":449},"  res.",[443,816,817],{"class":457},"setHeader",[443,819,734],{"class":449},[443,821,822],{"class":737},"\"Set-Cookie\"",[443,824,748],{"class":449},[443,826,827],{"class":737},"`sessionId=${",[443,829,491],{"class":449},[443,831,832],{"class":737},"}`",[443,834,835],{"class":449},");\n",[443,837,839,841,844,846,849],{"class":445,"line":838},9,[443,840,814],{"class":449},[443,842,843],{"class":457},"send",[443,845,734],{"class":449},[443,847,848],{"class":737},"\"ok\"",[443,850,835],{"class":449},[443,852,854],{"class":445,"line":853},10,[443,855,856],{"class":449},"});\n",[426,858,860],{"id":859},"需要登入的-api","需要登入的 API",[434,862,864],{"className":697,"code":863,"language":699,"meta":439,"style":439},"app.get(\"/profile\", (req, res) => {\n  const sessionId = req.cookies.sessionId;\n  const session = sessionStore[sessionId];\n  \n  if (!session) {\n    return res.status(401).send(\"not logged in\");\n  }\n  \n  res.send(`userId = ${session.userId}`);\n});\n",[402,865,866,892,903,915,920,934,962,967,971,994],{"__ignoreMap":439},[443,867,868,870,873,875,878,880,882,884,886,888,890],{"class":445,"line":446},[443,869,728],{"class":449},[443,871,872],{"class":457},"get",[443,874,734],{"class":449},[443,876,877],{"class":737},"\"/profile\"",[443,879,741],{"class":449},[443,881,745],{"class":744},[443,883,748],{"class":449},[443,885,751],{"class":744},[443,887,754],{"class":449},[443,889,757],{"class":453},[443,891,760],{"class":449},[443,893,894,896,898,900],{"class":445,"line":718},[443,895,766],{"class":453},[443,897,769],{"class":513},[443,899,712],{"class":453},[443,901,902],{"class":449}," req.cookies.sessionId;\n",[443,904,905,907,910,912],{"class":445,"line":725},[443,906,766],{"class":453},[443,908,909],{"class":513}," session",[443,911,712],{"class":453},[443,913,914],{"class":449}," sessionStore[sessionId];\n",[443,916,917],{"class":445,"line":763},[443,918,919],{"class":449},"  \n",[443,921,922,925,928,931],{"class":445,"line":784},[443,923,924],{"class":453},"  if",[443,926,927],{"class":449}," (",[443,929,930],{"class":453},"!",[443,932,933],{"class":449},"session) {\n",[443,935,936,939,942,945,947,950,953,955,957,960],{"class":445,"line":794},[443,937,938],{"class":453},"    return",[443,940,941],{"class":449}," res.",[443,943,944],{"class":457},"status",[443,946,734],{"class":449},[443,948,949],{"class":513},"401",[443,951,952],{"class":449},").",[443,954,843],{"class":457},[443,956,734],{"class":449},[443,958,959],{"class":737},"\"not logged in\"",[443,961,835],{"class":449},[443,963,964],{"class":445,"line":805},[443,965,966],{"class":449},"  }\n",[443,968,969],{"class":445,"line":811},[443,970,919],{"class":449},[443,972,973,975,977,979,982,985,988,990,992],{"class":445,"line":838},[443,974,814],{"class":449},[443,976,843],{"class":457},[443,978,734],{"class":449},[443,980,981],{"class":737},"`userId = ${",[443,983,984],{"class":449},"session",[443,986,987],{"class":737},".",[443,989,514],{"class":449},[443,991,832],{"class":737},[443,993,835],{"class":449},[443,995,996],{"class":445,"line":853},[443,997,856],{"class":449},[374,999],{},[377,1001,1003],{"id":1002},"安全性設定非常重要","安全性設定（非常重要）",[362,1005,1006],{},"實務上 Cookie 通常會加上安全參數，這在開發中不可忽略：",[434,1008,1010],{"className":436,"code":1009,"language":438,"meta":439,"style":439},"Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Lax\n",[402,1011,1012],{"__ignoreMap":439},[443,1013,1014,1016,1018,1020,1022,1024,1027,1029],{"class":445,"line":446},[443,1015,450],{"class":449},[443,1017,454],{"class":453},[443,1019,458],{"class":457},[443,1021,461],{"class":449},[443,1023,464],{"class":453},[443,1025,1026],{"class":449},"abc123; HttpOnly; Secure; SameSite",[443,1028,464],{"class":453},[443,1030,1031],{"class":449},"Lax\n",[389,1033,1034,1040,1046],{},[392,1035,1036,1039],{},[366,1037,1038],{},"HttpOnly","：避免 JavaScript 讀取 Cookie，降低 XSS 攻擊風險。",[392,1041,1042,1045],{},[366,1043,1044],{},"Secure","：只允許在 HTTPS 加密連線中傳輸。",[392,1047,1048,1051],{},[366,1049,1050],{},"SameSite=Lax","：降低 CSRF 跨站請求偽造的風險。",[374,1053],{},[377,1055,1056],{"id":1056},"總結",[362,1058,1059,1060],{},"Cookie + Session 驗證的核心流程如下：\n",[366,1061,1062],{},"Server 建立 Session → 把 sessionId 放進 Cookie → Browser 自動帶回 → Server 查詢 Session",[362,1064,1065],{},"理解這個流程後，你不只會知道「怎麼登入」，更會知道背後發生了什麼事情。這將幫助你在學習 JWT、OAuth 或其他驗證機制時，更容易理解它們與傳統 Session 的差異。",[1067,1068,1069],"style",{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":439,"searchDepth":718,"depth":718,"links":1071},[1072,1073,1077,1085,1086,1090,1091],{"id":379,"depth":718,"text":380},{"id":420,"depth":718,"text":421,"children":1074},[1075,1076],{"id":428,"depth":725,"text":429},{"id":494,"depth":725,"text":495},{"id":553,"depth":718,"text":554,"children":1078},[1079,1080,1081,1082,1083,1084],{"id":560,"depth":725,"text":561},{"id":571,"depth":725,"text":572},{"id":581,"depth":725,"text":582},{"id":607,"depth":725,"text":608},{"id":618,"depth":725,"text":619},{"id":632,"depth":725,"text":633},{"id":648,"depth":718,"text":648},{"id":687,"depth":718,"text":688,"children":1087},[1088,1089],{"id":694,"depth":725,"text":694},{"id":859,"depth":725,"text":860},{"id":1002,"depth":718,"text":1003},{"id":1056,"depth":718,"text":1056},"從 HTTP 無狀態特性開始，深入理解 Cookie 與 Session 的分工、登入流程與 Node.js 實作範例，建立完整的使用者驗證心智模型。","md",null,{"tags":1096,"category":203,"date":1101},[1097,1098,984,1099,1100],"http","cookie","authentication","nodejs","2026-02-13",{"title":319,"description":1092},"94j9wIpoZk022RSG-TMBBJhnAxRqh2f0SibZ7ZSoSEw",[1105,1107],{"title":313,"path":314,"stem":315,"description":1106,"children":-1},"探討身份驗證機制（JWT, Cookie/Session）、密鑰簽章以及 SSH 等安全技術。",{"title":323,"path":324,"stem":325,"description":1108,"children":-1},"深入理解 JWT（JSON Web Token）的運作原理與完整驗證流程，學會如何在 Node.js 與 SPA 架構中實作無狀態身份驗證。",1776690848298]