{"id":2625,"date":"2024-10-23T16:04:12","date_gmt":"2024-10-23T09:04:12","guid":{"rendered":"https:\/\/fstack.io.vn\/?p=2625"},"modified":"2024-10-23T16:14:46","modified_gmt":"2024-10-23T09:14:46","slug":"xac-thuc-jwt-trong-node-js-ket-hop-voi-redis-quan-ly-blacklist","status":"publish","type":"post","link":"https:\/\/fstack.io.vn\/blog\/xac-thuc-jwt-trong-node-js-ket-hop-voi-redis-quan-ly-blacklist\/","title":{"rendered":"X\u00e1c Th\u1ef1c JWT Trong Node.js: K\u1ebft h\u1ee3p v\u1edbi Redis Qu\u1ea3n L\u00fd Blacklist"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"2625\" class=\"elementor elementor-2625\" data-elementor-post-type=\"post\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f0e3bed e-flex e-con-boxed e-con e-parent\" data-id=\"f0e3bed\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3dcddb1 elementor-widget elementor-widget-text-editor\" data-id=\"3dcddb1\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Trong b\u1ed1i c\u1ea3nh b\u1ea3o m\u1eadt \u1ee9ng d\u1ee5ng web ng\u00e0y nay, vi\u1ec7c x\u00e1c th\u1ef1c ng\u01b0\u1eddi d\u00f9ng v\u00e0 qu\u1ea3n l\u00fd quy\u1ec1n truy c\u1eadp l\u00e0 r\u1ea5t quan tr\u1ecdng. <strong>JSON Web Tokens (JWT)<\/strong> \u0111\u00e3 tr\u1edf th\u00e0nh m\u1ed9t ph\u01b0\u01a1ng ph\u00e1p ph\u1ed5 bi\u1ebfn \u0111\u1ec3 th\u1ef1c hi\u1ec7n x\u00e1c th\u1ef1c. Tuy nhi\u00ean, khi s\u1eed d\u1ee5ng JWT, c\u00f3 m\u1ed9t v\u1ea5n \u0111\u1ec1 ph\u00e1t sinh li\u00ean quan \u0111\u1ebfn vi\u1ec7c qu\u1ea3n l\u00fd <strong><a href=\"https:\/\/fstack.io.vn\/blog\/whitelisting-vs-blacklisting-la-gi-4-su-khac-nhau-giua-chung\/\">blacklist<\/a><\/strong> cho nh\u1eefng token kh\u00f4ng c\u00f2n h\u1ee3p l\u1ec7. Trong b\u00e0i vi\u1ebft n\u00e0y, ch\u00fang ta s\u1ebd kh\u00e1m ph\u00e1 c\u00e1ch x\u00e1c th\u1ef1c JWT trong <a href=\"https:\/\/fstack.io.vn\/blog\/node-js-la-gi-tat-tan-tat-ve-node-js\/\">Node.js<\/a> v\u00e0 c\u00e1ch s\u1eed d\u1ee5ng <strong>Redis<\/strong> \u0111\u1ec3 qu\u1ea3n l\u00fd blacklist m\u1ed9t c\u00e1ch hi\u1ec7u qu\u1ea3.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ec51583 elementor-widget elementor-widget-heading\" data-id=\"ec51583\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_82_2 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Danh m\u1ee5c b\u00e0i vi\u1ebft<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/fstack.io.vn\/blog\/xac-thuc-jwt-trong-node-js-ket-hop-voi-redis-quan-ly-blacklist\/#JWT_la_gi\" >JWT l\u00e0 g\u00ec?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/fstack.io.vn\/blog\/xac-thuc-jwt-trong-node-js-ket-hop-voi-redis-quan-ly-blacklist\/#Tai_sao_can_quan_ly_Blacklist\" >T\u1ea1i sao c\u1ea7n qu\u1ea3n l\u00fd Blacklist?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/fstack.io.vn\/blog\/xac-thuc-jwt-trong-node-js-ket-hop-voi-redis-quan-ly-blacklist\/#Cach_ket_hop_JWT_voi_Redis_quan_ly_Blacklist_trong_Nodejs\" >C\u00e1ch k\u1ebft h\u1ee3p JWT v\u1edbi Redis qu\u1ea3n l\u00fd Blacklist trong Node.js<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/fstack.io.vn\/blog\/xac-thuc-jwt-trong-node-js-ket-hop-voi-redis-quan-ly-blacklist\/#Buoc_1_Cai_dat_cac_goi_can_thiet\" >B\u01b0\u1edbc 1: C\u00e0i \u0111\u1eb7t c\u00e1c g\u00f3i c\u1ea7n thi\u1ebft<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/fstack.io.vn\/blog\/xac-thuc-jwt-trong-node-js-ket-hop-voi-redis-quan-ly-blacklist\/#Buoc_2_Thiet_lap_Redis\" >B\u01b0\u1edbc 2: Thi\u1ebft l\u1eadp Redis<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/fstack.io.vn\/blog\/xac-thuc-jwt-trong-node-js-ket-hop-voi-redis-quan-ly-blacklist\/#Buoc_3_Tao_ung_dung_Nodejs\" >B\u01b0\u1edbc 3: T\u1ea1o \u1ee9ng d\u1ee5ng Node.js<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/fstack.io.vn\/blog\/xac-thuc-jwt-trong-node-js-ket-hop-voi-redis-quan-ly-blacklist\/#Giai_thich_ma_nguon\" >Gi\u1ea3i th\u00edch m\u00e3 ngu\u1ed3n<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/fstack.io.vn\/blog\/xac-thuc-jwt-trong-node-js-ket-hop-voi-redis-quan-ly-blacklist\/#Ket_luan\" >K\u1ebft lu\u1eadn<\/a><\/li><\/ul><\/nav><\/div>\n<h2 class=\"elementor-heading-title elementor-size-default\"><span class=\"ez-toc-section\" id=\"JWT_la_gi\"><\/span>JWT l\u00e0 g\u00ec?<span class=\"ez-toc-section-end\"><\/span><\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b4a2ee5 elementor-widget elementor-widget-text-editor\" data-id=\"b4a2ee5\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><strong>JSON Web Token (JWT)<\/strong> l\u00e0 m\u1ed9t chu\u1ea9n m\u1edf (RFC 7519) cho ph\u00e9p truy\u1ec1n t\u1ea3i th\u00f4ng tin gi\u1eefa hai b\u00ean d\u01b0\u1edbi d\u1ea1ng m\u1ed9t <a href=\"https:\/\/fstack.io.vn\/blog\/lap-trinh-huong-doi-tuong-la-gi-mot-so-dac-trung-cua-oop\/\">\u0111\u1ed1i t\u01b0\u1ee3ng<\/a> JSON. Th\u00f4ng tin trong JWT \u0111\u01b0\u1ee3c <a href=\"https:\/\/fstack.io.vn\/blog\/ma-hoa-vigenere-la-gi-giai-vigenere-truc-tuyen\/\">m\u00e3 h\u00f3a<\/a> v\u00e0 c\u00f3 th\u1ec3 \u0111\u01b0\u1ee3c x\u00e1c th\u1ef1c b\u1eb1ng c\u00e1ch s\u1eed d\u1ee5ng ch\u1eef k\u00fd s\u1ed1. JWT th\u01b0\u1eddng \u0111\u01b0\u1ee3c s\u1eed d\u1ee5ng \u0111\u1ec3 x\u00e1c th\u1ef1c ng\u01b0\u1eddi d\u00f9ng v\u00e0 cung c\u1ea5p quy\u1ec1n truy c\u1eadp v\u00e0o c\u00e1c t\u00e0i nguy\u00ean.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-42688a2 elementor-widget elementor-widget-text-editor\" data-id=\"42688a2\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>M\u1ed9t JWT bao g\u1ed3m ba ph\u1ea7n:<\/p><ol><li><strong>Header<\/strong>: Th\u00f4ng tin v\u1ec1 lo\u1ea1i token v\u00e0 thu\u1eadt to\u00e1n m\u00e3 h\u00f3a.<\/li><li><strong>Payload<\/strong>: Ch\u1ee9a th\u00f4ng tin v\u1ec1 ng\u01b0\u1eddi d\u00f9ng v\u00e0 quy\u1ec1n h\u1ea1n (claims).<\/li><li><strong>Signature<\/strong>: \u0110\u01b0\u1ee3c t\u1ea1o b\u1eb1ng c\u00e1ch m\u00e3 h\u00f3a header v\u00e0 payload c\u00f9ng v\u1edbi m\u1ed9t kh\u00f3a b\u00ed m\u1eadt.<\/li><\/ol>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3a169ca elementor-widget elementor-widget-heading\" data-id=\"3a169ca\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\"><span class=\"ez-toc-section\" id=\"Tai_sao_can_quan_ly_Blacklist\"><\/span>T\u1ea1i sao c\u1ea7n qu\u1ea3n l\u00fd Blacklist?<span class=\"ez-toc-section-end\"><\/span><\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b52b651 elementor-widget elementor-widget-text-editor\" data-id=\"b52b651\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>M\u1eb7c d\u00f9 JWT c\u00f3 \u01b0u \u0111i\u1ec3m l\u00e0 kh\u00f4ng c\u1ea7n l\u01b0u tr\u1eef tr\u1ea1ng th\u00e1i tr\u00ean server (stateless), nh\u01b0ng khi m\u1ed9t token b\u1ecb thu h\u1ed3i (v\u00ed d\u1ee5: ng\u01b0\u1eddi d\u00f9ng \u0111\u0103ng xu\u1ea5t), c\u1ea7n c\u00f3 c\u01a1 ch\u1ebf \u0111\u1ec3 qu\u1ea3n l\u00fd nh\u1eefng token n\u00e0y. N\u1ebfu kh\u00f4ng, nh\u1eefng token \u0111\u00e3 b\u1ecb thu h\u1ed3i v\u1eabn c\u00f3 th\u1ec3 \u0111\u01b0\u1ee3c s\u1eed d\u1ee5ng \u0111\u1ec3 truy c\u1eadp v\u00e0o t\u00e0i nguy\u00ean.<\/p><p>\u0110\u00e2y ch\u00ednh l\u00e0 l\u00fd do t\u1ea1i <a href=\"https:\/\/fstack.io.vn\/blog\/10-the-meta-ma-ban-nen-biet-khi-lam-seo-website\/\">sao<\/a> ch\u00fang ta c\u1ea7n s\u1eed d\u1ee5ng blacklist. Blacklist s\u1ebd l\u01b0u tr\u1eef danh s\u00e1ch c\u00e1c JWT \u0111\u00e3 b\u1ecb thu h\u1ed3i \u0111\u1ec3 kh\u00f4ng cho ph\u00e9p ch\u00fang \u0111\u01b0\u1ee3c s\u1eed d\u1ee5ng n\u1eefa.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7011fe2 elementor-widget elementor-widget-heading\" data-id=\"7011fe2\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\"><span class=\"ez-toc-section\" id=\"Cach_ket_hop_JWT_voi_Redis_quan_ly_Blacklist_trong_Nodejs\"><\/span>C\u00e1ch k\u1ebft h\u1ee3p JWT v\u1edbi Redis qu\u1ea3n l\u00fd Blacklist trong Node.js<span class=\"ez-toc-section-end\"><\/span><\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d4be052 elementor-widget elementor-widget-text-editor\" data-id=\"d4be052\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>B\u1ea1n c\u00f3 th\u1ec3 l\u00e0m theo c\u00e1c b\u01b0\u1edbc \u1edf ph\u00eda d\u01b0\u1edbi ho\u1eb7c xem video c\u1ee7a anh <a class=\"yt-simple-endpoint style-scope yt-formatted-string\" spellcheck=\"false\" href=\"https:\/\/www.youtube.com\/@anonystick\" rel=\"nofollow noopener\" target=\"_blank\">Tips Javascript<\/a>\u00a0m\u1ed9t ng\u01b0\u1eddi r\u1ea5t n\u1ed5i ti\u1ebfng trong vi\u1ec7c t\u1ed1i \u01b0u perfomance\u00a0<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b1ccd08 elementor-widget elementor-widget-video\" data-id=\"b1ccd08\" data-element_type=\"widget\" data-settings=\"{&quot;youtube_url&quot;:&quot;https:\\\/\\\/www.youtube.com\\\/watch?v=PP_7AvltBBM&quot;,&quot;autoplay&quot;:&quot;yes&quot;,&quot;mute&quot;:&quot;yes&quot;,&quot;video_type&quot;:&quot;youtube&quot;,&quot;controls&quot;:&quot;yes&quot;}\" data-widget_type=\"video.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-wrapper elementor-open-inline\">\n\t\t\t<div class=\"elementor-video\"><\/div>\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9d85156 elementor-widget elementor-widget-text-editor\" data-id=\"9d85156\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Ngu\u1ed3n<a href=\"https:\/\/www.youtube.com\/watch?v=PP_7AvltBBM\" rel=\"nofollow noopener\" target=\"_blank\"> Tips Javascript\u00a0<\/a><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d0196d1 elementor-widget elementor-widget-heading\" data-id=\"d0196d1\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\"><span class=\"ez-toc-section\" id=\"Buoc_1_Cai_dat_cac_goi_can_thiet\"><\/span>B\u01b0\u1edbc 1: C\u00e0i \u0111\u1eb7t c\u00e1c g\u00f3i c\u1ea7n thi\u1ebft<span class=\"ez-toc-section-end\"><\/span><\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f8a37ef elementor-widget elementor-widget-text-editor\" data-id=\"f8a37ef\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Tr\u01b0\u1edbc ti\u00ean, b\u1ea1n c\u1ea7n c\u00e0i \u0111\u1eb7t c\u00e1c g\u00f3i npm c\u1ea7n thi\u1ebft cho d\u1ef1 \u00e1n Node.js c\u1ee7a m\u00ecnh:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4903732 elementor-widget elementor-widget-code-highlight\" data-id=\"4903732\" data-element_type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-okaidia copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp>npm install express jsonwebtoken redis dotenv\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6c649e6 elementor-widget elementor-widget-heading\" data-id=\"6c649e6\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\"><span class=\"ez-toc-section\" id=\"Buoc_2_Thiet_lap_Redis\"><\/span>B\u01b0\u1edbc 2: Thi\u1ebft l\u1eadp Redis<span class=\"ez-toc-section-end\"><\/span><\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b5fef65 elementor-widget elementor-widget-text-editor\" data-id=\"b5fef65\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Kh\u1edfi \u0111\u1ed9ng m\u1ed9t phi\u00ean b\u1ea3n Redis. N\u1ebfu b\u1ea1n ch\u01b0a c\u00f3 Redis, c\u00f3 th\u1ec3 t\u1ea3i v\u00e0 c\u00e0i \u0111\u1eb7t Redis t\u1eeb <a href=\"https:\/\/redis.io\/\" target=\"_new\" rel=\"noopener nofollow\">trang ch\u1ee7 c\u1ee7a Redis<\/a>.<\/p><p>Sau khi c\u00e0i \u0111\u1eb7t xong, b\u1ea1n c\u00f3 th\u1ec3 ki\u1ec3m tra b\u1eb1ng c\u00e1ch ch\u1ea1y l\u1ec7nh:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9f1bb5a elementor-widget elementor-widget-code-highlight\" data-id=\"9f1bb5a\" data-element_type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-okaidia copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp>redis-server<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-decb173 elementor-widget elementor-widget-heading\" data-id=\"decb173\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\"><span class=\"ez-toc-section\" id=\"Buoc_3_Tao_ung_dung_Nodejs\"><\/span>B\u01b0\u1edbc 3: T\u1ea1o \u1ee9ng d\u1ee5ng Node.js<span class=\"ez-toc-section-end\"><\/span><\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-63452b6 elementor-widget elementor-widget-text-editor\" data-id=\"63452b6\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>T\u1ea1o m\u1ed9t file <code>app.js<\/code> v\u00e0 c\u1ea5u h\u00ecnh Express c\u00f9ng v\u1edbi JWT v\u00e0 Redis.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-238a895 elementor-widget elementor-widget-code-highlight\" data-id=\"238a895\" data-element_type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-okaidia copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp>const express = require('express');\nconst jwt = require('jsonwebtoken');\nconst redis = require('redis');\nconst dotenv = require('dotenv');\n\ndotenv.config();\n\nconst app = express();\nconst redisClient = redis.createClient();\n\nredisClient.on('error', (err) => {\n    console.error('Redis error: ', err);\n});\n\napp.use(express.json());\n\n\/\/ Kh\u00f3a b\u00ed m\u1eadt cho JWT\nconst SECRET_KEY = process.env.SECRET_KEY || 'your_secret_key';\n\n\/\/ <a href=\"https:\/\/fstack.io.vn\/blog\/constructor-ham-tao-trong-java-la-gi-mot-so-cach-khai-bao-constructor-trong-java\/\">H\u00e0m t\u1ea1o<\/a> token\nconst generateToken = (userId) => {\n    return jwt.sign({ id: userId }, SECRET_KEY, { expiresIn: '1h' });\n};\n\n\/\/ Middleware ki\u1ec3m tra token\nconst authenticateJWT = (req, res, next) => {\n    const token = req.header('Authorization')?.split(' ')[1];\n\n    if (!token) return res.sendStatus(401);\n\n    \/\/ Ki\u1ec3m tra blacklist\n    redisClient.get(token, (err, reply) => {\n        if (reply) return res.sendStatus(401); \/\/ Token b\u1ecb ch\u1eb7n\n\n        jwt.verify(token, SECRET_KEY, (err, user) => {\n            if (err) return res.sendStatus(403);\n            req.user = user;\n            next();\n        });\n    });\n};\n\n\/\/ \u0110\u0103ng nh\u1eadp v\u00e0 t\u1ea1o token\napp.post('\/login', (req, res) => {\n    const { username } = req.body; \/\/ Gi\u1ea3 s\u1eed b\u1ea1n c\u00f3 m\u1ed9t tr\u01b0\u1eddng username\n    const token = generateToken(username);\n    res.json({ token });\n});\n\n\/\/ \u0110\u0103ng xu\u1ea5t (thu h\u1ed3i token)\napp.post('\/logout', authenticateJWT, (req, res) => {\n    const token = req.header('Authorization').split(' ')[1];\n\n    \/\/ L\u01b0u token v\u00e0o Redis \u0111\u1ec3 blacklist\n    redisClient.set(token, 'blacklisted', 'EX', 3600); \/\/ Th\u1eddi gian s\u1ed1ng 1 gi\u1edd\n    res.sendStatus(200);\n});\n\n\/\/ Route b\u1ea3o v\u1ec7\napp.get('\/protected', authenticateJWT, (req, res) => {\n    res.send('This is a protected route.');\n});\n\n\/\/ Kh\u1edfi \u0111\u1ed9ng server\nconst PORT = process.env.PORT || 3000;\napp.listen(PORT, () => {\n    console.log(`Server is running on port ${PORT}`);\n});\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4776fbe elementor-widget elementor-widget-heading\" data-id=\"4776fbe\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\"><span class=\"ez-toc-section\" id=\"Giai_thich_ma_nguon\"><\/span>Gi\u1ea3i th\u00edch m\u00e3 ngu\u1ed3n<span class=\"ez-toc-section-end\"><\/span><\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-57f56dc elementor-widget elementor-widget-text-editor\" data-id=\"57f56dc\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<ul><li><strong>C\u00e0i \u0111\u1eb7t Redis:<\/strong> K\u1ebft n\u1ed1i \u0111\u1ebfn Redis v\u00e0 x\u1eed l\u00fd c\u00e1c l\u1ed7i k\u1ebft n\u1ed1i.<\/li><li><strong>T\u1ea1o token:<\/strong> H\u00e0m <code>generateToken<\/code> t\u1ea1o JWT cho ng\u01b0\u1eddi d\u00f9ng v\u1edbi th\u1eddi gian h\u1ebft h\u1ea1n l\u00e0 1 gi\u1edd.<\/li><li><strong>Middleware ki\u1ec3m tra JWT:<\/strong> Middleware <code>authenticateJWT<\/code> s\u1ebd ki\u1ec3m tra xem token c\u00f3 t\u1ed3n t\u1ea1i trong Redis kh\u00f4ng. N\u1ebfu c\u00f3, ngh\u0129a l\u00e0 token \u0111\u00e3 b\u1ecb thu h\u1ed3i v\u00e0 s\u1ebd tr\u1ea3 v\u1ec1 l\u1ed7i 401. N\u1ebfu kh\u00f4ng, n\u00f3 s\u1ebd x\u00e1c th\u1ef1c token v\u00e0 ti\u1ebfp t\u1ee5c x\u1eed l\u00fd y\u00eau c\u1ea7u.<\/li><li><strong>\u0110\u0103ng xu\u1ea5t:<\/strong> Khi ng\u01b0\u1eddi d\u00f9ng \u0111\u0103ng xu\u1ea5t, token s\u1ebd \u0111\u01b0\u1ee3c th\u00eam v\u00e0o Redis blacklist v\u1edbi th\u1eddi gian s\u1ed1ng (TTL) l\u00e0 1 gi\u1edd.<\/li><li><strong>Route b\u1ea3o v\u1ec7:<\/strong> Route <code>\/protected<\/code> s\u1ebd ch\u1ec9 cho ph\u00e9p truy c\u1eadp n\u1ebfu token l\u00e0 h\u1ee3p l\u1ec7 v\u00e0 kh\u00f4ng n\u1eb1m trong blacklist.<\/li><\/ul>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3dc88c8 elementor-widget elementor-widget-heading\" data-id=\"3dc88c8\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\"><span class=\"ez-toc-section\" id=\"Ket_luan\"><\/span>K\u1ebft lu\u1eadn<span class=\"ez-toc-section-end\"><\/span><\/h2>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0ed0bf0 elementor-widget elementor-widget-text-editor\" data-id=\"0ed0bf0\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Vi\u1ec7c x\u00e1c th\u1ef1c JWT trong Node.js k\u1ebft h\u1ee3p v\u1edbi Redis \u0111\u1ec3 qu\u1ea3n l\u00fd blacklist mang l\u1ea1i m\u1ed9t ph\u01b0\u01a1ng ph\u00e1p b\u1ea3o m\u1eadt hi\u1ec7u qu\u1ea3 cho \u1ee9ng d\u1ee5ng c\u1ee7a b\u1ea1n. N\u00f3 kh\u00f4ng ch\u1ec9 gi\u00fap ki\u1ec3m so\u00e1t quy\u1ec1n truy c\u1eadp m\u00e0 c\u00f2n b\u1ea3o v\u1ec7 t\u00e0i nguy\u00ean c\u1ee7a b\u1ea1n kh\u1ecfi c\u00e1c token kh\u00f4ng h\u1ee3p l\u1ec7. H\u00e3y \u00e1p d\u1ee5ng c\u00e1ch ti\u1ebfp c\u1eadn n\u00e0y \u0111\u1ec3 n\u00e2ng cao m\u1ee9c \u0111\u1ed9 b\u1ea3o m\u1eadt cho \u1ee9ng d\u1ee5ng c\u1ee7a b\u1ea1n!<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Trong b\u1ed1i c\u1ea3nh b\u1ea3o m\u1eadt \u1ee9ng d\u1ee5ng web ng\u00e0y nay, vi\u1ec7c x\u00e1c th\u1ef1c ng\u01b0\u1eddi d\u00f9ng v\u00e0 qu\u1ea3n l\u00fd quy\u1ec1n truy c\u1eadp l\u00e0 r\u1ea5t quan tr\u1ecdng. JSON Web Tokens (JWT) \u0111\u00e3 tr\u1edf th\u00e0nh m\u1ed9t ph\u01b0\u01a1ng ph\u00e1p ph\u1ed5 bi\u1ebfn \u0111\u1ec3 th\u1ef1c hi\u1ec7n x\u00e1c th\u1ef1c. Tuy nhi\u00ean, khi s\u1eed d\u1ee5ng JWT, c\u00f3 m\u1ed9t v\u1ea5n \u0111\u1ec1 ph\u00e1t sinh li\u00ean [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":2615,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[56],"class_list":["post-2625","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cong-nghe","tag-backend-developer"],"acf":[],"jetpack_featured_media_url":"https:\/\/fstack.io.vn\/blog\/wp-content\/uploads\/2024\/10\/revoking-access-with-a-jwt-blacklist.png","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/fstack.io.vn\/blog\/wp-json\/wp\/v2\/posts\/2625","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fstack.io.vn\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fstack.io.vn\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fstack.io.vn\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fstack.io.vn\/blog\/wp-json\/wp\/v2\/comments?post=2625"}],"version-history":[{"count":7,"href":"https:\/\/fstack.io.vn\/blog\/wp-json\/wp\/v2\/posts\/2625\/revisions"}],"predecessor-version":[{"id":2633,"href":"https:\/\/fstack.io.vn\/blog\/wp-json\/wp\/v2\/posts\/2625\/revisions\/2633"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/fstack.io.vn\/blog\/wp-json\/wp\/v2\/media\/2615"}],"wp:attachment":[{"href":"https:\/\/fstack.io.vn\/blog\/wp-json\/wp\/v2\/media?parent=2625"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fstack.io.vn\/blog\/wp-json\/wp\/v2\/categories?post=2625"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fstack.io.vn\/blog\/wp-json\/wp\/v2\/tags?post=2625"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}