{"id":90561,"date":"2025-10-05T17:36:38","date_gmt":"2025-10-05T10:36:38","guid":{"rendered":"https:\/\/itviec.com\/blog\/?p=90561"},"modified":"2025-10-31T11:27:26","modified_gmt":"2025-10-31T04:27:26","slug":"spring-security-la-gi","status":"publish","type":"post","link":"https:\/\/itviec.com\/blog\/spring-security-la-gi\/","title":{"rendered":"Spring security: Kh\u00e1m ph\u00e1 framework b\u1ea3o m\u1eadt h\u00e0ng \u0111\u1ea7u cho \u1ee9ng d\u1ee5ng Java"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_84 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\">N\u1ed9i dung 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:\/\/itviec.com\/blog\/spring-security-la-gi\/#Spring_Security_la_gi_Ai_nen_hoc_Spring_Security\" >Spring Security l\u00e0 g\u00ec? Ai n\u00ean h\u1ecdc Spring Security?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/itviec.com\/blog\/spring-security-la-gi\/#Uu_va_nhuoc_diem_cua_Spring_Security\" >\u01afu v\u00e0 nh\u01b0\u1ee3c \u0111i\u1ec3m c\u1ee7a Spring Security<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/itviec.com\/blog\/spring-security-la-gi\/#Cac_khai_niem_cot_loi_cua_Spring_Security\" >C\u00e1c kh\u00e1i ni\u1ec7m c\u1ed1t l\u00f5i c\u1ee7a Spring Security<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/itviec.com\/blog\/spring-security-la-gi\/#Cac_buoc_co_ban_xay_dung_ung_dung_voi_Spring_Security\" >C\u00e1c b\u01b0\u1edbc c\u01a1 b\u1ea3n x\u00e2y d\u1ef1ng \u1ee9ng d\u1ee5ng v\u1edbi Spring Security&nbsp;<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/itviec.com\/blog\/spring-security-la-gi\/#Cac_chu_de_nang_cao_cua_Spring_Security\" >C\u00e1c ch\u1ee7 \u0111\u1ec1 n\u00e2ng cao c\u1ee7a Spring Security<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/itviec.com\/blog\/spring-security-la-gi\/#Cac_cau_hoi_thuong_gap_ve_Spring_Security\" >C\u00e1c c\u00e2u h\u1ecfi th\u01b0\u1eddng g\u1eb7p v\u1ec1 Spring Security<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/itviec.com\/blog\/spring-security-la-gi\/#Tong_ket\" >T\u1ed5ng k\u1ebft<\/a><\/li><\/ul><\/nav><\/div>\n\n<p><strong><em>B\u1ea3o m\u1eadt l\u00e0 y\u1ebfu t\u1ed1 c\u1ef1c k\u1ef3 quan tr\u1ecdng c\u1ee7a c\u00e1c \u1ee9ng d\u1ee5ng web \u0111\u1ec3 tr\u00e1nh c\u00e1c r\u1ee7i ro nh\u01b0 r\u00f2 r\u1ec9 d\u1eef li\u1ec7u hay b\u1ecb t\u1ea5n c\u00f4ng. B\u00e0i vi\u1ebft n\u00e0y s\u1ebd h\u01b0\u1edbng d\u1eabn b\u1ea1n hi\u1ec3u v\u1ec1 Spring Security, framework b\u1ea3o m\u1eadt h\u00e0ng \u0111\u1ea7u cho Java, t\u1eeb c\u00e1c kh\u00e1i ni\u1ec7m c\u1ed1t l\u00f5i nh\u01b0 X\u00e1c th\u1ef1c (Authentication) v\u00e0 Ph\u00e2n quy\u1ec1n (Authorization) \u0111\u1ebfn v\u00ed d\u1ee5 th\u1ef1c t\u1ebf, gi\u00fap b\u1ea1n t\u1ef1 tin x\u00e2y d\u1ef1ng \u1ee9ng d\u1ee5ng an to\u00e0n.<\/em><\/strong><\/p>\n\n\n\n<p>\u0110\u1ecdc b\u00e0i vi\u1ebft n\u00e0y \u0111\u1ec3 hi\u1ec3u th\u00eam v\u1ec1:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>C\u00e1c kh\u00e1i ni\u1ec7m c\u1ed1t l\u00f5i trong Spring Security&nbsp;<\/li>\n\n\n\n<li>C\u00e1ch x\u00e2y d\u1ef1ng \u1ee9ng d\u1ee5ng v\u1edbi Spring Security<\/li>\n\n\n\n<li>C\u00e1c ch\u1ee7 \u0111\u1ec1 Spring Security n\u00e2ng cao<\/li>\n\n\n\n<li>C\u00e1c c\u00e2u h\u1ecfi th\u01b0\u1eddng g\u1eb7p v\u1ec1 Spring Security<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-spring-security-la-gi-ai-nen-h\u1ecdc-spring-security\"><span class=\"ez-toc-section\" id=\"Spring_Security_la_gi_Ai_nen_hoc_Spring_Security\"><\/span><strong>Spring Security l\u00e0 g\u00ec? Ai n\u00ean h\u1ecdc Spring Security?<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p><strong>Spring Security<\/strong> l\u00e0 m\u1ed9t framework m\u1ea1nh m\u1ebd v\u00e0 c\u1ef1c k\u1ef3 linh ho\u1ea1t \u0111\u1ec3 b\u1ea3o m\u1eadt c\u00e1c \u1ee9ng d\u1ee5ng Java \u0111\u01b0\u1ee3c x\u00e2y d\u1ef1ng tr\u00ean Spring Framework. N\u00f3 cung c\u1ea5p m\u1ed9t gi\u1ea3i ph\u00e1p to\u00e0n di\u1ec7n cho c\u1ea3 vi\u1ec7c x\u00e1c th\u1ef1c (Authentication) v\u00e0 ph\u00e2n quy\u1ec1n (Authorization).<\/p>\n\n\n\n<p>Trong h\u1ec7 sinh th\u00e1i Spring, Spring Security \u0111\u01b0\u1ee3c xem l\u00e0 gi\u1ea3i ph\u00e1p b\u1ea3o m\u1eadt ti\u00eau chu\u1ea9n v\u00e0 \u0111\u01b0\u1ee3c s\u1eed d\u1ee5ng v\u00f4 c\u00f9ng r\u1ed9ng r\u00e3i. Do s\u1ef1 t\u00edch h\u1ee3p s\u00e2u v\u00e0 ch\u1eb7t ch\u1ebd v\u1edbi Spring, n\u00f3 \u0111\u00e3 tr\u1edf th\u00e0nh l\u1ef1a ch\u1ecdn h\u00e0ng \u0111\u1ea7u cho h\u1ea7u h\u1ebft c\u00e1c d\u1ef1 \u00e1n t\u1eeb nh\u1ecf \u0111\u1ebfn l\u1edbn. B\u1ea5t k\u1ef3 l\u1eadp tr\u00ecnh vi\u00ean <strong>Backend<\/strong> ho\u1eb7c <strong>Full-stack<\/strong> n\u00e0o l\u00e0m vi\u1ec7c v\u1edbi Java Spring \u0111\u1ec1u c\u1ea7n c\u00f3 ki\u1ebfn th\u1ee9c v\u1eefng ch\u1eafc v\u1ec1 Spring Security. Ngo\u00e0i ra, c\u00e1c v\u1ecb tr\u00ed nh\u01b0 <strong>DevOps Engineer<\/strong> hay <strong>Security Engineer<\/strong> c\u0169ng c\u1ea7n hi\u1ec3u r\u00f5 v\u1ec1 n\u00f3 \u0111\u1ec3 c\u00f3 th\u1ec3 c\u1ea5u h\u00ecnh v\u00e0 v\u1eadn h\u00e0nh h\u1ec7 th\u1ed1ng m\u1ed9t c\u00e1ch an to\u00e0n.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><em>\u0110\u1ecdc chi ti\u1ebft: <strong><a href=\"https:\/\/itviec.com\/blog\/spring-java-la-gi\/\" target=\"_blank\" rel=\"noreferrer noopener\">Spring Java l\u00e0 g\u00ec: H\u01b0\u1edbng d\u1eabn chi ti\u1ebft c\u00e1ch b\u1eaft \u0111\u1ea7u v\u1edbi Spring<\/a><\/strong><\/em><\/p>\n<\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-\u01b0u-va-nh\u01b0\u1ee3c-di\u1ec3m-c\u1ee7a-spring-security\"><span class=\"ez-toc-section\" id=\"Uu_va_nhuoc_diem_cua_Spring_Security\"><\/span><strong>\u01afu v\u00e0 nh\u01b0\u1ee3c \u0111i\u1ec3m c\u1ee7a Spring Security<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-\u01b0u-di\u1ec3m-c\u1ee7a-spring-security\"><strong>\u01afu \u0111i\u1ec3m c\u1ee7a Spring Security<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>To\u00e0n di\u1ec7n v\u00e0 m\u1ea1nh m\u1ebd<\/strong>:&nbsp; Cung c\u1ea5p \u0111\u1ea7y \u0111\u1ee7 c\u00e1c t\u00ednh n\u0103ng b\u1ea3o m\u1eadt t\u1eeb c\u01a1 b\u1ea3n \u0111\u1ebfn n\u00e2ng cao (ch\u1ed1ng CSRF, OAuth2\/OIDC, SAML&#8230;).<\/li>\n\n\n\n<li><strong>T\u00edch h\u1ee3p s\u00e2u v\u1edbi h\u1ec7 sinh th\u00e1i Spring:<\/strong> Ho\u1ea1t \u0111\u1ed9ng li\u1ec1n m\u1ea1ch v\u1edbi c\u00e1c d\u1ef1 \u00e1n Spring Boot, Spring MVC, WebFlux&#8230;<\/li>\n\n\n\n<li><strong>Linh ho\u1ea1t v\u00e0 t\u00f9y bi\u1ebfn cao:<\/strong> H\u1ea7u h\u1ebft m\u1ecdi th\u00e0nh ph\u1ea7n m\u1eb7c \u0111\u1ecbnh \u0111\u1ec1u c\u00f3 th\u1ec3 \u0111\u01b0\u1ee3c thay th\u1ebf ho\u1eb7c m\u1edf r\u1ed9ng \u0111\u1ec3 \u0111\u00e1p \u1ee9ng y\u00eau c\u1ea7u nghi\u1ec7p v\u1ee5.<\/li>\n\n\n\n<li><strong>C\u1ed9ng \u0111\u1ed3ng l\u1edbn v\u00e0 t\u00e0i li\u1ec7u \u0111\u1ea7y \u0111\u1ee7:<\/strong> D\u1ec5 d\u00e0ng t\u00ecm ki\u1ebfm s\u1ef1 h\u1ed7 tr\u1ee3, c\u00e1c b\u00e0i h\u01b0\u1edbng d\u1eabn v\u00e0 gi\u1ea3i ph\u00e1p cho c\u00e1c v\u1ea5n \u0111\u1ec1 th\u01b0\u1eddng g\u1eb7p.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-nh\u01b0\u1ee3c-di\u1ec3m-c\u1ee7a-spring-security\"><strong>Nh\u01b0\u1ee3c \u0111i\u1ec3m c\u1ee7a Spring Security<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u0110\u1ed9 ph\u1ee9c t\u1ea1p cao:<\/strong> Ki\u1ebfn tr\u00fac d\u1ef1a tr\u00ean Filter Chain v\u00e0 s\u1ed1 l\u01b0\u1ee3ng l\u1edbp c\u1ea5u h\u00ecnh c\u00f3 th\u1ec3 g\u00e2y b\u1ed1i r\u1ed1i cho ng\u01b0\u1eddi m\u1edbi b\u1eaft \u0111\u1ea7u.<\/li>\n\n\n\n<li><strong>C\u1ea5u h\u00ecnh d\u00e0i d\u00f2ng:<\/strong> M\u1eb7c d\u00f9 \u0111\u00e3 c\u1ea3i thi\u1ec7n, vi\u1ec7c c\u1ea5u h\u00ecnh cho c\u00e1c k\u1ecbch b\u1ea3n ph\u1ee9c t\u1ea1p v\u1eabn c\u00f3 th\u1ec3 y\u00eau c\u1ea7u nhi\u1ec1u m\u00e3 l\u1ec7nh.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-so-sanh-spring-security-vs-apache-shiro\"><strong>So s\u00e1nh Spring Security vs <\/strong><a href=\"https:\/\/shiro.apache.org\/\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>Apache Shiro<\/strong><\/a><\/h3>\n\n\n\n<p>Shiro th\u01b0\u1eddng \u0111\u01b0\u1ee3c xem l\u00e0 \u0111\u01a1n gi\u1ea3n v\u00e0 d\u1ec5 h\u1ecdc h\u01a1n, ph\u00f9 h\u1ee3p cho c\u00e1c \u1ee9ng d\u1ee5ng c\u00f3 y\u00eau c\u1ea7u b\u1ea3o m\u1eadt kh\u00f4ng qu\u00e1 ph\u1ee9c t\u1ea1p. Tuy nhi\u00ean, Spring Security m\u1ea1nh m\u1ebd h\u01a1n, nhi\u1ec1u t\u00ednh n\u0103ng h\u01a1n v\u00e0 \u0111\u01b0\u1ee3c h\u1ed7 tr\u1ee3 t\u1ed1t h\u01a1n trong h\u1ec7 sinh th\u00e1i Spring.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-so-sanh-spring-security-v\u1edbi-cac-nha-cung-c\u1ea5p-d\u1ecbnh-danh-identity-providers-nh\u01b0-keycloak-okta\"><strong>So s\u00e1nh Spring Security v\u1edbi c\u00e1c nh\u00e0 cung c\u1ea5p \u0111\u1ecbnh danh (Identity Providers) nh\u01b0 <\/strong><a href=\"https:\/\/www.keycloak.org\/\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>Keycloak<\/strong><\/a><strong>, <\/strong><a href=\"https:\/\/www.okta.com\/\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>Okta<\/strong><\/a><strong>&nbsp;<\/strong><\/h3>\n\n\n\n<p>\u0110\u00e2y kh\u00f4ng ph\u1ea3i l\u00e0 \u0111\u1ed1i th\u1ee7 tr\u1ef1c ti\u1ebfp m\u00e0 l\u00e0 c\u00e1c gi\u1ea3i ph\u00e1p b\u1ed5 tr\u1ee3. Keycloak\/Okta qu\u1ea3n l\u00fd danh t\u00ednh t\u1eadp trung, trong khi Spring Security \u0111\u00f3ng vai tr\u00f2 l\u00e0 &#8220;c\u1ea3nh s\u00e1t&#8221; b\u1ea3o v\u1ec7 \u1ee9ng d\u1ee5ng v\u00e0 t\u00edch h\u1ee3p v\u1edbi c\u00e1c nh\u00e0 cung c\u1ea5p n\u00e0y th\u00f4ng qua c\u00e1c giao th\u1ee9c nh\u01b0 OAuth2\/OIDC.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-cac-khai-ni\u1ec7m-c\u1ed1t-loi-c\u1ee7a-spring-security\"><span class=\"ez-toc-section\" id=\"Cac_khai_niem_cot_loi_cua_Spring_Security\"><\/span><strong>C\u00e1c kh\u00e1i ni\u1ec7m c\u1ed1t l\u00f5i c\u1ee7a Spring Security<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>\u0110\u1ec3 s\u1eed d\u1ee5ng Spring Security hi\u1ec7u qu\u1ea3, tr\u01b0\u1edbc ti\u00ean ch\u00fang ta c\u1ea7n hi\u1ec3u r\u00f5 c\u00e1c th\u00e0nh ph\u1ea7n c\u1ea5u th\u00e0nh n\u00ean ki\u1ebfn tr\u00fac c\u1ee7a n\u00f3. \u0110\u00e2y l\u00e0 nh\u1eefng kh\u00e1i ni\u1ec7m n\u1ec1n t\u1ea3ng, quy\u1ebft \u0111\u1ecbnh c\u00e1ch lu\u1ed3ng b\u1ea3o m\u1eadt \u0111\u01b0\u1ee3c x\u1eed l\u00fd trong \u1ee9ng d\u1ee5ng c\u1ee7a b\u1ea1n.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-authentication-xac-th\u1ef1c\"><strong>Authentication (X\u00e1c th\u1ef1c)<\/strong><\/h3>\n\n\n\n<p><strong>Authentication<\/strong> l\u00e0 qu\u00e1 tr\u00ecnh x\u00e1c \u0111\u1ecbnh v\u00e0 x\u00e1c minh danh t\u00ednh c\u1ee7a m\u1ed9t ch\u1ee7 th\u1ec3 (user ho\u1eb7c h\u1ec7 th\u1ed1ng) \u0111ang c\u1ed1 g\u1eafng truy c\u1eadp v\u00e0o \u1ee9ng d\u1ee5ng.&nbsp;<\/p>\n\n\n\n<p>Trong th\u1ef1c t\u1ebf, qu\u00e1 tr\u00ecnh n\u00e0y th\u01b0\u1eddng li\u00ean quan \u0111\u1ebfn vi\u1ec7c ki\u1ec3m tra c\u00e1c th\u00f4ng tin x\u00e1c th\u1ef1c (credentials) m\u00e0 ch\u1ee7 th\u1ec3 cung c\u1ea5p. V\u00ed d\u1ee5 ph\u1ed5 bi\u1ebfn nh\u1ea5t l\u00e0 ki\u1ec3m tra s\u1ef1 tr\u00f9ng kh\u1edbp c\u1ee7a username v\u00e0 password v\u1edbi d\u1eef li\u1ec7u \u0111\u01b0\u1ee3c l\u01b0u trong c\u01a1 s\u1edf d\u1eef li\u1ec7u. C\u00e1c c\u01a1 ch\u1ebf kh\u00e1c bao g\u1ed3m x\u00e1c th\u1ef1c th\u00f4ng qua JWT (JSON Web Tokens), OAuth2, ho\u1eb7c c\u00e1c nh\u00e0 cung c\u1ea5p \u0111\u1ecbnh danh b\u00ean ngo\u00e0i.<\/p>\n\n\n\n<p>Khi x\u00e1c th\u1ef1c th\u00e0nh c\u00f4ng, Spring Security s\u1ebd t\u1ea1o ra m\u1ed9t \u0111\u1ed1i t\u01b0\u1ee3ng Authentication ch\u1ee9a \u0111\u1ea7y \u0111\u1ee7 th\u00f4ng tin c\u1ee7a ch\u1ee7 th\u1ec3 v\u00e0 \u0111\u00e1nh d\u1ea5u l\u00e0 \u0111\u00e3 \u0111\u01b0\u1ee3c x\u00e1c th\u1ef1c.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-authorization-phan-quy\u1ec1n\"><strong>Authorization (Ph\u00e2n quy\u1ec1n)<\/strong><\/h3>\n\n\n\n<p><strong>Authorization<\/strong> l\u00e0 qu\u00e1 tr\u00ecnh di\u1ec5n ra sau khi m\u1ed9t ch\u1ee7 th\u1ec3 \u0111\u00e3 \u0111\u01b0\u1ee3c x\u00e1c th\u1ef1c th\u00e0nh c\u00f4ng.&nbsp;<\/p>\n\n\n\n<p>N\u00f3 quy\u1ebft \u0111\u1ecbnh xem ch\u1ee7 th\u1ec3 \u0111\u00f3 c\u00f3 \u0111\u01b0\u1ee3c ph\u00e9p th\u1ef1c hi\u1ec7n m\u1ed9t h\u00e0nh \u0111\u1ed9ng c\u1ee5 th\u1ec3 ho\u1eb7c truy c\u1eadp m\u1ed9t t\u00e0i nguy\u00ean nh\u1ea5t \u0111\u1ecbnh hay kh\u00f4ng. M\u1ee5c ti\u00eau c\u1ee7a n\u00f3 l\u00e0 tr\u1ea3 l\u1eddi c\u00e2u h\u1ecfi: &#8220;Ch\u1ee7 th\u1ec3 n\u00e0y c\u00f3 quy\u1ec1n l\u00e0m vi\u1ec7c n\u00e0y kh\u00f4ng?&#8221;.<\/p>\n\n\n\n<p>V\u00ed d\u1ee5, m\u1ed9t ng\u01b0\u1eddi d\u00f9ng \u0111\u00e3 x\u00e1c th\u1ef1c v\u1edbi vai tr\u00f2 <code>USER<\/code> c\u00f3 th\u1ec3 \u0111\u01b0\u1ee3c c\u1ea5p quy\u1ec1n \u0111\u1ecdc danh s\u00e1ch s\u1ea3n ph\u1ea9m (<code>GET<\/code>\/<code>api<\/code>\/<code>products<\/code>), nh\u01b0ng s\u1ebd b\u1ecb t\u1eeb ch\u1ed1i khi c\u1ed1 g\u1eafng truy c\u1eadp v\u00e0o trang qu\u1ea3n tr\u1ecb (<code>GET <\/code>\/<code>api<\/code>\/<code>admin<\/code>). Vi\u1ec7c ki\u1ec3m tra quy\u1ec1n h\u1ea1n n\u00e0y ch\u00ednh l\u00e0 Authorization.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-principal\"><strong>Principal<\/strong><\/h3>\n\n\n\n<p><strong>Principal<\/strong> l\u00e0 m\u1ed9t \u0111\u1ed1i t\u01b0\u1ee3ng \u0111\u1ea1i di\u1ec7n cho ch\u1ee7 th\u1ec3 \u0111\u00e3 \u0111\u01b0\u1ee3c x\u00e1c th\u1ef1c. Sau khi qu\u00e1 tr\u00ecnh Authentication th\u00e0nh c\u00f4ng, th\u00f4ng tin v\u1ec1 ng\u01b0\u1eddi d\u00f9ng (nh\u01b0 username ho\u1eb7c m\u1ed9t \u0111\u1ed1i t\u01b0\u1ee3ng <code>UserDetails<\/code> ch\u1ee9a \u0111\u1ea7y \u0111\u1ee7 th\u00f4ng tin) \u0111\u01b0\u1ee3c g\u00f3i g\u1ecdn trong m\u1ed9t Principal. \u0110\u1ed1i t\u01b0\u1ee3ng n\u00e0y c\u00f3 th\u1ec3 \u0111\u01b0\u1ee3c truy xu\u1ea5t \u1edf b\u1ea5t k\u1ef3 \u0111\u00e2u trong \u1ee9ng d\u1ee5ng \u0111\u1ec3 l\u1ea5y th\u00f4ng tin v\u1ec1 ng\u01b0\u1eddi d\u00f9ng hi\u1ec7n t\u1ea1i c\u1ee7a phi\u00ean l\u00e0m vi\u1ec7c \u0111\u00f3.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-grantedauthority\"><strong>GrantedAuthority<\/strong><\/h3>\n\n\n\n<p><strong>GrantedAuthority<\/strong> l\u00e0 m\u1ed9t \u0111\u1ed1i t\u01b0\u1ee3ng \u0111\u1ea1i di\u1ec7n cho m\u1ed9t quy\u1ec1n h\u1ea1n duy nh\u1ea5t \u0111\u01b0\u1ee3c c\u1ea5p cho Principal. V\u1ec1 c\u01a1 b\u1ea3n, n\u00f3 l\u00e0 m\u1ed9t quy\u1ec1n (permission) \u0111\u01b0\u1ee3c bi\u1ec3u di\u1ec5n d\u01b0\u1edbi d\u1ea1ng chu\u1ed7i k\u00fd t\u1ef1. Theo quy \u01b0\u1edbc, c\u00e1c quy\u1ec1n h\u1ea1n li\u00ean quan \u0111\u1ebfn vai tr\u00f2 ng\u01b0\u1eddi d\u00f9ng th\u01b0\u1eddng c\u00f3 ti\u1ec1n t\u1ed1 <code>ROLE_ <\/code>(v\u00ed d\u1ee5: <code>ROLE_ADMIN, ROLE_MANAGER<\/code>). Ngo\u00e0i ra, n\u00f3 c\u0169ng c\u00f3 th\u1ec3 \u0111\u1ea1i di\u1ec7n cho c\u00e1c quy\u1ec1n chi ti\u1ebft h\u01a1n nh\u01b0 product:read ho\u1eb7c user:delete.<\/p>\n\n\n\n<p>M\u1ed9t Principal s\u1ebd c\u00f3 m\u1ed9t t\u1eadp h\u1ee3p c\u00e1c <code>GrantedAuthority<\/code>, v\u00e0 t\u1eadp h\u1ee3p n\u00e0y \u0111\u01b0\u1ee3c s\u1eed d\u1ee5ng trong qu\u00e1 tr\u00ecnh Authorization \u0111\u1ec3 quy\u1ebft \u0111\u1ecbnh quy\u1ec1n truy c\u1eadp.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-securitycontextholder\"><strong>SecurityContextHolder<\/strong><\/h3>\n\n\n\n<p><strong>SecurityContextHolder<\/strong> l\u00e0 m\u1ed9t th\u00e0nh ph\u1ea7n c\u1ed1t l\u00f5i c\u1ee7a Spring Security, c\u00f3 nhi\u1ec7m v\u1ee5 l\u01b0u tr\u1eef <code>SecurityContext<\/code>. Theo m\u1eb7c \u0111\u1ecbnh, <code>SecurityContextHolder<\/code> s\u1eed d\u1ee5ng m\u1ed9t \u0111\u1ed1i t\u01b0\u1ee3ng <code>ThreadLocal<\/code> \u0111\u1ec3 l\u01b0u tr\u1eef context, \u0111i\u1ec1u n\u00e0y c\u00f3 ngh\u0129a l\u00e0 context b\u1ea3o m\u1eadt s\u1ebd lu\u00f4n c\u00f3 s\u1eb5n cho lu\u1ed3ng x\u1eed l\u00fd c\u1ee7a request hi\u1ec7n t\u1ea1i.<\/p>\n\n\n\n<p>B\u00ean trong <code>SecurityContext<\/code> l\u00e0 \u0111\u1ed1i t\u01b0\u1ee3ng <code>Authentication<\/code> (ch\u1ee9a Principal v\u00e0 c\u00e1c GrantedAuthority). B\u1eb1ng c\u00e1ch truy c\u1eadp <code>SecurityContextHolder<\/code>, ch\u00fang ta c\u00f3 th\u1ec3 l\u1ea5y \u0111\u01b0\u1ee3c th\u00f4ng tin c\u1ee7a ng\u01b0\u1eddi d\u00f9ng \u0111ang \u0111\u0103ng nh\u1eadp \u1edf b\u1ea5t k\u1ef3 l\u1edbp (Service, Controller) n\u00e0o trong \u1ee9ng d\u1ee5ng.<\/p>\n\n\n\n<p>V\u00ed d\u1ee5:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ V\u00ed d\u1ee5 truy xu\u1ea5t username c\u1ee7a ng\u01b0\u1eddi d\u00f9ng hi\u1ec7n t\u1ea1i\nAuthentication authentication = SecurityContextHolder.getContext().getAuthentication();\nString currentPrincipalName = authentication.getName();<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-filters-va-filter-chain\"><strong>Filters v\u00e0 Filter Chain<\/strong><\/h3>\n\n\n\n<p>Ki\u1ebfn tr\u00fac c\u1ee7a Spring Security trong c\u00e1c \u1ee9ng d\u1ee5ng web \u0111\u01b0\u1ee3c x\u00e2y d\u1ef1ng d\u1ef1a tr\u00ean m\u1ed9t chu\u1ed7i c\u00e1c b\u1ed9 l\u1ecdc servlet (Servlet Filters), \u0111\u01b0\u1ee3c g\u1ecdi l\u00e0 <strong>Filter Chain<\/strong>. M\u1ecdi request HTTP g\u1eedi \u0111\u1ebfn \u1ee9ng d\u1ee5ng tr\u01b0\u1edbc ti\u00ean s\u1ebd \u0111\u01b0\u1ee3c ch\u1eb7n l\u1ea1i v\u00e0 \u0111i qua chu\u1ed7i b\u1ed9 l\u1ecdc n\u00e0y.<\/p>\n\n\n\n<p>M\u1ed7i <code>Filter<\/code> trong chu\u1ed7i c\u00f3 m\u1ed9t tr\u00e1ch nhi\u1ec7m c\u1ee5 th\u1ec3 v\u00e0 \u0111\u01b0\u1ee3c s\u1eafp x\u1ebfp theo m\u1ed9t th\u1ee9 t\u1ef1 \u01b0u ti\u00ean nh\u1ea5t \u0111\u1ecbnh. V\u00ed d\u1ee5 v\u1ec1 c\u00e1c filter quan tr\u1ecdng:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>CsrfFilter<\/strong>: \u00c1p d\u1ee5ng c\u01a1 ch\u1ebf ch\u1ed1ng t\u1ea5n c\u00f4ng CSRF.<\/li>\n\n\n\n<li><strong>UsernamePasswordAuthenticationFilter<\/strong>: Ch\u1eb7n c\u00e1c request \u0111\u1ebfn URL \u0111\u0103ng nh\u1eadp, tr\u00edch xu\u1ea5t username\/password v\u00e0 ti\u1ebfn h\u00e0nh x\u00e1c th\u1ef1c.<\/li>\n\n\n\n<li><strong>AuthorizationFilter<\/strong>: Ch\u1eb7n c\u00e1c request \u0111\u1ebfn c\u00e1c t\u00e0i nguy\u00ean \u0111\u01b0\u1ee3c b\u1ea3o v\u1ec7 v\u00e0 quy\u1ebft \u0111\u1ecbnh xem ng\u01b0\u1eddi d\u00f9ng c\u00f3 \u0111\u1ee7 quy\u1ec1n truy c\u1eadp hay kh\u00f4ng d\u1ef1a tr\u00ean c\u00e1c <code>GrantedAuthority<\/code> c\u1ee7a h\u1ecd.<\/li>\n<\/ul>\n\n\n\n<p>Request s\u1ebd \u0111i l\u1ea7n l\u01b0\u1ee3t qua t\u1eebng filter trong chu\u1ed7i. N\u1ebfu m\u1ed9t filter n\u00e0o \u0111\u00f3 quy\u1ebft \u0111\u1ecbnh r\u1eb1ng request kh\u00f4ng h\u1ee3p l\u1ec7 (v\u00ed d\u1ee5: x\u00e1c th\u1ef1c th\u1ea5t b\u1ea1i ho\u1eb7c kh\u00f4ng \u0111\u1ee7 quy\u1ec1n), n\u00f3 s\u1ebd ch\u1eb7n request v\u00e0 tr\u1ea3 v\u1ec1 l\u1ed7i ngay l\u1eadp t\u1ee9c m\u00e0 kh\u00f4ng c\u1ea7n \u0111i ti\u1ebfp \u0111\u1ebfn c\u00e1c filter sau ho\u1eb7c \u0111\u1ebfn Controller c\u1ee7a \u1ee9ng d\u1ee5ng.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-cac-b\u01b0\u1edbc-c\u01a1-b\u1ea3n-xay-d\u1ef1ng-\u1ee9ng-d\u1ee5ng-v\u1edbi-spring-security-nbsp\"><span class=\"ez-toc-section\" id=\"Cac_buoc_co_ban_xay_dung_ung_dung_voi_Spring_Security\"><\/span><strong>C\u00e1c b\u01b0\u1edbc c\u01a1 b\u1ea3n x\u00e2y d\u1ef1ng \u1ee9ng d\u1ee5ng v\u1edbi Spring Security&nbsp;<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-b\u01b0\u1edbc-1-kh\u1edfi-t\u1ea1o-d\u1ef1-an-spring-boot\"><strong>B\u01b0\u1edbc 1: Kh\u1edfi t\u1ea1o d\u1ef1 \u00e1n Spring Boot<\/strong><\/h3>\n\n\n\n<p>C\u00e1ch nhanh nh\u1ea5t \u0111\u1ec3 b\u1eaft \u0111\u1ea7u m\u1ed9t d\u1ef1 \u00e1n Spring Boot l\u00e0 s\u1eed d\u1ee5ng <strong>Spring Initializr<\/strong>.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Truy c\u1eadp trang <a href=\"https:\/\/start.spring.io\" target=\"_blank\" rel=\"noreferrer noopener\">start.spring.io<\/a>.<\/li>\n\n\n\n<li>Thi\u1ebft l\u1eadp th\u00f4ng tin d\u1ef1 \u00e1n:\n<ul class=\"wp-block-list\">\n<li><strong>Project<\/strong>: Maven (ho\u1eb7c Gradle t\u00f9y s\u1edf th\u00edch).<\/li>\n\n\n\n<li><strong>Language<\/strong>: Java.<\/li>\n\n\n\n<li><strong>Spring Boot<\/strong>: Ch\u1ecdn phi\u00ean b\u1ea3n \u1ed5n \u0111\u1ecbnh (kh\u00f4ng ch\u1ecdn SNAPSHOT).<\/li>\n\n\n\n<li><strong>Project Metadata<\/strong>: \u0110i\u1ec1n <code>Group<\/code>, <code>Artifact<\/code>, <code>Name<\/code>, <code>Description<\/code> theo \u00fd b\u1ea1n.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Th\u00eam c\u00e1c <strong>Dependencies<\/strong> c\u1ea7n thi\u1ebft:\n<ul class=\"wp-block-list\">\n<li><code>Spring Web<\/code>: \u0110\u1ec3 x\u00e2y d\u1ef1ng \u1ee9ng d\u1ee5ng web, t\u1ea1o c\u00e1c REST Controller.<\/li>\n\n\n\n<li><code>Thymeleaf<\/code>: M\u1ed9t template engine gi\u00fap ch\u00fang ta t\u1ea1o c\u00e1c trang view HTML \u0111\u01a1n gi\u1ea3n cho trang ch\u1ee7, trang \u0111\u0103ng nh\u1eadp.<\/li>\n\n\n\n<li><code>Spring Security<\/code>: Nh\u00e2n v\u1eadt ch\u00ednh c\u1ee7a ch\u00fang ta.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p>Sau khi \u0111i\u1ec1n xong, nh\u1ea5n n\u00fat <strong>GENERATE<\/strong> \u0111\u1ec3 t\u1ea3i file .zip c\u1ee7a d\u1ef1 \u00e1n v\u1ec1. Gi\u1ea3i n\u00e9n v\u00e0 m\u1edf d\u1ef1 \u00e1n b\u1eb1ng IDE y\u00eau th\u00edch c\u1ee7a b\u1ea1n (IntelliJ, VSCode, Eclipse,&#8230;).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-b\u01b0\u1edbc-2-c\u1ea5u-hinh-spring-security-c\u01a1-b\u1ea3n\"><strong>B\u01b0\u1edbc 2: C\u1ea5u h\u00ecnh Spring Security c\u01a1 b\u1ea3n<\/strong><\/h3>\n\n\n\n<p>\u0110i\u1ec1u k\u1ef3 di\u1ec7u \u0111\u1ea7u ti\u00ean khi b\u1ea1n th\u00eam dependency spring-boot-starter-security l\u00e0 n\u00f3 ho\u1ea1t \u0111\u1ed9ng ngay l\u1eadp t\u1ee9c m\u00e0 kh\u00f4ng c\u1ea7n m\u1ed9t d\u00f2ng code c\u1ea5u h\u00ecnh n\u00e0o.<\/p>\n\n\n\n<p>H\u00e3y th\u1eed ch\u1ea1y \u1ee9ng d\u1ee5ng ngay b\u00e2y gi\u1edd. B\u1ea1n s\u1ebd th\u1ea5y m\u1ed9t d\u00f2ng log quan tr\u1ecdng tr\u00ean console:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Using generated security password: &#91;m\u1ed9t-chu\u1ed7i-password-ng\u1eabu-nhi\u00ean]<\/code><\/pre>\n\n\n\n<p>B\u00e2y gi\u1edd, h\u00e3y truy c\u1eadp v\u00e0o <code>http:\/\/localhost:8080<\/code>. Thay v\u00ec th\u1ea5y trang l\u1ed7i 404, b\u1ea1n s\u1ebd \u0111\u01b0\u1ee3c t\u1ef1 \u0111\u1ed9ng chuy\u1ec3n h\u01b0\u1edbng \u0111\u1ebfn m\u1ed9t trang \u0111\u0103ng nh\u1eadp (<code>http:\/\/localhost:8080\/login<\/code>). \u0110\u00e2y ch\u00ednh l\u00e0 h\u00e0nh vi m\u1eb7c \u0111\u1ecbnh c\u1ee7a Spring Security: <strong>b\u1ea3o v\u1ec7 t\u1ea5t c\u1ea3 c\u00e1c endpoint v\u00e0 t\u1ef1 \u0111\u1ed9ng t\u1ea1o m\u1ed9t form \u0111\u0103ng nh\u1eadp<\/strong>.<\/p>\n\n\n\n<p>\u0110\u1ec3 \u0111\u0103ng nh\u1eadp, h\u00e3y s\u1eed d\u1ee5ng:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Username<\/strong>: <code>user<\/code><\/li>\n\n\n\n<li><strong>Password<\/strong>: chu\u1ed7i m\u1eadt kh\u1ea9u \u0111\u01b0\u1ee3c sinh ra tr\u00ean console.<\/li>\n<\/ul>\n\n\n\n<p>H\u00e0nh vi m\u1eb7c \u0111\u1ecbnh n\u00e0y r\u1ea5t ti\u1ec7n l\u1ee3i, nh\u01b0ng trong th\u1ef1c t\u1ebf, ch\u00fang ta lu\u00f4n c\u1ea7n t\u00f9y ch\u1ec9nh l\u1ea1i n\u00f3.<\/p>\n\n\n\n<p><strong>T\u1ea1o l\u1edbp c\u1ea5u h\u00ecnh<\/strong><\/p>\n\n\n\n<p>H\u00e3y t\u1ea1o m\u1ed9t l\u1edbp c\u1ea5u h\u00ecnh \u0111\u1ec3 ghi \u0111\u00e8 c\u00e1c thi\u1ebft l\u1eadp m\u1eb7c \u0111\u1ecbnh. T\u1ea1o m\u1ed9t package m\u1edbi t\u00ean l\u00e0 config v\u00e0 t\u1ea1o file <code>SecurityConfig.java <\/code>trong \u0111\u00f3.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.example.demo.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.web.SecurityFilterChain;\n\n@Configuration\n@EnableWebSecurity\npublic class SecurityConfig {\n\n    @Bean\n    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {\n        http\n            .authorizeHttpRequests(authorize -&gt; authorize\n                .requestMatchers(\"\/\", \"\/home\").permitAll() \/\/ Cho ph\u00e9p t\u1ea5t c\u1ea3 truy c\u1eadp v\u00e0o trang ch\u1ee7\n                .requestMatchers(\"\/admin\/**\").hasRole(\"ADMIN\") \/\/ Ch\u1ec9 user c\u00f3 role ADMIN m\u1edbi v\u00e0o \u0111\u01b0\u1ee3c \/admin\/**\n                .requestMatchers(\"\/profile\").hasAnyRole(\"USER\", \"ADMIN\") \/\/ C\u1ea3 USER v\u00e0 ADMIN \u0111\u1ec1u v\u00e0o \u0111\u01b0\u1ee3c \/profile\n                .anyRequest().authenticated() \/\/ T\u1ea5t c\u1ea3 c\u00e1c request kh\u00e1c \u0111\u1ec1u c\u1ea7n ph\u1ea3i x\u00e1c th\u1ef1c\n            )\n            .formLogin(formLogin -&gt; formLogin\n                .loginPage(\"\/login\") \/\/ Ch\u1ec9 \u0111\u1ecbnh trang \u0111\u0103ng nh\u1eadp t\u00f9y ch\u1ec9nh\n                .permitAll()\n            )\n            .logout(logout -&gt; logout.permitAll());\n\n        return http.build();\n    }\n}<\/code><\/pre>\n\n\n\n<p>Gi\u1ea3i th\u00edch \u0111o\u1ea1n code tr\u00ean:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>authorizeHttpRequests()<\/code>: B\u1eaft \u0111\u1ea7u c\u1ea5u h\u00ecnh c\u00e1c quy t\u1eafc ph\u00e2n quy\u1ec1n cho c\u00e1c request HTTP.<\/li>\n\n\n\n<li><code>requestMatchers(...)<\/code>: D\u00f9ng \u0111\u1ec3 ch\u1ec9 \u0111\u1ecbnh c\u00e1c m\u1eabu URL.<\/li>\n\n\n\n<li><code>permitAll()<\/code>: Cho ph\u00e9p t\u1ea5t c\u1ea3 ng\u01b0\u1eddi d\u00f9ng (k\u1ec3 c\u1ea3 ch\u01b0a \u0111\u0103ng nh\u1eadp) truy c\u1eadp.<\/li>\n\n\n\n<li><code>hasRole(\"ADMIN\")<\/code>: Y\u00eau c\u1ea7u ng\u01b0\u1eddi d\u00f9ng ph\u1ea3i c\u00f3 vai tr\u00f2 <code>ADMIN<\/code>.<\/li>\n\n\n\n<li><code>authenticated()<\/code>: Y\u00eau c\u1ea7u ng\u01b0\u1eddi d\u00f9ng ph\u1ea3i \u0111\u0103ng nh\u1eadp.<\/li>\n\n\n\n<li><code>formLogin()<\/code>: K\u00edch ho\u1ea1t v\u00e0 c\u1ea5u h\u00ecnh x\u00e1c th\u1ef1c qua form \u0111\u0103ng nh\u1eadp.<\/li>\n\n\n\n<li><code>logout()<\/code>: K\u00edch ho\u1ea1t ch\u1ee9c n\u0103ng \u0111\u0103ng xu\u1ea5t.<\/li>\n<\/ul>\n\n\n\n<p><strong>L\u01b0u \u00fd quan tr\u1ecdng:<\/strong> K\u1ec3 t\u1eeb Spring Security 5.7.0, c\u00e1ch c\u1ea5u h\u00ecnh b\u1eb1ng c\u00e1ch k\u1ebf th\u1eeba t\u1eeb <code>WebSecurityConfigurerAdapter<\/code> \u0111\u00e3 b\u1ecb deprecated (kh\u00f4ng d\u00f9ng n\u1eefa). Thay v\u00e0o \u0111\u00f3, ch\u00fang ta \u0111\u1ecbnh ngh\u0129a m\u1ed9t <strong><code>@Bean<\/code><\/strong> tr\u1ea3 v\u1ec1 ki\u1ec3u <code>SecurityFilterChain<\/code> nh\u01b0 tr\u00ean. \u0110\u00e2y l\u00e0 c\u00e1ch ti\u1ebfp c\u1eadn hi\u1ec7n \u0111\u1ea1i v\u00e0 \u0111\u01b0\u1ee3c khuy\u1ebfn kh\u00edch.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-b\u01b0\u1edbc-3-qu\u1ea3n-ly-thong-tin-ng\u01b0\u1eddi-dung\"><strong>B\u01b0\u1edbc 3: Qu\u1ea3n l\u00fd th\u00f4ng tin ng\u01b0\u1eddi d\u00f9ng<\/strong><\/h3>\n\n\n\n<p>Ng\u01b0\u1eddi d\u00f9ng user m\u1eb7c \u0111\u1ecbnh l\u00e0 kh\u00f4ng \u0111\u1ee7. Ch\u00fang ta c\u1ea7n \u0111\u1ecbnh ngh\u0129a ng\u01b0\u1eddi d\u00f9ng c\u1ee7a ri\u00eang m\u00ecnh.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"h-cach-1-in-memory-authentication-phu-h\u1ee3p-cho-demo\"><strong>C\u00e1ch 1:<\/strong> <a href=\"https:\/\/docs.spring.io\/spring-security\/reference\/servlet\/authentication\/passwords\/in-memory.html\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>In-Memory Authentication<\/strong><\/a><strong> (Ph\u00f9 h\u1ee3p cho demo)<\/strong><\/h4>\n\n\n\n<p>\u0110\u00e2y l\u00e0 c\u00e1ch nhanh nh\u1ea5t \u0111\u1ec3 t\u1ea1o ng\u01b0\u1eddi d\u00f9ng nh\u1eb1m m\u1ee5c \u0111\u00edch ki\u1ec3m th\u1eed. Ch\u00fang ta s\u1ebd \u0111\u1ecbnh ngh\u0129a th\u00f4ng tin ng\u01b0\u1eddi d\u00f9ng ngay trong b\u1ed9 nh\u1edb.<\/p>\n\n\n\n<p>Trong file <code>SecurityConfig.java<\/code>, h\u00e3y th\u00eam m\u1ed9t <code>@Bean UserDetailsService<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import org.springframework.security.core.userdetails.User;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.core.userdetails.UserDetailsService;\nimport org.springframework.security.provisioning.InMemoryUserDetailsManager;\n\n\/\/ ... b\u00ean trong l\u1edbp SecurityConfig\n\n@Bean\npublic UserDetailsService userDetailsService() {\n    UserDetails user = User.withDefaultPasswordEncoder()\n        .username(\"user\")\n        .password(\"password\")\n        .roles(\"USER\")\n        .build();\n\n    UserDetails admin = User.withDefaultPasswordEncoder()\n        .username(\"admin\")\n        .password(\"password\")\n        .roles(\"ADMIN\", \"USER\")\n        .build();\n\n    return new InMemoryUserDetailsManager(user, admin);\n}<\/code><\/pre>\n\n\n\n<p><strong>L\u01b0u \u00fd:<\/strong> withDefaultPasswordEncoder() c\u0169ng \u0111\u00e3 b\u1ecb deprecated v\u00e0 ch\u1ec9 n\u00ean d\u00f9ng cho m\u1ee5c \u0111\u00edch demo. \u1ede ph\u1ea7n sau, ch\u00fang ta s\u1ebd d\u00f9ng m\u1ed9t PasswordEncoder m\u1ea1nh h\u01a1n.<\/p>\n\n\n\n<p>B\u00e2y gi\u1edd, h\u00e3y kh\u1edfi \u0111\u1ed9ng l\u1ea1i \u1ee9ng d\u1ee5ng. B\u1ea1n c\u00f3 th\u1ec3 \u0111\u0103ng nh\u1eadp v\u1edbi user\/password ho\u1eb7c admin\/password v\u00e0 truy c\u1eadp c\u00e1c trang t\u01b0\u01a1ng \u1ee9ng v\u1edbi quy\u1ec1n h\u1ea1n \u0111\u00e3 c\u1ea5u h\u00ecnh.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"h-cach-2-jdbc-jpa-authentication-s\u1eed-d\u1ee5ng-trong-th\u1ef1c-t\u1ebf\"><strong>C\u00e1ch 2: <\/strong><a href=\"https:\/\/www.baeldung.com\/spring-security-jdbc-authenticatio\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>JDBC\/JPA Authentication<\/strong><\/a><strong> (S\u1eed d\u1ee5ng trong th\u1ef1c t\u1ebf)<\/strong><\/h4>\n\n\n\n<p>Trong m\u1ed9t \u1ee9ng d\u1ee5ng th\u1ef1c t\u1ebf, th\u00f4ng tin ng\u01b0\u1eddi d\u00f9ng ph\u1ea3i \u0111\u01b0\u1ee3c l\u01b0u trong c\u01a1 s\u1edf d\u1eef li\u1ec7u.<\/p>\n\n\n\n<p><strong>a. T\u1ea1o Entity <code>User<\/code> v\u00e0 <code>Role<\/code> (Gi\u1ea3 s\u1eed b\u1ea1n \u0111\u00e3 c\u00f3 dependency spring-boot-starter-data-jpa v\u00e0 \u0111\u00e3 c\u1ea5u h\u00ecnh database)<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ User.java\n@Entity\n@Table(name = \"users\")\npublic class User {\n    @Id\n    @GeneratedValue(strategy = GenerationType.IDENTITY)\n    private Long id;\n    private String username;\n    private String password;\n    \/\/ getters and setters\n}\n\n\/\/ Role.java (N\u1ebfu b\u1ea1n mu\u1ed1n qu\u1ea3n l\u00fd role \u0111\u1ed9ng<\/code><\/pre>\n\n\n\n<p><strong>b. Tri\u1ec3n khai <\/strong><strong>UserDetailsService&nbsp;<\/strong><\/p>\n\n\n\n<p>T\u1ea1o m\u1ed9t service m\u1edbi, v\u00ed d\u1ee5 JpaUserDetailsService, \u0111\u1ec3 Spring Security bi\u1ebft c\u00e1ch &#8220;\u0111\u1ecdc&#8221; th\u00f4ng tin ng\u01b0\u1eddi d\u00f9ng t\u1eeb database c\u1ee7a b\u1ea1n.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package com.example.demo.service;\n\nimport com.example.demo.repository.UserRepository;\nimport org.springframework.security.core.userdetails.UserDetails;\nimport org.springframework.security.core.userdetails.UserDetailsService;\nimport org.springframework.security.core.userdetails.UsernameNotFoundException;\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class JpaUserDetailsService implements UserDetailsService {\n\n    private final UserRepository userRepository;\n\n    public JpaUserDetailsService(UserRepository userRepository) {\n        this.userRepository = userRepository;\n    }\n\n    @Override\n    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {\n        return userRepository\n                .findByUsername(username)\n                .map(SecurityUser::new) \/\/ Chuy\u1ec3n \u0111\u1ed5i t\u1eeb User entity sang UserDetails\n                .orElseThrow(() -&gt; new UsernameNotFoundException(\"Username not found: \" + username));\n    }\n}<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>L\u01b0u \u00fd: L\u1edbp <code>SecurityUser<\/code> l\u00e0 m\u1ed9t l\u1edbp implement <code>UserDetails<\/code> \u0111\u1ec3 g\u00f3i <code>User<\/code> entity c\u1ee7a b\u1ea1n l\u1ea1i.<\/li>\n<\/ul>\n\n\n\n<p><strong>c. C\u1ea5u h\u00ecnh <\/strong><strong>PasswordEncoder<\/strong><\/p>\n\n\n\n<p>L\u01b0u \u00fd quan tr\u1ecdng: TUY\u1ec6T \u0110\u1ed0I KH\u00d4NG BAO GI\u1edc L\u01afU M\u1eacT KH\u1ea8U D\u1ea0NG CHU\u1ed6I K\u00dd T\u1ef0 G\u1ed0C (PLAIN TEXT) TRONG DATABASE!<\/p>\n\n\n\n<p>M\u1eadt kh\u1ea9u ph\u1ea3i lu\u00f4n \u0111\u01b0\u1ee3c &#8220;b\u0103m&#8221; (hashed) b\u1eb1ng m\u1ed9t thu\u1eadt to\u00e1n m\u1ea1nh, m\u1ed9t chi\u1ec1u. <strong>BCrypt<\/strong> l\u00e0 m\u1ed9t l\u1ef1a ch\u1ecdn ti\u00eau chu\u1ea9n v\u00e0 \u0111\u01b0\u1ee3c khuy\u1ebfn kh\u00edch.<\/p>\n\n\n\n<p>Trong SecurityConfig.java, h\u00e3y \u0111\u1ecbnh ngh\u0129a PasswordEncoder bean:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;\nimport org.springframework.security.crypto.password.PasswordEncoder;\n\n\/\/ ... b\u00ean trong l\u1edbp SecurityConfig\n\n@Bean\npublic PasswordEncoder passwordEncoder() {\n    return new BCryptPasswordEncoder();\n}<\/code><\/pre>\n\n\n\n<p>Khi t\u1ea1o ng\u01b0\u1eddi d\u00f9ng m\u1edbi, b\u1ea1n s\u1ebd d\u00f9ng bean n\u00e0y \u0111\u1ec3 m\u00e3 h\u00f3a m\u1eadt kh\u1ea9u tr\u01b0\u1edbc khi l\u01b0u v\u00e0o database:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ V\u00ed d\u1ee5 trong m\u1ed9t service t\u1ea1o user\nUser newUser = new User();\nnewUser.setUsername(\"newuser\");\nnewUser.setPassword(passwordEncoder.encode(\"strongpassword123\"));\nuserRepository.save(newUser);<\/code><\/pre>\n\n\n\n<p>Spring Security s\u1ebd t\u1ef1 \u0111\u1ed9ng s\u1eed d\u1ee5ng <code>PasswordEncoder <\/code>bean n\u00e0y \u0111\u1ec3 so s\u00e1nh m\u1eadt kh\u1ea9u ng\u01b0\u1eddi d\u00f9ng nh\u1eadp v\u00e0o (sau khi \u0111\u00e3 b\u0103m) v\u1edbi m\u1eadt kh\u1ea9u \u0111\u00e3 \u0111\u01b0\u1ee3c b\u0103m trong database.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-cac-ch\u1ee7-d\u1ec1-nang-cao-c\u1ee7a-spring-security\"><span class=\"ez-toc-section\" id=\"Cac_chu_de_nang_cao_cua_Spring_Security\"><\/span><strong>C\u00e1c ch\u1ee7 \u0111\u1ec1 n\u00e2ng cao c\u1ee7a Spring Security<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Khi b\u1ea1n \u0111\u00e3 n\u1eafm v\u1eefng c\u00e1c ki\u1ebfn th\u1ee9c c\u01a1 b\u1ea3n, th\u1ebf gi\u1edbi Spring Security c\u00f2n r\u1ea5t nhi\u1ec1u ch\u1ee7 \u0111\u1ec1 th\u00fa v\u1ecb v\u00e0 m\u1ea1nh m\u1ebd kh\u00e1c \u0111\u1ec3 kh\u00e1m ph\u00e1. D\u01b0\u1edbi \u0111\u00e2y l\u00e0 m\u1ed9t s\u1ed1 h\u01b0\u1edbng \u0111i n\u00e2ng cao gi\u00fap b\u1ea1n x\u00e2y d\u1ef1ng c\u00e1c h\u1ec7 th\u1ed1ng ph\u1ee9c t\u1ea1p v\u00e0 an to\u00e0n h\u01a1n.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-b\u1ea3o-m\u1eadt-api-v\u1edbi-jwt-json-web-tokens\"><strong>B\u1ea3o M\u1eadt API V\u1edbi JWT (JSON Web Tokens)<\/strong><\/h3>\n\n\n\n<p>Trong c\u00e1c ki\u1ebfn tr\u00fac hi\u1ec7n \u0111\u1ea1i nh\u01b0 <strong>Microservices<\/strong> ho\u1eb7c c\u00e1c \u1ee9ng d\u1ee5ng <strong>Stateless<\/strong> (n\u01a1i server kh\u00f4ng l\u01b0u tr\u1eef session c\u1ee7a ng\u01b0\u1eddi d\u00f9ng), c\u01a1 ch\u1ebf <code>formLogin<\/code> d\u1ef1a tr\u00ean session kh\u00f4ng c\u00f2n ph\u00f9 h\u1ee3p. \u0110\u00e2y l\u00e0 l\u00fac <strong>JWT<\/strong> t\u1ecfa s\u00e1ng.<\/p>\n\n\n\n<p><strong>C\u00e1ch ho\u1ea1t \u0111\u1ed9ng<\/strong>: Khi ng\u01b0\u1eddi d\u00f9ng \u0111\u0103ng nh\u1eadp th\u00e0nh c\u00f4ng, thay v\u00ec t\u1ea1o m\u1ed9t session tr\u00ean server, h\u1ec7 th\u1ed1ng s\u1ebd c\u1ea5p cho h\u1ecd m\u1ed9t chu\u1ed7i token (JWT) \u0111\u00e3 \u0111\u01b0\u1ee3c k\u00fd s\u1ed1. Trong c\u00e1c y\u00eau c\u1ea7u ti\u1ebfp theo, ng\u01b0\u1eddi d\u00f9ng ch\u1ec9 c\u1ea7n g\u1eedi token n\u00e0y trong <code>Authorization <\/code>header. Server s\u1ebd x\u00e1c th\u1ef1c ch\u1eef k\u00fd c\u1ee7a token \u0111\u1ec3 x\u00e1c th\u1ef1c ng\u01b0\u1eddi d\u00f9ng m\u00e0 kh\u00f4ng c\u1ea7n truy v\u1ea5n database hay b\u1ed9 nh\u1edb session.<\/p>\n\n\n\n<p><strong>L\u1ee3i \u00edch<\/strong>: Gi\u1ea3m t\u1ea3i cho server, d\u1ec5 d\u00e0ng m\u1edf r\u1ed9ng (scaling), v\u00e0 l\u00e0 ti\u00eau chu\u1ea9n v\u00e0ng \u0111\u1ec3 b\u1ea3o m\u1eadt giao ti\u1ebfp gi\u1eefa c\u00e1c service.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-oauth-2-0-amp-openid-connect-oidc\"><strong>OAuth 2.0 &amp; OpenID Connect (OIDC)<\/strong><\/h3>\n\n\n\n<p>B\u1ea1n ch\u1eafc ch\u1eafn \u0111\u00e3 t\u1eebng th\u1ea5y c\u00e1c n\u00fat &#8220;\u0110\u0103ng nh\u1eadp v\u1edbi Google&#8221; ho\u1eb7c &#8220;\u0110\u0103ng nh\u1eadp v\u1edbi Facebook&#8221;. \u0110\u00f3 ch\u00ednh l\u00e0 \u1ee9ng d\u1ee5ng c\u1ee7a <strong>OAuth 2.0<\/strong> v\u00e0 <strong>OpenID Connect<\/strong>.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>OAuth 2.0<\/strong>: L\u00e0 m\u1ed9t framework v\u1ec1 <strong>ph\u00e2n quy\u1ec1n<\/strong>. N\u00f3 cho ph\u00e9p m\u1ed9t \u1ee9ng d\u1ee5ng (v\u00ed d\u1ee5: trang web c\u1ee7a b\u1ea1n) c\u00f3 \u0111\u01b0\u1ee3c quy\u1ec1n truy c\u1eadp gi\u1edbi h\u1ea1n v\u00e0o t\u00e0i nguy\u00ean c\u1ee7a ng\u01b0\u1eddi d\u00f9ng tr\u00ean m\u1ed9t server kh\u00e1c (v\u00ed d\u1ee5: Google) m\u00e0 kh\u00f4ng c\u1ea7n bi\u1ebft m\u1eadt kh\u1ea9u c\u1ee7a ng\u01b0\u1eddi d\u00f9ng.<\/li>\n\n\n\n<li><strong>OpenID Connect (OIDC)<\/strong>: L\u00e0 m\u1ed9t l\u1edbp \u0111\u1ecbnh danh n\u1eb1m tr\u00ean OAuth 2.0. N\u1ebfu OAuth 2.0 ch\u1ec9 gi\u1ea3i quy\u1ebft vi\u1ec7c &#8220;\u1ee7y quy\u1ec1n&#8221;, th\u00ec OIDC gi\u1ea3i quy\u1ebft vi\u1ec7c <strong>x\u00e1c th\u1ef1c<\/strong> \u2013 &#8220;ng\u01b0\u1eddi d\u00f9ng n\u00e0y l\u00e0 ai?&#8221;. N\u00f3 cung c\u1ea5p th\u00f4ng tin h\u1ed3 s\u01a1 ng\u01b0\u1eddi d\u00f9ng d\u01b0\u1edbi d\u1ea1ng m\u1ed9t token \u0111\u1eb7c bi\u1ec7t g\u1ecdi l\u00e0 ID Token.<\/li>\n<\/ul>\n\n\n\n<p>Spring Security cung c\u1ea5p m\u1ed9t module <code>spring-boot-starter-oauth2-client<\/code> c\u1ef1c k\u1ef3 m\u1ea1nh m\u1ebd \u0111\u1ec3 t\u00edch h\u1ee3p c\u00e1c lu\u1ed3ng \u0111\u0103ng nh\u1eadp n\u00e0y m\u1ed9t c\u00e1ch d\u1ec5 d\u00e0ng.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-method-level-security-b\u1ea3o-m\u1eadt-c\u1ea5p-ph\u01b0\u01a1ng-th\u1ee9c\"><a href=\"https:\/\/docs.spring.io\/spring-security\/reference\/servlet\/authorization\/method-security.html\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>Method Level Security<\/strong><\/a><strong> (B\u1ea3o M\u1eadt C\u1ea5p Ph\u01b0\u01a1ng Th\u1ee9c)<\/strong><\/h3>\n\n\n\n<p>B\u00ean c\u1ea1nh vi\u1ec7c b\u1ea3o m\u1eadt d\u1ef1a tr\u00ean URL (authorizeHttpRequests), Spring Security c\u00f2n cho ph\u00e9p b\u1ea1n \u00e1p d\u1ee5ng c\u00e1c quy t\u1eafc b\u1ea3o m\u1eadt tr\u1ef1c ti\u1ebfp tr\u00ean c\u00e1c ph\u01b0\u01a1ng th\u1ee9c trong t\u1ea7ng Service.<\/p>\n\n\n\n<p><strong>C\u00e1ch s\u1eed d\u1ee5ng<\/strong>: B\u1eb1ng c\u00e1ch b\u1eadt @EnableMethodSecurity v\u00e0 s\u1eed d\u1ee5ng c\u00e1c annotation nh\u01b0 @PreAuthorize, @PostAuthorize, v\u00e0 @Secured tr\u00ean c\u00e1c ph\u01b0\u01a1ng th\u1ee9c.<\/p>\n\n\n\n<p><strong>L\u1ee3i \u00edch<\/strong>: Cung c\u1ea5p m\u1ed9t l\u1edbp b\u1ea3o m\u1eadt chi ti\u1ebft v\u00e0 ch\u1eb7t ch\u1ebd h\u01a1n, g\u1eafn li\u1ec1n v\u1edbi logic nghi\u1ec7p v\u1ee5.<\/p>\n\n\n\n<p><strong>V\u00ed d\u1ee5<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Ch\u1ec9 ng\u01b0\u1eddi d\u00f9ng c\u00f3 vai tr\u00f2 ADMIN m\u1edbi c\u00f3 th\u1ec3 g\u1ecdi ph\u01b0\u01a1ng th\u1ee9c n\u00e0y\n@PreAuthorize(\"hasRole('ADMIN')\")\npublic void deleteUser(Long userId) {\n    \/\/ ... logic x\u00f3a ng\u01b0\u1eddi d\u00f9ng\n}\n\n\/\/ Ch\u1ec9 ng\u01b0\u1eddi d\u00f9ng n\u00e0o c\u00f3 username tr\u00f9ng v\u1edbi `username` trong path\n\/\/ m\u1edbi c\u00f3 th\u1ec3 xem th\u00f4ng tin c\u1ee7a ch\u00ednh m\u00ecnh.\n@PreAuthorize(\"#username == authentication.principal.username\")\npublic UserProfile getProfileByUsername(String username) {\n    \/\/ ... logic l\u1ea5y profile\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-cors-cross-origin-resource-sharing\"><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Guides\/CORS\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>CORS (Cross-Origin Resource Sharing)<\/strong><\/a><\/h3>\n\n\n\n<p>Khi \u1ee9ng d\u1ee5ng Frontend (v\u00ed d\u1ee5: React, Vue) c\u1ee7a b\u1ea1n ch\u1ea1y tr\u00ean m\u1ed9t domain kh\u00e1c (vd: myapp.com) v\u00e0 g\u1ecdi API \u0111\u1ebfn Backend Spring Boot ch\u1ea1y tr\u00ean domain (vd: api.myapp.com), tr\u00ecnh duy\u1ec7t s\u1ebd m\u1eb7c \u0111\u1ecbnh ch\u1eb7n c\u00e1c y\u00eau c\u1ea7u n\u00e0y v\u00ec l\u00fd do b\u1ea3o m\u1eadt.<\/p>\n\n\n\n<p><strong>CORS<\/strong> l\u00e0 m\u1ed9t c\u01a1 ch\u1ebf cho ph\u00e9p server ch\u1ec9 \u0111\u1ecbnh nh\u1eefng &#8220;ngu\u1ed3n&#8221; (origin) n\u00e0o kh\u00e1c \u0111\u01b0\u1ee3c ph\u00e9p truy c\u1eadp t\u00e0i nguy\u00ean c\u1ee7a m\u00ecnh. Spring Security cho ph\u00e9p b\u1ea1n c\u1ea5u h\u00ecnh CORS m\u1ed9t c\u00e1ch linh ho\u1ea1t:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ V\u00ed d\u1ee5 c\u1ea5u h\u00ecnh CORS trong SecurityFilterChain\nhttp.cors(cors -&gt; cors.configurationSource(request -&gt; {\n    CorsConfiguration config = new CorsConfiguration();\n    config.setAllowedOrigins(List.of(\"https:\/\/myapp.com\"));\n    config.setAllowedMethods(List.of(\"GET\", \"POST\", \"PUT\", \"DELETE\"));\n    config.setAllowedHeaders(List.of(\"*\"));\n    return config;\n}));<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-csrf-cross-site-request-forgery-protection\"><a href=\"https:\/\/portswigger.net\/web-security\/csrf\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>CSRF (Cross-Site Request Forgery) Protection<\/strong><\/a><\/h3>\n\n\n\n<p><strong>SRF<\/strong> l\u00e0 m\u1ed9t ki\u1ec3u t\u1ea5n c\u00f4ng trong \u0111\u00f3 k\u1ebb x\u1ea5u l\u1eeba ng\u01b0\u1eddi d\u00f9ng \u0111\u00e3 \u0111\u0103ng nh\u1eadp th\u1ef1c hi\u1ec7n m\u1ed9t h\u00e0nh \u0111\u1ed9ng kh\u00f4ng mong mu\u1ed1n tr\u00ean m\u1ed9t trang web. V\u00ed d\u1ee5: l\u1eeba ng\u01b0\u1eddi d\u00f9ng nh\u1ea5n v\u00e0o m\u1ed9t link \u0111\u1ec3 t\u1ef1 \u0111\u1ed9ng chuy\u1ec3n ti\u1ec1n t\u1eeb t\u00e0i kho\u1ea3n c\u1ee7a h\u1ecd.<\/p>\n\n\n\n<p><strong>C\u00e1ch Spring Security b\u1ea3o v\u1ec7<\/strong>: \u0110\u1ed1i v\u1edbi c\u00e1c \u1ee9ng d\u1ee5ng stateful (s\u1eed d\u1ee5ng session), Spring Security m\u1eb7c \u0111\u1ecbnh <strong>\u0111\u00e3 b\u1eadt t\u00ednh n\u0103ng ch\u1ed1ng CSRF<\/strong>. N\u00f3 ho\u1ea1t \u0111\u1ed9ng b\u1eb1ng c\u00e1ch y\u00eau c\u1ea7u m\u1ecdi request thay \u0111\u1ed5i tr\u1ea1ng th\u00e1i (POST, PUT, DELETE) ph\u1ea3i \u0111\u00ednh k\u00e8m m\u1ed9t token b\u00ed m\u1eadt, ng\u1eabu nhi\u00ean (g\u1ecdi l\u00e0 CSRF token). Token n\u00e0y ch\u1ec9 \u0111\u01b0\u1ee3c t\u1ea1o ra v\u00e0 bi\u1ebft b\u1edfi server v\u00e0 client h\u1ee3p l\u1ec7. K\u1ebb t\u1ea5n c\u00f4ng kh\u00f4ng c\u00f3 token n\u00e0y s\u1ebd b\u1ecb ch\u1eb7n.<\/p>\n\n\n\n<p><strong>L\u01b0u \u00fd<\/strong>: C\u01a1 ch\u1ebf b\u1ea3o v\u1ec7 n\u00e0y th\u01b0\u1eddng kh\u00f4ng c\u1ea7n thi\u1ebft cho c\u00e1c API stateless s\u1eed d\u1ee5ng token (nh\u01b0 JWT) v\u00ec ch\u00fang kh\u00f4ng d\u1ef1a v\u00e0o cookie session c\u1ee7a tr\u00ecnh duy\u1ec7t \u0111\u1ec3 x\u00e1c th\u1ef1c.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-cac-cau-h\u1ecfi-th\u01b0\u1eddng-g\u1eb7p-v\u1ec1-spring-security\"><span class=\"ez-toc-section\" id=\"Cac_cau_hoi_thuong_gap_ve_Spring_Security\"><\/span><strong>C\u00e1c c\u00e2u h\u1ecfi th\u01b0\u1eddng g\u1eb7p v\u1ec1 Spring Security<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-s\u1ef1-khac-bi\u1ec7t-gi\u1eefa-hasrole-va-hasauthority-la-gi\"><strong>S\u1ef1 kh\u00e1c bi\u1ec7t gi\u1eefa <\/strong><strong>hasRole()<\/strong><strong> v\u00e0 <\/strong><strong>hasAuthority()<\/strong><strong> l\u00e0 g\u00ec?<\/strong><\/h3>\n\n\n\n<p>C\u1ea3 hasRole() v\u00e0 hasAuthority() \u0111\u1ec1u d\u00f9ng \u0111\u1ec3 ki\u1ec3m tra quy\u1ec1n h\u1ea1n, nh\u01b0ng c\u00f3 m\u1ed9t quy \u01b0\u1edbc ng\u1ea7m:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>hasRole(&#8220;ADMIN&#8221;)<\/strong>: T\u1ef1 \u0111\u1ed9ng ki\u1ec3m tra quy\u1ec1n h\u1ea1n c\u00f3 t\u00ean l\u00e0 &#8220;ROLE_ADMIN&#8221;. Spring s\u1ebd t\u1ef1 th\u00eam ti\u1ec1n t\u1ed1 ROLE_ cho b\u1ea1n.<\/li>\n\n\n\n<li><strong>hasAuthority(&#8220;ROLE_ADMIN&#8221;)<\/strong>: Ki\u1ec3m tra ch\u00ednh x\u00e1c quy\u1ec1n h\u1ea1n c\u00f3 t\u00ean l\u00e0 &#8220;ROLE_ADMIN&#8221;. B\u1ea1n ph\u1ea3i cung c\u1ea5p to\u00e0n b\u1ed9 t\u00ean.<\/li>\n\n\n\n<li><strong>hasAuthority(&#8220;WRITE_PRIVILEGE&#8221;)<\/strong>: D\u00f9ng cho c\u00e1c quy\u1ec1n chi ti\u1ebft, kh\u00f4ng ph\u1ea3i l\u00e0 vai tr\u00f2.<\/li>\n<\/ul>\n\n\n\n<p>N\u00f3i ng\u1eafn g\u1ecdn, hasRole() l\u00e0 m\u1ed9t tr\u01b0\u1eddng h\u1ee3p \u0111\u1eb7c bi\u1ec7t c\u1ee7a hasAuthority() \u0111\u01b0\u1ee3c th\u00eam v\u00e0o \u0111\u1ec3 cho ti\u1ec7n l\u1ee3i.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-securitycontextholder-ho\u1ea1t-d\u1ed9ng-th\u1ebf-nao-v\u1edbi-cac-ph\u01b0\u01a1ng-th\u1ee9c-async-t\u1ea1i-sao-thong-tin-dang-nh\u1eadp-b\u1ecb-m\u1ea5t\"><strong>SecurityContextHolder<\/strong><strong> ho\u1ea1t \u0111\u1ed9ng th\u1ebf n\u00e0o v\u1edbi c\u00e1c ph\u01b0\u01a1ng th\u1ee9c <\/strong><strong>@Async<\/strong><strong>? T\u1ea1i sao th\u00f4ng tin \u0111\u0103ng nh\u1eadp b\u1ecb m\u1ea5t?<\/strong><\/h3>\n\n\n\n<p>\u0110\u00e2y l\u00e0 m\u1ed9t v\u1ea5n \u0111\u1ec1 k\u1ef9 thu\u1eadt kinh \u0111i\u1ec3n.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>V\u1ea5n \u0111\u1ec1:<\/strong> M\u1eb7c \u0111\u1ecbnh, SecurityContextHolder s\u1eed d\u1ee5ng chi\u1ebfn l\u01b0\u1ee3c ThreadLocal \u0111\u1ec3 l\u01b0u tr\u1eef th\u00f4ng tin b\u1ea3o m\u1eadt. ThreadLocal ch\u1ec9 g\u1eafn d\u1eef li\u1ec7u v\u00e0o lu\u1ed3ng (thread) \u0111ang x\u1eed l\u00fd request. Khi b\u1ea1n g\u1ecdi m\u1ed9t ph\u01b0\u01a1ng th\u1ee9c \u0111\u01b0\u1ee3c \u0111\u00e1nh d\u1ea5u @Async, Spring s\u1ebd t\u1ea1o m\u1ed9t lu\u1ed3ng m\u1edbi t\u1eeb m\u1ed9t ThreadPool \u0111\u1ec3 th\u1ef1c thi n\u00f3. Lu\u1ed3ng m\u1edbi n\u00e0y kh\u00f4ng c\u00f3 th\u00f4ng tin v\u1ec1 SecurityContext c\u1ee7a lu\u1ed3ng ban \u0111\u1ea7u, d\u1eabn \u0111\u1ebfn vi\u1ec7c Authentication tr\u1ea3 v\u1ec1 null.<\/li>\n\n\n\n<li><strong>Gi\u1ea3i ph\u00e1p:<\/strong> B\u1ea1n c\u1ea7n thay \u0111\u1ed5i chi\u1ebfn l\u01b0\u1ee3c l\u01b0u tr\u1eef c\u1ee7a SecurityContextHolder tr\u01b0\u1edbc khi \u1ee9ng d\u1ee5ng kh\u1edfi \u0111\u1ed9ng. H\u00e3y chuy\u1ec3n sang ch\u1ebf \u0111\u1ed9 MODE_INHERITABLE, ch\u1ebf \u0111\u1ed9 n\u00e0y s\u1eed d\u1ee5ng InheritableThreadLocal \u0111\u1ec3 t\u1ef1 \u0111\u1ed9ng sao ch\u00e9p context t\u1eeb lu\u1ed3ng cha sang lu\u1ed3ng con.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-khi-nao-toi-nen-t\u1ef1-vi\u1ebft-m\u1ed9t-authenticationprovider-tuy-ch\u1ec9nh\"><strong>Khi n\u00e0o t\u00f4i n\u00ean t\u1ef1 vi\u1ebft m\u1ed9t <\/strong><strong>AuthenticationProvider<\/strong><strong> t\u00f9y ch\u1ec9nh?<\/strong><\/h3>\n\n\n\n<p>B\u1ea1n c\u1ea7n m\u1ed9t AuthenticationProvider t\u00f9y ch\u1ec9nh khi c\u01a1 ch\u1ebf x\u00e1c th\u1ef1c c\u1ee7a b\u1ea1n kh\u00f4ng theo chu\u1ea9n username\/password th\u00f4ng th\u01b0\u1eddng m\u00e0 DaoAuthenticationProvider (provider m\u1eb7c \u0111\u1ecbnh) x\u1eed l\u00fd.<\/p>\n\n\n\n<p><strong>C\u00e1c tr\u01b0\u1eddng h\u1ee3p ph\u1ed5 bi\u1ebfn:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>X\u00e1c th\u1ef1c ng\u01b0\u1eddi d\u00f9ng b\u1eb1ng c\u00e1ch g\u1ecdi m\u1ed9t API c\u1ee7a b\u00ean th\u1ee9 ba.<\/li>\n\n\n\n<li>X\u00e1c th\u1ef1c b\u1eb1ng m\u1ed9t c\u1eb7p API Key v\u00e0 Secret Key \u0111\u01b0\u1ee3c g\u1eedi qua header.<\/li>\n\n\n\n<li>Quy tr\u00ecnh x\u00e1c th\u1ef1c y\u00eau c\u1ea7u nhi\u1ec1u y\u1ebfu t\u1ed1 (multi-factor) ph\u1ee9c t\u1ea1p kh\u00f4ng \u0111\u01b0\u1ee3c h\u1ed7 tr\u1ee3 s\u1eb5n.<\/li>\n\n\n\n<li>X\u00e1c th\u1ef1c d\u1ef1a tr\u00ean ch\u1ee9ng ch\u1ec9 client (client certificate).<\/li>\n<\/ul>\n\n\n\n<p>\u0110\u1ec3 l\u00e0m \u0111i\u1ec1u n\u00e0y, b\u1ea1n c\u1ea7n t\u1ea1o m\u1ed9t class implement interface AuthenticationProvider v\u00e0 ghi \u0111\u00e8 hai ph\u01b0\u01a1ng th\u1ee9c:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>authenticate(): Ch\u1ee9a logic x\u00e1c th\u1ef1c ch\u00ednh c\u1ee7a b\u1ea1n.<\/li>\n\n\n\n<li>supports(): Ch\u1ec9 \u0111\u1ecbnh lo\u1ea1i Authentication token m\u00e0 Provider n\u00e0y c\u00f3 th\u1ec3 x\u1eed l\u00fd.<\/li>\n<\/ol>\n\n\n\n<p>Sau \u0111\u00f3, b\u1ea1n \u0111\u0103ng k\u00fd Provider n\u00e0y v\u00e0o AuthenticationManager.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-khi-nao-ch\u1ec9-c\u1ea7n-spring-security-truy\u1ec1n-th\u1ed1ng-khi-nao-c\u1ea7n-them-spring-boot\"><strong>Khi n\u00e0o ch\u1ec9 c\u1ea7n Spring Security truy\u1ec1n th\u1ed1ng, khi n\u00e0o c\u1ea7n th\u00eam Spring Boot?<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>D\u00f9ng Spring Boot + Spring Security: <\/strong>Ph\u00f9 h\u1ee3p khi b\u1eaft \u0111\u1ea7u b\u1ea5t k\u1ef3 d\u1ef1 \u00e1n m\u1edbi n\u00e0o, ho\u1eb7c x\u00e2y d\u1ef1ng microservices.<\/li>\n<\/ul>\n\n\n\n<p>V\u00ec Spring Boot c\u00f3 t\u1ef1 \u0111\u1ed9ng c\u1ea5u h\u00ecnh (autoconfiguration), n\u00f3 s\u1ebd t\u1ef1 \u0111\u1ed9ng thi\u1ebft l\u1eadp b\u1ea3o m\u1eadt c\u01a1 b\u1ea3n cho b\u1ea1n. B\u1ea1n ch\u1ec9 c\u1ea7n th\u00eam m\u1ed9t dependency starter duy nh\u1ea5t. C\u00e1ch n\u00e0y gi\u00fap ph\u00e1t tri\u1ec3n c\u1ef1c k\u1ef3 nhanh ch\u00f3ng.<\/p>\n\n\n\n<p>T\u00ecm hi\u1ec3u th\u00eam: T\u1ed5ng quan v\u1ec1 Spring Boot Security<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>D\u00f9ng Spring Security Truy\u1ec1n th\u1ed1ng:<\/strong> Ch\u1ec9 khi b\u1ea1n b\u1ecb bu\u1ed9c ph\u1ea3i l\u00e0m v\u1eady ho\u1eb7c do nhu c\u1ea7u c\u00e1 bi\u1ec7t c\u1ee7a d\u1ef1 \u00e1n, ch\u1ee7 y\u1ebfu l\u00e0 \u0111\u1ec3 b\u1ea3o tr\u00ec c\u00e1c d\u1ef1 \u00e1n c\u0169 kh\u00f4ng \u0111\u01b0\u1ee3c x\u00e2y d\u1ef1ng tr\u00ean Spring Boot.<\/li>\n<\/ul>\n\n\n\n<p>V\u00ec y\u00eau c\u1ea7u c\u1ea5u h\u00ecnh th\u1ee7 c\u00f4ng m\u1ecdi th\u1ee9 (th\u01b0\u1eddng qua file XML), qu\u1ea3n l\u00fd th\u01b0 vi\u1ec7n ph\u1ee9c t\u1ea1p v\u00e0 t\u1ed1n nhi\u1ec1u c\u00f4ng s\u1ee9c cho nh\u1eefng thi\u1ebft l\u1eadp c\u01a1 b\u1ea3n.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-t\u1ed5ng-k\u1ebft\"><span class=\"ez-toc-section\" id=\"Tong_ket\"><\/span><strong>T\u1ed5ng k\u1ebft<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Qua b\u00e0i vi\u1ebft, ch\u00fang ta \u0111\u00e3 \u0111i t\u1eeb c\u00e1c kh\u00e1i ni\u1ec7m c\u1ed1t l\u00f5i \u0111\u1ebfn vi\u1ec7c x\u00e2y d\u1ef1ng m\u1ed9t \u1ee9ng d\u1ee5ng th\u1ef1c t\u1ebf v\u1edbi Spring Security. Hy v\u1ecdng b\u1ea1n \u0111\u00e3 c\u00f3 m\u1ed9t n\u1ec1n t\u1ea3ng v\u1eefng ch\u1eafc \u0111\u1ec3 t\u1ef1 tin \u00e1p d\u1ee5ng c\u00f4ng c\u1ee5 m\u1ea1nh m\u1ebd n\u00e0y. H\u00e3y nh\u1edb, b\u1ea3o m\u1eadt l\u00e0 y\u1ebfu t\u1ed1 kh\u00f4ng th\u1ec3 thi\u1ebfu, v\u00e0 \u0111\u00e2y ch\u1ec9 l\u00e0 \u0111i\u1ec3m kh\u1edfi \u0111\u1ea7u tr\u00ean h\u00e0nh tr\u00ecnh l\u00e0m ch\u1ee7 Spring Security c\u1ee7a b\u1ea1n.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>B\u1ea3o m\u1eadt l\u00e0 y\u1ebfu t\u1ed1 c\u1ef1c k\u1ef3 quan tr\u1ecdng c\u1ee7a c\u00e1c \u1ee9ng d\u1ee5ng web \u0111\u1ec3 tr\u00e1nh c\u00e1c r\u1ee7i ro nh\u01b0 r\u00f2 r\u1ec9 d\u1eef li\u1ec7u hay b\u1ecb t\u1ea5n c\u00f4ng. B\u00e0i vi\u1ebft n\u00e0y s\u1ebd h\u01b0\u1edbng d\u1eabn b\u1ea1n hi\u1ec3u v\u1ec1 Spring Security, framework b\u1ea3o m\u1eadt h\u00e0ng \u0111\u1ea7u cho Java, t\u1eeb c\u00e1c kh\u00e1i ni\u1ec7m c\u1ed1t l\u00f5i nh\u01b0 X\u00e1c th\u1ef1c [&hellip;]<\/p>\n","protected":false},"author":203,"featured_media":92008,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_gspb_post_css":"","footnotes":""},"categories":[109,10350],"tags":[],"class_list":["post-90561","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-chuyen-mon-it","category-java"],"blocksy_meta":[],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.8 (Yoast SEO v27.7) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Spring security: Kh\u00e1m ph\u00e1 framework b\u1ea3o m\u1eadt h\u00e0ng \u0111\u1ea7u cho \u1ee9ng d\u1ee5ng Java - ITviec Blog<\/title>\n<meta name=\"description\" content=\"Kh\u00e1m ph\u00e1 Spring Security t\u1eeb ki\u1ebfn tr\u00fac \u0111\u1ebfn c\u00e1ch d\u00f9ng th\u1ef1c t\u1ebf: X\u00e1c th\u1ef1c, ph\u00e2n quy\u1ec1n, JWT, OAuth2, Filter Chain,... k\u00e8m v\u00ed d\u1ee5 d\u1ec5 hi\u1ec3u.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/itviec.com\/blog\/spring-security-la-gi\/\" \/>\n<meta property=\"og:locale\" content=\"vi_VN\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Spring security: Kh\u00e1m ph\u00e1 framework b\u1ea3o m\u1eadt h\u00e0ng \u0111\u1ea7u cho \u1ee9ng d\u1ee5ng Java\" \/>\n<meta property=\"og:description\" content=\"B\u1ea3o m\u1eadt l\u00e0 y\u1ebfu t\u1ed1 c\u1ef1c k\u1ef3 quan tr\u1ecdng c\u1ee7a c\u00e1c \u1ee9ng d\u1ee5ng web \u0111\u1ec3 tr\u00e1nh c\u00e1c r\u1ee7i ro nh\u01b0 r\u00f2 r\u1ec9 d\u1eef li\u1ec7u hay b\u1ecb t\u1ea5n c\u00f4ng. B\u00e0i vi\u1ebft n\u00e0y s\u1ebd h\u01b0\u1edbng d\u1eabn b\u1ea1n hi\u1ec3u v\u1ec1\" \/>\n<meta property=\"og:url\" content=\"https:\/\/itviec.com\/blog\/spring-security-la-gi\/\" \/>\n<meta property=\"og:site_name\" content=\"ITviec Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/ITviec\" \/>\n<meta property=\"article:published_time\" content=\"2025-10-05T10:36:38+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-10-31T04:27:26+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/itviec.com\/blog\/wp-content\/uploads\/2025\/08\/spring-security-scaled.png\" \/>\n\t<meta property=\"og:image:width\" content=\"800\" \/>\n\t<meta property=\"og:image:height\" content=\"421\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Tien Tran\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@ITviec\" \/>\n<meta name=\"twitter:site\" content=\"@ITviec\" \/>\n<meta name=\"twitter:label1\" content=\"\u0110\u01b0\u1ee3c vi\u1ebft b\u1edfi\" \/>\n\t<meta name=\"twitter:data1\" content=\"Tien Tran\" \/>\n\t<meta name=\"twitter:label2\" content=\"\u01af\u1edbc t\u00ednh th\u1eddi gian \u0111\u1ecdc\" \/>\n\t<meta name=\"twitter:data2\" content=\"19 ph\u00fat\" \/>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Spring security: Kh\u00e1m ph\u00e1 framework b\u1ea3o m\u1eadt h\u00e0ng \u0111\u1ea7u cho \u1ee9ng d\u1ee5ng Java - ITviec Blog","description":"Kh\u00e1m ph\u00e1 Spring Security t\u1eeb ki\u1ebfn tr\u00fac \u0111\u1ebfn c\u00e1ch d\u00f9ng th\u1ef1c t\u1ebf: X\u00e1c th\u1ef1c, ph\u00e2n quy\u1ec1n, JWT, OAuth2, Filter Chain,... k\u00e8m v\u00ed d\u1ee5 d\u1ec5 hi\u1ec3u.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/itviec.com\/blog\/spring-security-la-gi\/","og_locale":"vi_VN","og_type":"article","og_title":"Spring security: Kh\u00e1m ph\u00e1 framework b\u1ea3o m\u1eadt h\u00e0ng \u0111\u1ea7u cho \u1ee9ng d\u1ee5ng Java","og_description":"B\u1ea3o m\u1eadt l\u00e0 y\u1ebfu t\u1ed1 c\u1ef1c k\u1ef3 quan tr\u1ecdng c\u1ee7a c\u00e1c \u1ee9ng d\u1ee5ng web \u0111\u1ec3 tr\u00e1nh c\u00e1c r\u1ee7i ro nh\u01b0 r\u00f2 r\u1ec9 d\u1eef li\u1ec7u hay b\u1ecb t\u1ea5n c\u00f4ng. B\u00e0i vi\u1ebft n\u00e0y s\u1ebd h\u01b0\u1edbng d\u1eabn b\u1ea1n hi\u1ec3u v\u1ec1","og_url":"https:\/\/itviec.com\/blog\/spring-security-la-gi\/","og_site_name":"ITviec Blog","article_publisher":"https:\/\/www.facebook.com\/ITviec","article_published_time":"2025-10-05T10:36:38+00:00","article_modified_time":"2025-10-31T04:27:26+00:00","og_image":[{"width":800,"height":421,"url":"https:\/\/itviec.com\/blog\/wp-content\/uploads\/2025\/08\/spring-security-scaled.png","type":"image\/png"}],"author":"Tien Tran","twitter_card":"summary_large_image","twitter_creator":"@ITviec","twitter_site":"@ITviec","twitter_misc":{"\u0110\u01b0\u1ee3c vi\u1ebft b\u1edfi":"Tien Tran","\u01af\u1edbc t\u00ednh th\u1eddi gian \u0111\u1ecdc":"19 ph\u00fat"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/itviec.com\/blog\/spring-security-la-gi\/#article","isPartOf":{"@id":"https:\/\/itviec.com\/blog\/spring-security-la-gi\/"},"author":{"name":"Tien Tran","@id":"https:\/\/itviec.com\/blog\/#\/schema\/person\/1595d671c49cfa2a48cd3c0a047a1298"},"headline":"Spring security: Kh\u00e1m ph\u00e1 framework b\u1ea3o m\u1eadt h\u00e0ng \u0111\u1ea7u cho \u1ee9ng d\u1ee5ng Java","datePublished":"2025-10-05T10:36:38+00:00","dateModified":"2025-10-31T04:27:26+00:00","mainEntityOfPage":{"@id":"https:\/\/itviec.com\/blog\/spring-security-la-gi\/"},"wordCount":5006,"publisher":{"@id":"https:\/\/itviec.com\/blog\/#organization"},"image":{"@id":"https:\/\/itviec.com\/blog\/spring-security-la-gi\/#primaryimage"},"thumbnailUrl":"https:\/\/itviec.com\/blog\/wp-content\/uploads\/2025\/08\/spring-security-scaled.png","articleSection":["Chuy\u00ean m\u00f4n IT","Java"],"inLanguage":"vi"},{"@type":"WebPage","@id":"https:\/\/itviec.com\/blog\/spring-security-la-gi\/","url":"https:\/\/itviec.com\/blog\/spring-security-la-gi\/","name":"Spring security: Kh\u00e1m ph\u00e1 framework b\u1ea3o m\u1eadt h\u00e0ng \u0111\u1ea7u cho \u1ee9ng d\u1ee5ng Java - ITviec Blog","isPartOf":{"@id":"https:\/\/itviec.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/itviec.com\/blog\/spring-security-la-gi\/#primaryimage"},"image":{"@id":"https:\/\/itviec.com\/blog\/spring-security-la-gi\/#primaryimage"},"thumbnailUrl":"https:\/\/itviec.com\/blog\/wp-content\/uploads\/2025\/08\/spring-security-scaled.png","datePublished":"2025-10-05T10:36:38+00:00","dateModified":"2025-10-31T04:27:26+00:00","description":"Kh\u00e1m ph\u00e1 Spring Security t\u1eeb ki\u1ebfn tr\u00fac \u0111\u1ebfn c\u00e1ch d\u00f9ng th\u1ef1c t\u1ebf: X\u00e1c th\u1ef1c, ph\u00e2n quy\u1ec1n, JWT, OAuth2, Filter Chain,... k\u00e8m v\u00ed d\u1ee5 d\u1ec5 hi\u1ec3u.","breadcrumb":{"@id":"https:\/\/itviec.com\/blog\/spring-security-la-gi\/#breadcrumb"},"inLanguage":"vi","potentialAction":[{"@type":"ReadAction","target":["https:\/\/itviec.com\/blog\/spring-security-la-gi\/"]}]},{"@type":"ImageObject","inLanguage":"vi","@id":"https:\/\/itviec.com\/blog\/spring-security-la-gi\/#primaryimage","url":"https:\/\/itviec.com\/blog\/wp-content\/uploads\/2025\/08\/spring-security-scaled.png","contentUrl":"https:\/\/itviec.com\/blog\/wp-content\/uploads\/2025\/08\/spring-security-scaled.png","width":800,"height":421,"caption":"spring security - itviec blog"},{"@type":"BreadcrumbList","@id":"https:\/\/itviec.com\/blog\/spring-security-la-gi\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Chuy\u00ean m\u00f4n IT","item":"https:\/\/itviec.com\/blog\/chuyen-mon-it\/"},{"@type":"ListItem","position":2,"name":"Spring security: Kh\u00e1m ph\u00e1 framework b\u1ea3o m\u1eadt h\u00e0ng \u0111\u1ea7u cho \u1ee9ng d\u1ee5ng Java"}]},{"@type":"WebSite","@id":"https:\/\/itviec.com\/blog\/#website","url":"https:\/\/itviec.com\/blog\/","name":"ITviec Blog","description":"IT Jobs &amp; People in Vietnam","publisher":{"@id":"https:\/\/itviec.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/itviec.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"vi"},{"@type":"Organization","@id":"https:\/\/itviec.com\/blog\/#organization","name":"ITviec","url":"https:\/\/itviec.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"vi","@id":"https:\/\/itviec.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/itviec.com\/blog\/wp-content\/uploads\/2018\/12\/itviec-black-square-facebook.png","contentUrl":"https:\/\/itviec.com\/blog\/wp-content\/uploads\/2018\/12\/itviec-black-square-facebook.png","width":1800,"height":1800,"caption":"ITviec"},"image":{"@id":"https:\/\/itviec.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/ITviec","https:\/\/x.com\/ITviec","https:\/\/www.linkedin.com\/company\/itviec","https:\/\/www.youtube.com\/channel\/UCYthAQ3bcGr57M_ag5gHDvQ"]},{"@type":"Person","@id":"https:\/\/itviec.com\/blog\/#\/schema\/person\/1595d671c49cfa2a48cd3c0a047a1298","name":"Tien Tran","image":{"@type":"ImageObject","inLanguage":"vi","@id":"https:\/\/itviec.com\/blog\/wp-content\/uploads\/2024\/05\/tien-tran-author-e1715658627643-100x100.jpg","url":"https:\/\/itviec.com\/blog\/wp-content\/uploads\/2024\/05\/tien-tran-author-e1715658627643-100x100.jpg","contentUrl":"https:\/\/itviec.com\/blog\/wp-content\/uploads\/2024\/05\/tien-tran-author-e1715658627643-100x100.jpg","caption":"Tien Tran"},"url":"https:\/\/itviec.com\/blog\/author\/tien-tran\/"}]}},"_links":{"self":[{"href":"https:\/\/itviec.com\/blog\/wp-json\/wp\/v2\/posts\/90561","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/itviec.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itviec.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/itviec.com\/blog\/wp-json\/wp\/v2\/users\/203"}],"replies":[{"embeddable":true,"href":"https:\/\/itviec.com\/blog\/wp-json\/wp\/v2\/comments?post=90561"}],"version-history":[{"count":4,"href":"https:\/\/itviec.com\/blog\/wp-json\/wp\/v2\/posts\/90561\/revisions"}],"predecessor-version":[{"id":92009,"href":"https:\/\/itviec.com\/blog\/wp-json\/wp\/v2\/posts\/90561\/revisions\/92009"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/itviec.com\/blog\/wp-json\/wp\/v2\/media\/92008"}],"wp:attachment":[{"href":"https:\/\/itviec.com\/blog\/wp-json\/wp\/v2\/media?parent=90561"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itviec.com\/blog\/wp-json\/wp\/v2\/categories?post=90561"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itviec.com\/blog\/wp-json\/wp\/v2\/tags?post=90561"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}