{"id":475028,"date":"2025-09-15T05:15:28","date_gmt":"2025-09-15T05:15:28","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=475028"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"spring-security-dlya-nachinayuschih-konspekt-ot-autentifikatsii-do-jwt","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=475028","title":{"rendered":"Spring Security \u0434\u043b\u044f \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0445: \u043a\u043e\u043d\u0441\u043f\u0435\u043a\u0442 \u043e\u0442 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0434\u043e JWT"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p><strong>Spring Security<\/strong> \u2014 \u044d\u0442\u043e \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0437\u0430\u0449\u0438\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 Spring. \u041e\u043d \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430:<\/p>\n<ul>\n<li>\n<p><strong>\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e (Authentication)<\/strong> \u2014 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043b\u0438\u0447\u043d\u043e\u0441\u0442\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f (\u043b\u043e\u0433\u0438\u043d\/\u043f\u0430\u0440\u043e\u043b\u044c, OAuth2-\u0442\u043e\u043a\u0435\u043d, JWT).<\/p>\n<\/li>\n<li>\n<p><strong>\u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e (Authorization)<\/strong> \u2014 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043f\u0440\u0430\u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0430: \u0447\u0442\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442 \u0434\u0435\u043b\u0430\u0442\u044c \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435.<\/p>\n<\/li>\n<li>\n<p><strong>\u0417\u0430\u0449\u0438\u0442\u0443 \u043e\u0442 \u0430\u0442\u0430\u043a<\/strong>: CSRF (\u043f\u043e\u0434\u0434\u0435\u043b\u043a\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432), session fixation (\u0444\u0438\u043a\u0441\u0430\u0446\u0438\u044f \u0441\u0435\u0441\u0441\u0438\u0438), clickjacking, brute-force \u0438 \u0442. \u0434.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e \u0432\u0430\u0436\u043d\u043e?<\/p>\n<ul>\n<li>\n<p>\u0421\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0438\u043b\u0438 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0423\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u044c \u0432 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 = \u043f\u0440\u044f\u043c\u044b\u0435 \u0443\u0431\u044b\u0442\u043a\u0438, \u0443\u0442\u0435\u0447\u043a\u0438 \u0438 \u0440\u0435\u043f\u0443\u0442\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0443\u0434\u0430\u0440.<\/p>\n<\/li>\n<li>\n<p>Spring Security \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043e\u043c: \u043d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f\u0448\u043d\u0438\u0439 \u0434\u0435\u043d\u044c \u043f\u043e\u0434\u0430\u0432\u043b\u044f\u044e\u0449\u0435\u0435 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 Spring \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0435\u0433\u043e.<\/p>\n<\/li>\n<\/ul>\n<p>Spring Security \u0432\u0441\u0442\u0440\u043e\u0435\u043d \u0433\u043b\u0443\u0431\u043e\u043a\u043e \u0432 \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u0443 Spring Boot: \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c <code>spring-boot-starter-security<\/code>, \u0438 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432\u0441\u0451 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043e (\u0434\u043e\u0441\u0442\u0443\u043f \u0440\u0430\u0437\u0440\u0435\u0448\u0451\u043d \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c).<\/p>\n<blockquote>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u2014 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u0443\u044e \u0437\u0430\u0449\u0438\u0442\u0443 \u043f\u043e\u0434 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f: web-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u0444\u043e\u0440\u043c\u043e\u0439 \u043b\u043e\u0433\u0438\u043d\u0430, REST API \u0441 JWT, \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0441 OAuth2 \u0438 \u0442. \u0434.<\/p>\n<\/blockquote>\n<h3>2. \u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 Spring Security<\/h3>\n<p>\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 Spring Security \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u043d\u0430 <strong>\u0446\u0435\u043f\u043e\u0447\u043a\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 (Filter Chain)<\/strong>.<\/p>\n<h4>2.1. \u041a\u0430\u043a \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0437\u0430\u043f\u0440\u043e\u0441<\/h4>\n<ol>\n<li>\n<p><strong>\u041a\u043b\u0438\u0435\u043d\u0442<\/strong> (\u0431\u0440\u0430\u0443\u0437\u0435\u0440, \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441) \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442 HTTP-\u0437\u0430\u043f\u0440\u043e\u0441.<\/p>\n<ul>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0432\u043a\u043b\u044e\u0447\u0451\u043d HTTPS \u2014 \u0442\u0440\u0430\u0444\u0438\u043a \u0448\u0438\u0444\u0440\u0443\u0435\u0442\u0441\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0440\u043e\u0441 \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c <code>Authorization: Bearer &lt;token&gt;<\/code> \u0438\u043b\u0438 <code>Cookie: JSESSIONID<\/code>.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>\u0421\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 (Spring Boot)<\/strong> \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441.<\/p>\n<ul>\n<li>\n<p>\u0414\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432 \u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u0432 <strong>\u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 (Filter Chain)<\/strong>.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>Spring Security Filter Chain<\/strong> \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442:<\/p>\n<ul>\n<li>\n<p>\u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d \u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c?<\/p>\n<\/li>\n<li>\n<p>\u043a\u0430\u043a\u0438\u0435 \u043f\u0440\u0430\u0432\u0430 \u0443 \u043d\u0435\u0433\u043e \u0435\u0441\u0442\u044c?<\/p>\n<\/li>\n<li>\n<p>\u0440\u0430\u0437\u0440\u0435\u0448\u0451\u043d \u043b\u0438 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0440\u0435\u0441\u0443\u0440\u0441\u0443?<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0435 \u043f\u0440\u043e\u0439\u0434\u0435\u043d\u0430 \u2192 \u043e\u0442\u0432\u0435\u0442 401 (Unauthorized \u2014 \u043d\u0435\u0442 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438) \u0438\u043b\u0438 403 (Forbidden \u2014 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432).<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u0430 \u2192 \u0437\u0430\u043f\u0440\u043e\u0441 \u0443\u0445\u043e\u0434\u0438\u0442 \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440, \u0441\u0435\u0440\u0432\u0438\u0441, \u0411\u0414.<\/p>\n<\/li>\n<\/ol>\n<h4>2.2. \u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b<\/h4>\n<ul>\n<li>\n<p><strong>DelegatingFilterProxy<\/strong> \u2014 \u0442\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 \u0432 Spring Security \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0441\u0435\u0440\u0432\u043b\u0435\u0442\u043e\u0432 (Tomcat, Jetty \u0438 \u0442. \u0434.).<\/p>\n<\/li>\n<li>\n<p><strong>FilterChainProxy<\/strong> \u2014 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p><strong>SecurityFilterChain<\/strong> \u2014 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430 URL (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <code>\/api\/**<\/code> \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 JWT, \u0430 <code>\/login<\/code> \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 \u0444\u043e\u0440\u043c\u0443).<\/p>\n<\/li>\n<li>\n<p><strong>AuthenticationManager<\/strong> \u2014 \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e. \u041e\u043d \u0434\u0435\u043b\u0435\u0433\u0438\u0440\u0443\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u043c \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0430\u043c (<code>AuthenticationProvider<\/code>).<\/p>\n<\/li>\n<li>\n<p><strong>UserDetailsService<\/strong> \u2014 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435 \u0438\u0437 \u0411\u0414 (\u043b\u043e\u0433\u0438\u043d, \u043f\u0430\u0440\u043e\u043b\u044c, \u0440\u043e\u043b\u0438).<\/p>\n<\/li>\n<li>\n<p><strong>PasswordEncoder<\/strong> \u2014 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043f\u0430\u0440\u043e\u043b\u0435\u0439 (BCrypt \u0438 \u0442. \u0434.).<\/p>\n<\/li>\n<li>\n<p><strong>SecurityContext<\/strong> \u2014 \u043e\u0431\u044a\u0435\u043a\u0442, \u0433\u0434\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435 (<code>Authentication<\/code>).<\/p>\n<\/li>\n<\/ul>\n<h4>2.3. \u041f\u0440\u0438\u043c\u0435\u0440 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 \u0446\u0435\u043f\u043e\u0447\u043a\u0438 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432<\/h4>\n<p>\u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0441 \u0444\u043e\u0440\u043c\u043e\u0439 \u043b\u043e\u0433\u0438\u043d\u0430 Spring Security \u0441\u0442\u0440\u043e\u0438\u0442 \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442:<\/p>\n<ol>\n<li>\n<p><code>SecurityContextPersistenceFilter<\/code> \u2014 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435 \u0438\u0437 \u0441\u0435\u0441\u0441\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p><code>CsrfFilter<\/code> \u2014 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 CSRF-\u0442\u043e\u043a\u0435\u043d.<\/p>\n<\/li>\n<li>\n<p><code>UsernamePasswordAuthenticationFilter<\/code> \u2014 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 POST <code>\/login<\/code>, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043b\u043e\u0433\u0438\u043d\/\u043f\u0430\u0440\u043e\u043b\u044c.<\/p>\n<\/li>\n<li>\n<p><code>BasicAuthenticationFilter<\/code> \u2014 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a <code>Authorization: Basic ...<\/code>.<\/p>\n<\/li>\n<li>\n<p><code>BearerTokenAuthenticationFilter<\/code> \u2014 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 JWT \u0438\u043b\u0438 OAuth2-\u0442\u043e\u043a\u0435\u043d.<\/p>\n<\/li>\n<li>\n<p><code>AnonymousAuthenticationFilter<\/code> \u2014 \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0435 \u0437\u0430\u043b\u043e\u0433\u0438\u043d\u0435\u043d, \u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u0435\u0442 \u0435\u043c\u0443 &#171;\u0430\u043d\u043e\u043d\u0438\u043c\u043d\u0443\u044e&#187; \u0440\u043e\u043b\u044c.<\/p>\n<\/li>\n<li>\n<p><code>ExceptionTranslationFilter<\/code> \u2014 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0438 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438.<\/p>\n<\/li>\n<li>\n<p><code>FilterSecurityInterceptor<\/code> \u2014 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u0440\u0430\u0432 \u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f.<\/p>\n<\/li>\n<\/ol>\n<h4>2.4. Servlet vs Reactive<\/h4>\n<ul>\n<li>\n<p><strong>Servlet (Tomcat\/Jetty\/Undertow)<\/strong>: \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0446\u0435\u043f\u043e\u0447\u043a\u0430 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 (<code>Filter<\/code>).<\/p>\n<\/li>\n<li>\n<p><strong>Reactive (WebFlux\/Netty)<\/strong>: \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f <code>WebFilter<\/code>, <code>SecurityWebFilterChain<\/code>, \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0439 <code>ReactiveAuthenticationManager<\/code>. \u041e\u0442\u043b\u0438\u0447\u0438\u0435 \u2014 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0432 <em>reactive context<\/em>, \u0430 \u043d\u0435 \u0432 <code>ThreadLocal<\/code>.<\/p>\n<\/li>\n<\/ul>\n<h3>3. \u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0438 \u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f<\/h3>\n<h4>3.1. \u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f (Authentication)<\/h4>\n<p>\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f = \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043b\u0438\u0447\u043d\u043e\u0441\u0442\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<br \/> Spring Security \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441: <strong>\u043a\u0442\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441?<\/strong><\/p>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438:<\/p>\n<ol>\n<li>\n<p><strong>\u0424\u043e\u0440\u043c\u0430 \u043b\u043e\u0433\u0438\u043d\u0430 (Form Login)<\/strong><\/p>\n<ul>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 POST <code>\/login<\/code> \u0441 <code>username<\/code> \u0438 <code>password<\/code>.<\/p>\n<\/li>\n<li>\n<p><code>UsernamePasswordAuthenticationFilter<\/code> \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441.<\/p>\n<\/li>\n<li>\n<p><code>AuthenticationManager<\/code> \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 <code>DaoAuthenticationProvider<\/code>.<\/p>\n<\/li>\n<li>\n<p><code>UserDetailsService<\/code> \u0438\u0449\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 \u0411\u0414.<\/p>\n<\/li>\n<li>\n<p><code>PasswordEncoder<\/code> \u0441\u0432\u0435\u0440\u044f\u0435\u0442 \u043f\u0430\u0440\u043e\u043b\u044c (BCrypt, Argon2).<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u0430 \u2192 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442 <code>Authentication<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0432 <code>SecurityContext<\/code>.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>HTTP Basic<\/strong><\/p>\n<ul>\n<li>\n<p>\u0417\u0430\u043f\u0440\u043e\u0441 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 <code>Authorization: Basic base64(user:password)<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 REST API (\u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0435\u0440\u0435\u0437 HTTPS).<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>JWT (Bearer Token)<\/strong><\/p>\n<ul>\n<li>\n<p>\u0412 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435: <code>Authorization: Bearer &lt;jwt&gt;<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0422\u043e\u043a\u0435\u043d \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f (<code>exp<\/code>, <code>iss<\/code>, <code>aud<\/code>, \u043f\u043e\u0434\u043f\u0438\u0441\u044c).<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439 \u2192 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f <code>Authentication<\/code>.<\/p>\n<\/li>\n<li>\n<p>Stateful-\u0441\u0435\u0441\u0441\u0438\u0439 \u043d\u0435\u0442, \u043a\u0430\u0436\u0434\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u0430\u044f.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>OAuth2 \/ OpenID Connect<\/strong><\/p>\n<ul>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043b\u043e\u0433\u0438\u043d\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0430 (Google, GitHub).<\/p>\n<\/li>\n<li>\n<p>Spring Security \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 access token \/ id token.<\/p>\n<\/li>\n<li>\n<p>\u0420\u0435\u0441\u0443\u0440\u0441\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 (resource server) \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d (\u043e\u0431\u044b\u0447\u043d\u043e JWT).<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>LDAP \/ Active Directory<\/strong><\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>\u041a\u0430\u0441\u0442\u043e\u043c\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/strong><\/p>\n<ul>\n<li>\n<p>\u041c\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 <code>AuthenticationProvider<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 HMAC-\u043f\u043e\u0434\u043f\u0438\u0441\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438\u043b\u0438 API-\u043a\u043b\u044e\u0447\u0435\u0439.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<h4>3.2. \u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f (Authorization)<\/h4>\n<p>\u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f = \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u0440\u0430\u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0430.<br \/> Spring Security \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442: <strong>\u043a\u0430\u043a\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u044b?<\/strong><\/p>\n<p>\u0423\u0440\u043e\u0432\u043d\u0438:<\/p>\n<ol>\n<li>\n<p><strong>URL-\u0443\u0440\u043e\u0432\u0435\u043d\u044c<\/strong><br \/> \u0412 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 <code>HttpSecurity<\/code>:<\/p>\n<pre><code class=\"java\">http.authorizeHttpRequests(auth -&gt; auth    .requestMatchers(\"\/admin\/**\").hasRole(\"ADMIN\")    .requestMatchers(\"\/user\/**\").hasAnyRole(\"USER\", \"ADMIN\")    .anyRequest().authenticated());<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>\/admin\/**<\/code> \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0442\u043e\u043b\u044c\u043a\u043e ADMIN, <code>\/user\/**<\/code> \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d USER \u0438 ADMIN, \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 URL \u0442\u0440\u0435\u0431\u0443\u044e\u0442 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>\u041c\u0435\u0442\u043e\u0434\u043d\u044b\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c<\/strong><br \/> \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 \u0432 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445:<\/p>\n<pre><code class=\"java\">@PreAuthorize(\"hasRole('ADMIN')\")public void deleteUser(Long id) { ... }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0418\u043b\u0438 \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f (SpEL):<\/p>\n<pre><code class=\"java\">@PreAuthorize(\"#id == principal.id or hasRole('ADMIN')\")public Account getAccount(Long id) { ... }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0437\u0430\u0432\u044f\u0437\u0430\u043d\u0430 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u0440\u043e\u043b\u0438, \u043d\u043e \u0438 \u043d\u0430 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0443.<\/p>\n<\/li>\n<li>\n<p><strong>\u0414\u043e\u0441\u0442\u0443\u043f \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 (ACL)<\/strong><\/p>\n<ul>\n<li>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <code>AclService<\/code> \u0438 <code>PermissionEvaluator<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440: \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u0432\u0442\u043e\u0440 \u0441\u0442\u0430\u0442\u044c\u0438 \u043c\u043e\u0436\u0435\u0442 \u0435\u0451 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<h4>3.3. UserDetails \u0438 PasswordEncoder<\/h4>\n<ol>\n<li>\n<p><strong>UserDetailsService<\/strong><br \/> \u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 <code>UserDetails<\/code>.<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438:<\/p>\n<pre><code class=\"java\">@Servicepublic class CustomUserDetailsService implements UserDetailsService {    private final UserRepository userRepository;    public UserDetails loadUserByUsername(String username) {        UserEntity user = userRepository.findByUsername(username)            .orElseThrow(() -&gt; new UsernameNotFoundException(\"Not found\"));        return new org.springframework.security.core.userdetails.User(            user.getUsername(),            user.getPassword(),            user.getRoles().stream().map(SimpleGrantedAuthority::new).toList()        );    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/li>\n<li>\n<p><strong>PasswordEncoder<\/strong><br \/> \u041f\u0430\u0440\u043e\u043b\u0438 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u0432\u0438\u0434\u0435.<\/p>\n<ul>\n<li>\n<p><code>BCryptPasswordEncoder<\/code> (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e).<\/p>\n<\/li>\n<li>\n<p><code>Argon2PasswordEncoder<\/code> (\u0435\u0449\u0451 \u0431\u043e\u043b\u0435\u0435 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439).<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code class=\"java\">@BeanPasswordEncoder passwordEncoder() {    return new BCryptPasswordEncoder();}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u0440\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u0445\u044d\u0448\u0438\u0440\u0443\u0435\u0442\u0441\u044f, \u043f\u0440\u0438 \u043b\u043e\u0433\u0438\u043d\u0435 \u2014 \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0445\u044d\u0448.<\/p>\n<\/li>\n<\/ol>\n<h4>3.4. \u041f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e?<\/h4>\n<ul>\n<li>\n<p><strong>TLS\/HTTPS<\/strong> \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u0442 \u043e\u0442 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0430 \u0442\u0440\u0430\u0444\u0438\u043a\u0430 (\u0447\u0435\u043b\u043e\u0432\u0435\u043a \u043f\u043e\u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435 \u043d\u0435 \u0443\u0432\u0438\u0434\u0438\u0442 \u043f\u0430\u0440\u043e\u043b\u044c).<\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u0430\u0440\u043e\u043b\u0438 \u0445\u044d\u0448\u0438\u0440\u0443\u044e\u0442\u0441\u044f<\/strong> (bcrypt\/argon2): \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0443\u043a\u0440\u0430\u0434\u0443\u0442 \u0411\u0414, \u043f\u0430\u0440\u043e\u043b\u044c \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u0432\u0438\u0434\u0435 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c.<\/p>\n<\/li>\n<li>\n<p><strong>\u0422\u043e\u043a\u0435\u043d\u044b \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f<\/strong>: JWT \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0446\u0438\u0444\u0440\u043e\u0432\u0443\u044e \u043f\u043e\u0434\u043f\u0438\u0441\u044c, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043d\u0435\u043b\u044c\u0437\u044f \u043f\u043e\u0434\u0434\u0435\u043b\u0430\u0442\u044c \u0431\u0435\u0437 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430.<\/p>\n<\/li>\n<li>\n<p><strong>\u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u043c\u043d\u043e\u0433\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u0430\u044f<\/strong>: \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u0442\u043e\u043a\u0435\u043d, \u0434\u043e\u0441\u0442\u0443\u043f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d \u0440\u043e\u043b\u044f\u043c\u0438 \u0438 ACL.<\/p>\n<\/li>\n<li>\n<p><strong>\u041c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u044b \u0437\u0430\u0449\u0438\u0442\u044b \u043e\u0442 \u0430\u0442\u0430\u043a<\/strong>: CSRF-\u0442\u043e\u043a\u0435\u043d\u044b, \u0441\u0435\u0441\u0441\u0438\u043e\u043d\u043d\u0430\u044f \u0438\u0437\u043e\u043b\u044f\u0446\u0438\u044f, \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u043e\u043f\u044b\u0442\u043e\u043a \u0432\u0445\u043e\u0434\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441 <strong>\u00ab\u043a\u0442\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441?\u00bb<\/strong>.<br \/> \u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441 <strong>\u00ab\u0447\u0442\u043e \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u043e \u0434\u0435\u043b\u0430\u0442\u044c?\u00bb<\/strong>.<br \/> \u0412\u043c\u0435\u0441\u0442\u0435 \u043e\u043d\u0438 \u043e\u0431\u0440\u0430\u0437\u0443\u044e\u0442 \u043e\u0441\u043d\u043e\u0432\u0443 Spring Security.<\/p>\n<h3>4. \u0416\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u0439 \u0446\u0438\u043a\u043b \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 Spring Security<\/h3>\n<p>\u0427\u0442\u043e\u0431\u044b \u0443\u0432\u0435\u0440\u0435\u043d\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441\u043e Spring Security, \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c: <strong>\u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442, \u043a\u043e\u0433\u0434\u0430 \u043a\u043b\u0438\u0435\u043d\u0442 \u0434\u0435\u043b\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e<\/strong>.<\/p>\n<h4>4.1. \u041e\u0431\u0449\u0430\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c<\/h4>\n<ol>\n<li>\n<p>\u041a\u043b\u0438\u0435\u043d\u0442 (\u0431\u0440\u0430\u0443\u0437\u0435\u0440, \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441) \u2192 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 (GET\/POST\/PUT \u0438 \u0442. \u0434.).<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0440\u043e\u0441 \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 (Tomcat\/Jetty\/Undertow).<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 <strong>\u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 (Filter Chain)<\/strong>.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0440\u0435\u0434\u0438 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 \u0435\u0441\u0442\u044c <code>DelegatingFilterProxy<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432 Spring Security.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0440\u043e\u0441 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 \u0441\u0435\u0440\u0438\u044e \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 Spring Security.<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0443\u0441\u043f\u0435\u0448\u043d\u044b\u0435 \u2192 \u0437\u0430\u043f\u0440\u043e\u0441 \u0434\u043e\u0445\u043e\u0434\u0438\u0442 \u0434\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0443 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0442\u0432\u0435\u0442.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u0432\u0435\u0442 \u0441\u043d\u043e\u0432\u0430 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 \u0444\u0438\u043b\u044c\u0442\u0440\u044b (\u0447\u0430\u0441\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u0441\u0435\u0441\u0441\u0438\u044e, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438).<\/p>\n<\/li>\n<\/ol>\n<h4>4.2. \u0414\u0435\u0442\u0430\u043b\u044c\u043d\u043e: \u0448\u0430\u0433 \u0437\u0430 \u0448\u0430\u0433\u043e\u043c<\/h4>\n<p>\u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <strong>Spring Boot MVC + Form Login<\/strong>.<\/p>\n<p><strong>\u0428\u0430\u0433 1. \u0421\u0435\u0442\u0435\u0432\u043e\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c<\/strong><\/p>\n<ul>\n<li>\n<p>\u041a\u043b\u0438\u0435\u043d\u0442 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 <code>\/login<\/code>.<\/p>\n<\/li>\n<li>\n<p>TLS\/HTTPS \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435.<\/p>\n<\/li>\n<li>\n<p>Tomcat \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0438 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0435\u0433\u043e \u0432 <code>HttpServletRequest<\/code>.<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u0428\u0430\u0433 2. \u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0444\u0438\u043b\u044c\u0442\u0440\u044b<\/strong><\/p>\n<ul>\n<li>\n<p>Tomcat \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0432\u0441\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u044b, \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0440\u0435\u0434\u0438 \u043d\u0438\u0445 \u0435\u0441\u0442\u044c <code>DelegatingFilterProxy(\"springSecurityFilterChain\")<\/code>.<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u0428\u0430\u0433 3. \u0412\u0445\u043e\u0434 \u0432 Spring Security Filter Chain<\/strong><\/p>\n<ul>\n<li>\n<p><code>FilterChainProxy<\/code> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442, \u043a\u0430\u043a\u0438\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e URL.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f <code>\/login<\/code> \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 <code>UsernamePasswordAuthenticationFilter<\/code>.<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u0428\u0430\u0433 4. \u0420\u0430\u0431\u043e\u0442\u0430 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432<\/strong><\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440\u043d\u044b\u0439 \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e):<\/p>\n<ol>\n<li>\n<p><code><strong>SecurityContextPersistenceFilter<\/strong><\/code><br \/> \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 <code>SecurityContext<\/code> \u0438\u0437 \u0441\u0435\u0441\u0441\u0438\u0438 (\u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c).<br \/> \u0415\u0441\u043b\u0438 \u043d\u0435\u0442 \u2014 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043d\u043e\u0432\u044b\u0439 (\u0430\u043d\u043e\u043d\u0438\u043c\u043d\u044b\u0439).<\/p>\n<\/li>\n<li>\n<p><code><strong>CsrfFilter<\/strong><\/code><br \/> \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 CSRF-\u0442\u043e\u043a\u0435\u043d\u0430 (\u0434\u043b\u044f POST\/PUT\/DELETE).<\/p>\n<\/li>\n<li>\n<p><code><strong>LogoutFilter<\/strong><\/code><br \/> \u041f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 <code>\/logout<\/code>, \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u0441\u0435\u0441\u0441\u0438\u044e, \u043a\u0443\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p><code><strong>UsernamePasswordAuthenticationFilter<\/strong><\/code><br \/> \u0415\u0441\u043b\u0438 POST <code>\/login<\/code> \u2192 \u0431\u0435\u0440\u0451\u0442 <code>username<\/code> \u0438 <code>password<\/code>.<br \/> \u0421\u043e\u0437\u0434\u0430\u0451\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 <code>UsernamePasswordAuthenticationToken<\/code>.<br \/> \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0435\u0433\u043e \u0432 <code>AuthenticationManager<\/code>.<\/p>\n<\/li>\n<li>\n<p><code><strong>AuthenticationManager<\/strong><\/code><strong> \u2192 <\/strong><code><strong>AuthenticationProvider<\/strong><\/code><br \/> \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <code>DaoAuthenticationProvider<\/code>.<br \/> \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0447\u0435\u0440\u0435\u0437 <code>UserDetailsService<\/code>.<br \/> \u0421\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u0442 \u043f\u0430\u0440\u043e\u043b\u044c \u0447\u0435\u0440\u0435\u0437 <code>PasswordEncoder<\/code>.<br \/> \u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u0430 \u2192 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>Authentication<\/code> \u0441 \u0440\u043e\u043b\u044f\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p><code><strong>SecurityContextHolder<\/strong><\/code><br \/> \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 <code>Authentication<\/code> (\u0432 <code>ThreadLocal<\/code>).<br \/> \u0415\u0441\u043b\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 stateful \u2192 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0438\u0448\u0443\u0442\u0441\u044f \u0432 <code>HttpSession<\/code>.<\/p>\n<\/li>\n<li>\n<p><code><strong>FilterSecurityInterceptor<\/strong><\/code><br \/> \u0424\u0438\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430: \u0435\u0441\u0442\u044c \u043b\u0438 \u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f \u043a URL\/\u043c\u0435\u0442\u043e\u0434\u0443.<br \/> \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 <code>AccessDecisionManager<\/code>.<\/p>\n<\/li>\n<\/ol>\n<p>\u0415\u0441\u043b\u0438 \u0433\u0434\u0435-\u0442\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0430\u0440\u043e\u043b\u044c \u043d\u0435\u0432\u0435\u0440\u043d\u044b\u0439, \u0442\u043e\u043a\u0435\u043d \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439) \u2192 \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>AuthenticationException<\/code>, \u0438 \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 401\/403.<\/p>\n<p><strong>\u0428\u0430\u0433 5. \u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440<\/strong><\/p>\n<ul>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u0440\u043e\u0439\u0434\u0435\u043d\u044b, <code>DispatcherServlet<\/code> \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code class=\"java\">@GetMapping(\"\/admin\")@PreAuthorize(\"hasRole('ADMIN')\")public String adminPage() { ... }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0438\u043c\u0435\u0435\u0442 \u0440\u043e\u043b\u044c <code>ADMIN<\/code> \u2192 \u043c\u0435\u0442\u043e\u0434 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0441\u044f.<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u0428\u0430\u0433 6. \u041e\u0431\u0440\u0430\u0442\u043d\u044b\u0439 \u043f\u0443\u0442\u044c (Response)<\/strong><\/p>\n<ul>\n<li>\n<p>\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>ResponseEntity<\/code> \u0438\u043b\u0438 <code>View<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u0432\u0435\u0442 \u0441\u043d\u043e\u0432\u0430 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 \u0444\u0438\u043b\u044c\u0442\u0440\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <code>HeaderWriterFilter<\/code> \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438).<\/p>\n<\/li>\n<li>\n<p>Tomcat \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043e\u0442\u0432\u0435\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0443.<\/p>\n<\/li>\n<\/ul>\n<h4>4.3. \u0412\u0430\u0440\u0438\u0430\u0446\u0438\u0438<\/h4>\n<ul>\n<li>\n<p><strong>JWT API (stateless)<\/strong><br \/> \u041d\u0435\u0442 <code>HttpSession<\/code>.<br \/> <code>BearerTokenAuthenticationFilter<\/code> \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435.<br \/> \u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0437\u0430\u043d\u043e\u0432\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437.<\/p>\n<\/li>\n<li>\n<p><strong>WebFlux (reactive)<\/strong><br \/> \u0412\u043c\u0435\u0441\u0442\u043e <code>Filter<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <code>WebFilter<\/code>.<br \/> \u0412\u043c\u0435\u0441\u0442\u043e <code>ThreadLocal SecurityContextHolder<\/code> \u2192 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0439 <code>Context<\/code>.<br \/> \u0412\u0441\u044f \u0440\u0430\u0431\u043e\u0442\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e.<\/p>\n<\/li>\n<\/ul>\n<h4>4.4. \u041a\u043b\u044e\u0447\u0435\u0432\u043e\u0439 \u043f\u0440\u0438\u043d\u0446\u0438\u043f<\/h4>\n<p>\u0412\u0441\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c \u0432 Spring Security \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f <strong>\u0434\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438<\/strong>.<br \/> \u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0435 \u043f\u0440\u043e\u0448\u0451\u043b \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u2014 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0434\u0430\u0436\u0435 \u043d\u0435 \u0432\u044b\u0437\u043e\u0432\u0435\u0442\u0441\u044f.<\/p>\n<ul>\n<li>\n<p>Spring Security \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u0430\u043a <strong>\u043f\u0440\u043e\u0441\u043b\u043e\u0439\u043a\u0430 \u043c\u0435\u0436\u0434\u0443 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u043c<\/strong>.<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u0436\u0434\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0414\u041e \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438.<\/p>\n<\/li>\n<\/ul>\n<h3>5. Stateful vs Stateless (\u0441\u0435\u0441\u0441\u0438\u0438 \u0438 JWT)<\/h3>\n<p>\u041e\u0434\u0438\u043d \u0438\u0437 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0445 \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438: <strong>\u043a\u0430\u043a \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435 \u043c\u0435\u0436\u0434\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438<\/strong>.<\/p>\n<h4>5.1. Stateful (\u0441 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c, \u0447\u0435\u0440\u0435\u0437 \u0441\u0435\u0441\u0441\u0438\u0438)<\/h4>\n<h4>\u041a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442<\/h4>\n<ol>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0435\u0440\u0435\u0437 \u0444\u043e\u0440\u043c\u0443).<\/p>\n<\/li>\n<li>\n<p>\u0421\u0435\u0440\u0432\u0435\u0440 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043b\u043e\u0433\u0438\u043d\/\u043f\u0430\u0440\u043e\u043b\u044c.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435 \u0432 <strong>HttpSession<\/strong>.<\/p>\n<ul>\n<li>\n<p>\u042d\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u043d\u0451\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f <code>SecurityContext<\/code> \u0441 <code>Authentication<\/code>.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>\u041a\u043b\u0438\u0435\u043d\u0442\u0443 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f <strong>cookie (JSESSIONID)<\/strong>.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442 cookie, \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u043e \u043d\u0435\u043c\u0443 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0437 \u0441\u0435\u0441\u0441\u0438\u0438.<\/p>\n<\/li>\n<\/ol>\n<h4>\u041f\u0440\u0438\u043c\u0435\u0440<\/h4>\n<ul>\n<li>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u0432\u0445\u043e\u0434 \u2192 <code>POST \/login<\/code><\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u0432\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u2192 <code>Set-Cookie: JSESSIONID=abc123<\/code><\/p>\n<\/li>\n<li>\n<p>\u0414\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u2192 <code>Cookie: JSESSIONID=abc123<\/code><\/p>\n<\/li>\n<\/ul>\n<h4>\u041f\u043b\u044e\u0441\u044b<\/h4>\n<ul>\n<li>\n<p>\u041f\u0440\u043e\u0441\u0442\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c.<\/p>\n<\/li>\n<li>\n<p>\u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u0434\u043b\u044f \u0437\u0430\u043a\u0440\u044b\u0442\u044b\u0445 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u00ab\u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438\u00bb \u0432 Spring Security.<\/p>\n<\/li>\n<\/ul>\n<h4>\u041c\u0438\u043d\u0443\u0441\u044b<\/h4>\n<ul>\n<li>\n<p>\u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u043b\u043e\u0436\u043d\u0435\u0435: \u043f\u0440\u0438 \u0431\u043e\u043b\u044c\u0448\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e <strong>\u0448\u0430\u0440\u0438\u0442\u044c \u0441\u0435\u0441\u0441\u0438\u0438<\/strong> (sticky sessions, Redis, Hazelcast).<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u0443\u0434\u043e\u0431\u043d\u043e \u0434\u043b\u044f REST API \u0438 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043b\u043e\u0445\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f mobile-first \u0438 SPA (React, Angular, iOS\/Android).<\/p>\n<\/li>\n<\/ul>\n<h4>5.2. Stateless (\u0431\u0435\u0437 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f, \u0447\u0435\u0440\u0435\u0437 JWT \u0438\u043b\u0438 \u0442\u043e\u043a\u0435\u043d\u044b)<\/h4>\n<h4>\u041a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442<\/h4>\n<ol>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u0442\u0441\u044f (\u0438\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0447\u0435\u0440\u0435\u0437 OAuth2).<\/p>\n<\/li>\n<li>\n<p>\u0421\u0435\u0440\u0432\u0435\u0440 <strong>\u043d\u0435 \u0445\u0440\u0430\u043d\u0438\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438<\/strong>.<\/p>\n<\/li>\n<li>\n<p>\u041a\u043b\u0438\u0435\u043d\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 <strong>JWT (JSON Web Token)<\/strong>.<\/p>\n<\/li>\n<li>\n<p>JWT \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 (localStorage, secure cookie, mobile keystore).<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a:<\/p>\n<pre><code>Authorization: Bearer &lt;jwt-token&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/li>\n<li>\n<p>\u0421\u0435\u0440\u0432\u0435\u0440 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d (\u043f\u043e\u0434\u043f\u0438\u0441\u044c, \u0441\u0440\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f, \u043f\u0440\u0430\u0432\u0430).<\/p>\n<\/li>\n<\/ol>\n<h4>JWT \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430<\/h4>\n<p>JWT \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0442\u0440\u0451\u0445 \u0447\u0430\u0441\u0442\u0435\u0439 (\u0440\u0430\u0437\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0445 \u0442\u043e\u0447\u043a\u0430\u043c\u0438):<\/p>\n<pre><code>header.payload.signature<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p><strong>Header<\/strong> \u2192 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u043f\u043e\u0434\u043f\u0438\u0441\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, HS256).<\/p>\n<\/li>\n<li>\n<p><strong>Payload<\/strong> \u2192 \u0434\u0430\u043d\u043d\u044b\u0435: <code>sub<\/code> (user id), <code>roles<\/code>, <code>exp<\/code> (\u0441\u0440\u043e\u043a \u0436\u0438\u0437\u043d\u0438).<\/p>\n<\/li>\n<li>\n<p><strong>Signature<\/strong> \u2192 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u043e\u0434\u043b\u0438\u043d\u043d\u043e\u0441\u0442\u0438 (HMAC \u0438\u043b\u0438 RSA).<\/p>\n<\/li>\n<\/ul>\n<h4>\u041f\u0440\u0438\u043c\u0435\u0440 payload<\/h4>\n<pre><code class=\"json\">{  \"sub\": \"user123\",  \"roles\": [\"USER\"],  \"exp\": 1736448900}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>\u041f\u043b\u044e\u0441\u044b<\/h4>\n<ul>\n<li>\n<p>\u041f\u0440\u043e\u0441\u0442\u043e\u0435 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435: \u0441\u0435\u0440\u0432\u0435\u0440 stateless, \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u043e\u0432 \u043d\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043e.<\/p>\n<\/li>\n<li>\n<p>\u0423\u0434\u043e\u0431\u043d\u043e \u0434\u043b\u044f \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u043b\u044e\u0431\u044b\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 (web, mobile, API).<\/p>\n<\/li>\n<\/ul>\n<h4>\u041c\u0438\u043d\u0443\u0441\u044b<\/h4>\n<ul>\n<li>\n<p>JWT \u043d\u0435\u043b\u044c\u0437\u044f \u043e\u0442\u043e\u0437\u0432\u0430\u0442\u044c \u0434\u043e \u0438\u0441\u0442\u0435\u0447\u0435\u043d\u0438\u044f \u0441\u0440\u043e\u043a\u0430 (\u0435\u0441\u043b\u0438 \u043d\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u044c blacklist).<\/p>\n<\/li>\n<li>\n<p>Payload \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u0432\u0438\u0434\u0435 (Base64, \u043d\u0435 \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d, \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d).<\/p>\n<\/li>\n<li>\n<p>\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0441\u0445\u0435\u043c\u0430 \u0434\u043b\u044f refresh-\u0442\u043e\u043a\u0435\u043d\u043e\u0432.<\/p>\n<\/li>\n<\/ul>\n<h4>5.3. Refresh \u0442\u043e\u043a\u0435\u043d\u044b<\/h4>\n<p>\u0427\u0442\u043e\u0431\u044b access-\u0442\u043e\u043a\u0435\u043d \u043d\u0435 \u0431\u044b\u043b \u00ab\u0432\u0435\u0447\u043d\u044b\u043c\u00bb, \u0447\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u0445\u0435\u043c\u0430 \u0441 \u0434\u0432\u0443\u043c\u044f \u0442\u043e\u043a\u0435\u043d\u0430\u043c\u0438:<\/p>\n<ol>\n<li>\n<p><strong>Access Token<\/strong> \u2014 \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0436\u0438\u0432\u0443\u0449\u0438\u0439 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, 15 \u043c\u0438\u043d\u0443\u0442).<\/p>\n<\/li>\n<li>\n<p><strong>Refresh Token<\/strong> \u2014 \u0434\u043e\u043b\u0433\u043e\u0436\u0438\u0432\u0443\u0449\u0438\u0439 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, 30 \u0434\u043d\u0435\u0439).<\/p>\n<\/li>\n<\/ol>\n<p>\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c:<\/p>\n<ul>\n<li>\n<p>\u041a\u043b\u0438\u0435\u043d\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043e\u0431\u0430 \u0442\u043e\u043a\u0435\u043d\u0430 \u043f\u0440\u0438 \u043b\u043e\u0433\u0438\u043d\u0435.<\/p>\n<\/li>\n<li>\n<p>Access Token \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445.<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0441\u0440\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0438\u0441\u0442\u0435\u043a\u0430\u0435\u0442 \u2192 \u043a\u043b\u0438\u0435\u043d\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 Refresh Token \u043d\u0430 <code>\/refresh<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0435\u0440\u0432\u0435\u0440 \u0432\u044b\u0434\u0430\u0451\u0442 \u043d\u043e\u0432\u044b\u0439 Access Token.<\/p>\n<\/li>\n<\/ul>\n<h4>5.4. Spring Security \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h4>\n<ul>\n<li>\n<p><strong>Stateful (Session):<\/strong><\/p>\n<ul>\n<li>\n<p><code>HttpSessionSecurityContextRepository<\/code><\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u00ab\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e\u00bb \u043f\u0440\u0438 form login.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>Stateless (JWT):<\/strong><\/p>\n<ul>\n<li>\n<p><code>BearerTokenAuthenticationFilter<\/code><\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0432 <code>SecurityFilterChain<\/code>:<\/p>\n<pre><code class=\"java\">http  .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)  .and()  .oauth2ResourceServer().jwt();<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h4>5.5. \u041a\u043e\u0433\u0434\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0447\u0442\u043e<\/h4>\n<ul>\n<li>\n<p><strong>Stateful (\u0441\u0435\u0441\u0441\u0438\u0438):<\/strong><\/p>\n<ul>\n<li>\n<p>\u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0435\u0440\u0435\u0437 \u0431\u0440\u0430\u0443\u0437\u0435\u0440.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>Stateless (JWT):<\/strong><\/p>\n<ul>\n<li>\n<p>REST API \u0434\u043b\u044f \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p>\u041c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u0441\u043e\u043a\u0430\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0435 \u043a \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u0438.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Stateful \u2192 \u0441\u0435\u0440\u0432\u0435\u0440 \u0445\u0440\u0430\u043d\u0438\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043f\u0440\u043e\u0449\u0435, \u043d\u043e \u0445\u0443\u0436\u0435 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u0442\u0441\u044f.<br \/> Stateless \u2192 \u043a\u043b\u0438\u0435\u043d\u0442 \u0445\u0440\u0430\u043d\u0438\u0442 \u0442\u043e\u043a\u0435\u043d, \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f API \u0438 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432.<br \/> JWT \u2014 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c, \u043d\u043e \u043d\u0435 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u0430\u044f \u00ab\u043f\u0430\u043d\u0430\u0446\u0435\u044f\u00bb.<\/p>\n<h3>6. \u041f\u0430\u0440\u043e\u043b\u0438 \u0438 PasswordEncoder \u2014 \u043a\u0430\u043a \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e<\/h3>\n<p>\u041e\u0434\u043d\u0430 \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u0447\u0430\u0441\u0442\u044b\u0445 \u043e\u0448\u0438\u0431\u043e\u043a \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0445 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u2014 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043f\u0430\u0440\u043e\u043b\u0435\u0439 \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u0432\u0438\u0434\u0435 (plain text) \u0438\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0445\u044d\u0448\u0435\u0439 \u0432\u0440\u043e\u0434\u0435 <strong>MD5\/SHA1<\/strong>.<br \/> Spring Security \u0440\u0435\u0448\u0430\u0435\u0442 \u044d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443 \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c <strong>PasswordEncoder<\/strong>.<\/p>\n<h4>6.1. \u041f\u043e\u0447\u0435\u043c\u0443 \u043d\u0435\u043b\u044c\u0437\u044f \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043f\u0430\u0440\u043e\u043b\u0438 \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u0432\u0438\u0434\u0435<\/h4>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439:<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">id<\/p>\n<\/th>\n<th>\n<p align=\"left\">username<\/p>\n<\/th>\n<th>\n<p align=\"left\">password<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">1<\/p>\n<\/td>\n<td>\n<p align=\"left\">admin<\/p>\n<\/td>\n<td>\n<p align=\"left\">qwerty123<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">2<\/p>\n<\/td>\n<td>\n<p align=\"left\">user<\/p>\n<\/td>\n<td>\n<p align=\"left\">123456<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u044b:<\/p>\n<ul>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0431\u0430\u0437\u0430 \u0443\u0442\u0435\u0447\u0451\u0442 \u2192 \u043c\u043e\u0436\u043d\u043e \u0441\u0440\u0430\u0437\u0443 \u0432\u043e\u0439\u0442\u0438.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0447\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 \u043f\u0430\u0440\u043e\u043b\u044c \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445.<\/p>\n<\/li>\n<li>\n<p>\u0414\u0430\u0436\u0435 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u044b \u0411\u0414 \u0432\u0438\u0434\u044f\u0442 \u043f\u0430\u0440\u043e\u043b\u0438, \u0447\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0440\u0438\u0441\u043a \u0438\u043d\u0441\u0430\u0439\u0434\u0430.<\/p>\n<\/li>\n<\/ul>\n<h4>6.2. \u0425\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u043c\u0435\u0441\u0442\u043e \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u00ab\u043a\u0430\u043a \u0435\u0441\u0442\u044c\u00bb<\/h4>\n<p>\u0425\u0440\u0430\u043d\u0438\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0435 \u043f\u0430\u0440\u043e\u043b\u044c, \u0430 <strong>\u0445\u044d\u0448<\/strong>.<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 (BCrypt):<\/p>\n<pre><code>$2a$10$DowJHd\/8DqzRzTQaI7Em5Ocu8l7v.8dxyl0nHKz3Oy4rQ0cl6iTga<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430:<\/p>\n<ul>\n<li>\n<p>\u041d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u00ab\u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0432\u043e\u0440\u043e\u0442\u0430\u00bb (\u0445\u044d\u0448 \u2014 \u043e\u0434\u043d\u043e\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u044f\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f).<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0437\u043d\u044b\u0435 \u0445\u044d\u0448\u0438 \u0434\u043b\u044f \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0445 \u043f\u0430\u0440\u043e\u043b\u0435\u0439 (\u0438\u0437-\u0437\u0430 \u0441\u043e\u043b\u0438).<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043c\u0435\u0434\u043b\u0435\u043d\u0438\u0435 \u0431\u0440\u0443\u0442\u0444\u043e\u0440\u0441\u0430 (BCrypt \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u00ab\u0442\u043e\u0440\u043c\u043e\u0437\u043d\u043e\u0439\u00bb).<\/p>\n<\/li>\n<\/ul>\n<h4>6.3. \u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b \u0432 Spring Security<\/h4>\n<p>\u0414\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b:<\/p>\n<ul>\n<li>\n<p><strong>BCrypt<\/strong> (<code>BCryptPasswordEncoder<\/code>)<\/p>\n<ul>\n<li>\n<p>\u0421\u0430\u043c\u044b\u0439 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0451\u043d\u043d\u044b\u0439, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442 \u0441\u043e\u043b\u044c + \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 (cost).<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>Argon2<\/strong> (<code>Argon2PasswordEncoder<\/code>)<\/p>\n<ul>\n<li>\n<p>\u041f\u043e\u0431\u0435\u0434\u0438\u0442\u0435\u043b\u044c Password Hashing Competition.<\/p>\n<\/li>\n<li>\n<p>\u0423\u0441\u0442\u043e\u0439\u0447\u0438\u0432 \u043a \u0430\u0442\u0430\u043a\u0430\u043c \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c GPU\/ASIC.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>PBKDF2<\/strong> (<code>Pbkdf2PasswordEncoder<\/code>)<\/p>\n<ul>\n<li>\n<p>\u041c\u0435\u0434\u043b\u0435\u043d\u043d\u044b\u0439 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 HMAC.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>SCrypt<\/strong> (<code>SCryptPasswordEncoder<\/code>)<\/p>\n<ul>\n<li>\n<p>\u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 BCrypt, \u0431\u043e\u043b\u0435\u0435 \u0437\u0430\u0442\u0440\u0430\u0442\u043d\u044b\u0439 \u043f\u043e \u043f\u0430\u043c\u044f\u0442\u0438.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>\u041d\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c:<\/p>\n<ul>\n<li>\n<p>MD5, SHA-1, SHA-256 \u2192 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0431\u044b\u0441\u0442\u0440\u044b\u0435, \u043b\u0435\u0433\u043a\u043e \u043f\u043e\u0434\u0434\u0430\u044e\u0442\u0441\u044f \u0431\u0440\u0443\u0442\u0444\u043e\u0440\u0441\u0443.<\/p>\n<\/li>\n<\/ul>\n<h4>6.4. PasswordEncoder \u0432 \u043a\u043e\u0434\u0435<\/h4>\n<p>Spring \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0435\u043b\u0435\u0433\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u044d\u043d\u043a\u043e\u0434\u0435\u0440:<\/p>\n<pre><code class=\"java\">@Beanpublic PasswordEncoder passwordEncoder() {    return PasswordEncoderFactories.createDelegatingPasswordEncoder();}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u043d \u0441\u043e\u0437\u0434\u0430\u0451\u0442 <code>DelegatingPasswordEncoder<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e = BCrypt, \u043d\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b.<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0437\u0430\u043f\u0438\u0441\u0438 \u043f\u0430\u0440\u043e\u043b\u044f \u0432 \u0411\u0414:<\/p>\n<pre><code>{bcrypt}$2a$10$DowJHd\/8DqzRzTQaI7Em5Ocu8l7v.8dxyl0nHKz3Oy4rQ0cl6iTga<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>6.5. \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u0430\u0440\u043e\u043b\u044f<\/h4>\n<p>\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c:<\/p>\n<ol>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u0432\u043e\u0434\u0438\u0442 \u043f\u0430\u0440\u043e\u043b\u044c.<\/p>\n<\/li>\n<li>\n<p><code>PasswordEncoder.matches(rawPassword, storedHash)<\/code> \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u0442 \u0432\u0432\u0435\u0434\u0451\u043d\u043d\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c \u0438 \u0445\u044d\u0448.<\/p>\n<\/li>\n<li>\n<p>\u0412 Spring Security \u044d\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432 <code>DaoAuthenticationProvider<\/code>.<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code class=\"java\">String raw = \"qwerty123\";String encoded = passwordEncoder.encode(raw);boolean matches = passwordEncoder.matches(raw, encoded); \/\/ true<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>6.6. Best Practices<\/h4>\n<ul>\n<li>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <strong>BCrypt<\/strong> \u0438\u043b\u0438 <strong>Argon2<\/strong>.<\/p>\n<\/li>\n<li>\n<p>\u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043b\u0438\u043d\u0430 \u043f\u0430\u0440\u043e\u043b\u044f \u2014 8\u201312 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432, \u043b\u0443\u0447\u0448\u0435 12\u201316.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u0447\u0438\u0441\u043b\u0430 \u043f\u043e\u043f\u044b\u0442\u043e\u043a \u0432\u0445\u043e\u0434\u0430 (\u0437\u0430\u0449\u0438\u0442\u0430 \u043e\u0442 brute force).<\/p>\n<\/li>\n<li>\n<p>\u0425\u0440\u0430\u043d\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0445\u044d\u0448, \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u00ab\u0441\u044b\u0440\u043e\u0439\u00bb \u043f\u0430\u0440\u043e\u043b\u044c.<\/p>\n<\/li>\n<li>\n<p>\u0420\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044f \u0441 BCrypt \u2192 Argon2).<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c 2FA \u0434\u043b\u044f \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c.<\/p>\n<\/li>\n<\/ul>\n<h3>7. AuthenticationManager \u0438 UserDetailsService<\/h3>\n<p>Spring Security \u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u043b\u044e\u0431\u044b\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438 \u2014 SQL-\u0411\u0414, LDAP \u0438\u043b\u0438 OAuth2.<br \/> \u0412 \u043e\u0441\u043d\u043e\u0432\u0435 \u043b\u0435\u0436\u0430\u0442 \u0442\u0440\u0438 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430:<\/p>\n<ul>\n<li>\n<p><strong>AuthenticationManager<\/strong> \u2014 \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u00ab\u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u00bb \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>AuthenticationProvider<\/strong> \u2014 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0411\u0414 \u0438\u043b\u0438 JWT).<\/p>\n<\/li>\n<li>\n<p><strong>UserDetailsService<\/strong> \u2014 \u0437\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435 (\u043e\u0431\u044b\u0447\u043d\u043e \u0438\u0437 \u0411\u0414).<\/p>\n<\/li>\n<\/ul>\n<h4>7.1. Authentication (\u043e\u0431\u044a\u0435\u043a\u0442 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438)<\/h4>\n<p>\u041f\u0440\u0438 \u0432\u0445\u043e\u0434\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f Spring Security \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 <code>Authentication<\/code>.<\/p>\n<p>\u0414\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438:<\/p>\n<pre><code class=\"java\">UsernamePasswordAuthenticationToken [Principal=admin, Credentials=123456, Authenticated=false]<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438:<\/p>\n<pre><code class=\"java\">UsernamePasswordAuthenticationToken [Principal=User(admin,ROLE_ADMIN), Credentials=[PROTECTED], Authenticated=true]<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043f\u043e\u043b\u044f:<\/p>\n<ul>\n<li>\n<p><code>Principal<\/code> \u2192 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435 (\u043e\u0431\u044b\u0447\u043d\u043e UserDetails).<\/p>\n<\/li>\n<li>\n<p><code>Credentials<\/code> \u2192 \u0447\u0435\u043c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043d \u0432\u0445\u043e\u0434 (\u043f\u0430\u0440\u043e\u043b\u044c, \u0442\u043e\u043a\u0435\u043d).<\/p>\n<\/li>\n<li>\n<p><code>Authorities<\/code> \u2192 \u043f\u0440\u0430\u0432\u0430 (<code>ROLE_USER<\/code>, <code>ROLE_ADMIN<\/code>).<\/p>\n<\/li>\n<\/ul>\n<h4>7.2. AuthenticationManager<\/h4>\n<p>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0441 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u043c\u0435\u0442\u043e\u0434\u043e\u043c:<\/p>\n<pre><code class=\"java\">public interface AuthenticationManager {    Authentication authenticate(Authentication authentication) throws AuthenticationException;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435: \u043f\u0440\u0438\u043d\u044f\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e \u0438 \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 (<code>Authentication<\/code>) \u0438\u043b\u0438 \u0432\u044b\u0431\u0440\u043e\u0441\u0438\u0442\u044c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435.<\/p>\n<h4>7.3. AuthenticationProvider<\/h4>\n<p><code>AuthenticationManager<\/code> \u0434\u0435\u043b\u0435\u0433\u0438\u0440\u0443\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043e\u0434\u043d\u043e\u043c\u0443 \u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c <strong>AuthenticationProvider<\/strong>.<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440\u044b \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u043e\u0432:<\/p>\n<ul>\n<li>\n<p><code>DaoAuthenticationProvider<\/code> \u2192 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043b\u043e\u0433\u0438\u043d\u0430\/\u043f\u0430\u0440\u043e\u043b\u044f \u0447\u0435\u0440\u0435\u0437 <code>UserDetailsService<\/code>.<\/p>\n<\/li>\n<li>\n<p><code>LdapAuthenticationProvider<\/code> \u2192 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0432 LDAP\/Active Directory.<\/p>\n<\/li>\n<li>\n<p><code>JwtAuthenticationProvider<\/code> \u2192 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 JWT-\u0442\u043e\u043a\u0435\u043d\u0430.<\/p>\n<\/li>\n<\/ul>\n<h4>7.4. UserDetailsService<\/h4>\n<p>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0437 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0411\u0414):<\/p>\n<pre><code class=\"java\">public interface UserDetailsService {    UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 (\u0447\u0435\u0440\u0435\u0437 JPA):<\/p>\n<pre><code class=\"java\">@Servicepublic class MyUserDetailsService implements UserDetailsService {    private final UserRepository userRepository;    @Override    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {        UserEntity user = userRepository.findByUsername(username)            .orElseThrow(() -&gt; new UsernameNotFoundException(\"User not found: \" + username));        return org.springframework.security.core.userdetails.User            .withUsername(user.getUsername())            .password(user.getPassword()) \/\/ \u0443\u0436\u0435 \u0437\u0430\u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c!            .roles(user.getRole())            .build();    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>7.5. \u041a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441\u0432\u044f\u0437\u043a\u0430<\/h4>\n<ol>\n<li>\n<p>\u041a\u043b\u0438\u0435\u043d\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 <code>POST \/login<\/code> \u0441 \u043b\u043e\u0433\u0438\u043d\u043e\u043c \u0438 \u043f\u0430\u0440\u043e\u043b\u0435\u043c.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0438\u043b\u044c\u0442\u0440 <code>UsernamePasswordAuthenticationFilter<\/code> \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0438 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 <code>UsernamePasswordAuthenticationToken<\/code>.<\/p>\n<\/li>\n<li>\n<p><code>AuthenticationManager<\/code> \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442 \u0442\u043e\u043a\u0435\u043d \u0432 <code>DaoAuthenticationProvider<\/code>.<\/p>\n<\/li>\n<li>\n<p><code>DaoAuthenticationProvider<\/code>:<\/p>\n<ul>\n<li>\n<p>\u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 <code>UserDetailsService.loadUserByUsername(username)<\/code><\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0437 \u0411\u0414<\/p>\n<\/li>\n<li>\n<p>\u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u0442 \u043f\u0430\u0440\u043e\u043b\u044c \u0447\u0435\u0440\u0435\u0437 <code>PasswordEncoder.matches()<\/code><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438 \u0443\u0441\u043f\u0435\u0445\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f <code>Authentication<\/code> \u0441 <code>Authenticated=true<\/code>.<\/p>\n<\/li>\n<li>\n<p><code>SecurityContextHolder<\/code> \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0438 \u043e\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u0445 \u0447\u0435\u0440\u0435\u0437 <code>@AuthenticationPrincipal<\/code>.<\/p>\n<\/li>\n<\/ol>\n<h4>7.6. \u041f\u0440\u0438\u043c\u0435\u0440 SecurityConfig<\/h4>\n<pre><code class=\"java\">@Configuration@EnableMethodSecuritypublic class SecurityConfig {    private final UserDetailsService userDetailsService;    private final PasswordEncoder passwordEncoder;    @Bean    public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {        return http            .getSharedObject(AuthenticationManagerBuilder.class)            .userDetailsService(userDetailsService)            .passwordEncoder(passwordEncoder)            .and()            .build();    }    @Bean    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {        http            .authorizeHttpRequests(auth -&gt; auth                .requestMatchers(\"\/admin\/**\").hasRole(\"ADMIN\")                .anyRequest().authenticated()            )            .formLogin(Customizer.withDefaults());        return http.build();    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>7.7. Best Practices<\/h4>\n<ul>\n<li>\n<p>\u0412\u0441\u0435\u0433\u0434\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>PasswordEncoder<\/code> \u043f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0440\u043e\u043b\u0435\u0439 (user\/role).<\/p>\n<\/li>\n<li>\n<p>\u0414\u043b\u044f \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043b\u043e\u0433\u0438\u043d \u043f\u043e email \u0438\u043b\u0438 \u043d\u043e\u043c\u0435\u0440\u0443 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430) \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u0439 <code>UserDetailsService<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e <code>AuthenticationProvider<\/code> (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u0411\u0414 \u0438 JWT \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e).<\/p>\n<\/li>\n<\/ul>\n<ul>\n<li>\n<p><code>AuthenticationManager<\/code> \u2014 \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p><code>AuthenticationProvider<\/code> \u2014 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p><code>UserDetailsService<\/code> \u2014 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0437 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u0441\u0432\u044f\u0437\u043a\u0435 \u043e\u043d\u0438 \u0434\u0430\u044e\u0442 \u0433\u0438\u0431\u043a\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0432 Spring Security.<\/p>\n<\/li>\n<\/ul>\n<h3>8. SecurityContext \u0438 SecurityContextHolder<\/h3>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u0440\u043e\u0448\u0451\u043b \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e, Spring Security \u0434\u043e\u043b\u0436\u0435\u043d \u0433\u0434\u0435-\u0442\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043d\u0451\u043c, \u0447\u0442\u043e\u0431\u044b:<\/p>\n<ul>\n<li>\n<p>\u043d\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043f\u0430\u0440\u043e\u043b\u044c \u0437\u0430\u043d\u043e\u0432\u043e \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441,<\/p>\n<\/li>\n<li>\n<p>\u0431\u044b\u0441\u0442\u0440\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u043a\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u043b \u0437\u0430\u043f\u0440\u043e\u0441,<\/p>\n<\/li>\n<li>\n<p>\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043f\u0440\u0430\u0432\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u0445 \u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u0432\u044f\u0437\u043a\u0430:<\/p>\n<ul>\n<li>\n<p><strong>SecurityContext<\/strong> \u2014 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440, \u0433\u0434\u0435 \u043b\u0435\u0436\u0438\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435.<\/p>\n<\/li>\n<li>\n<p><strong>SecurityContextHolder<\/strong> \u2014 \u0443\u0442\u0438\u043b\u0438\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u0430\u0451\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0442\u0435\u043a\u0443\u0449\u0435\u043c\u0443 <code>SecurityContext<\/code>.<\/p>\n<\/li>\n<\/ul>\n<h4>8.1. SecurityContext<\/h4>\n<p><code>SecurityContext<\/code> \u2014 \u044d\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0445\u0440\u0430\u043d\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0443 \u0432\u0435\u0449\u044c: <strong>Authentication<\/strong>.<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code class=\"java\">SecurityContext context = SecurityContextHolder.getContext();Authentication auth = context.getAuthentication();<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412\u043d\u0443\u0442\u0440\u0438 <code>Authentication<\/code> \u043b\u0435\u0436\u0438\u0442:<\/p>\n<ul>\n<li>\n<p><code>Principal<\/code> \u2014 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c (\u043e\u0431\u044b\u0447\u043d\u043e UserDetails).<\/p>\n<\/li>\n<li>\n<p><code>Authorities<\/code> \u2014 \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u043e\u043b\u0435\u0439\/\u043f\u0440\u0430\u0432 (<code>ROLE_USER<\/code>, <code>ROLE_ADMIN<\/code>).<\/p>\n<\/li>\n<li>\n<p><code>Details<\/code> \u2014 \u0434\u043e\u043f. \u0434\u0430\u043d\u043d\u044b\u0435 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, IP, sessionId).<\/p>\n<\/li>\n<\/ul>\n<h4>8.2. SecurityContextHolder<\/h4>\n<p>\u042d\u0442\u043e <strong>\u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435<\/strong>, \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0442\u0435\u043a\u0443\u0449\u0435\u043c\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e.<\/p>\n<pre><code class=\"java\">Authentication authentication = SecurityContextHolder.getContext().getAuthentication();String username = authentication.getName();<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>SecurityContextHolder<\/code> \u043e\u0431\u044b\u0447\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 <strong>ThreadLocal<\/strong>:<\/p>\n<ul>\n<li>\n<p>\u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a (\u0432 servlet-\u043c\u043e\u0434\u0435\u043b\u0438).<\/p>\n<\/li>\n<li>\n<p>\u0412 \u044d\u0442\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f <code>SecurityContext<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0437\u0430\u043f\u0440\u043e\u0441 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043b\u0441\u044f \u2192 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u043e\u0447\u0438\u0449\u0430\u0435\u0442\u0441\u044f.<\/p>\n<\/li>\n<\/ul>\n<h4>8.3. \u0412\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f (Modes)<\/h4>\n<p>Spring Security \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0439 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430:<\/p>\n<ol>\n<li>\n<p><strong>MODE_THREADLOCAL<\/strong> (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e)<\/p>\n<ul>\n<li>\n<p>\u041a\u0430\u0436\u0434\u044b\u0439 \u043f\u043e\u0442\u043e\u043a \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0439 SecurityContext.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0430\u043c\u044b\u0439 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>MODE_INHERITABLETHREADLOCAL<\/strong><\/p>\n<ul>\n<li>\n<p>\u0414\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u043f\u043e\u0442\u043e\u043a\u0438 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u044e\u0442 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0443\u0436\u043d\u043e \u0440\u0435\u0434\u043a\u043e (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u0438 async-\u0437\u0430\u0434\u0430\u0447\u0430\u0445).<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>MODE_GLOBAL<\/strong><\/p>\n<ul>\n<li>\n<p>\u041e\u0434\u0438\u043d \u043e\u0431\u0449\u0438\u0439 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0434\u043b\u044f \u0432\u0441\u0435\u0445.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0447\u0442\u0438 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f (\u043d\u0435\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e).<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<h4>8.4. SecurityContextPersistenceFilter<\/h4>\n<p>\u041a\u0442\u043e \u0432\u043e\u043e\u0431\u0449\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0438 \u0434\u043e\u0441\u0442\u0430\u0451\u0442 SecurityContext?<\/p>\n<p>\u042d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u0444\u0438\u043b\u044c\u0442\u0440 <code>SecurityContextPersistenceFilter<\/code>:<\/p>\n<ul>\n<li>\n<p>\u0412 \u043d\u0430\u0447\u0430\u043b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043e\u043d \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 (\u0438\u0437 \u0441\u0435\u0441\u0441\u0438\u0438 \u0438\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043d\u043e\u0432\u044b\u0439).<\/p>\n<\/li>\n<li>\n<p>\u0412 \u043a\u043e\u043d\u0446\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043e\u043d \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0451\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u043e\u0431\u0440\u0430\u0442\u043d\u043e.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u043b\u044f stateless (JWT) \u2014 \u043d\u043e\u0432\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441.<br \/> \u0414\u043b\u044f stateful (\u0441\u0435\u0441\u0441\u0438\u0438) \u2014 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0434\u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u0438\u0437 <code>HttpSession<\/code>.<\/p>\n<h4>8.5. \u0414\u043e\u0441\u0442\u0443\u043f \u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u0445<\/h4>\n<p>Spring Security \u0434\u0430\u0451\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u044e\u0437\u0435\u0440\u0430:<\/p>\n<h4>\u0427\u0435\u0440\u0435\u0437 Authentication<\/h4>\n<pre><code class=\"java\">@GetMapping(\"\/me\")public String me(Authentication auth) {    return \"Hello \" + auth.getName();}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>\u0427\u0435\u0440\u0435\u0437 SecurityContextHolder<\/h4>\n<pre><code class=\"java\">@GetMapping(\"\/me\")public String me() {    Authentication auth = SecurityContextHolder.getContext().getAuthentication();    return \"Hello \" + auth.getName();}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>\u0427\u0435\u0440\u0435\u0437 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e @AuthenticationPrincipal<\/h4>\n<pre><code class=\"java\">@GetMapping(\"\/me\")public String me(@AuthenticationPrincipal UserDetails user) {    return \"Hello \" + user.getUsername();}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>8.6. \u041f\u0440\u0438\u043c\u0435\u0440 \u0432 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445<\/h4>\n<p>\u041c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u0445, \u043d\u043e \u0438 \u0432 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445:<\/p>\n<pre><code class=\"java\">@Servicepublic class AccountService {    public void doSomething() {        Authentication auth = SecurityContextHolder.getContext().getAuthentication();        String user = auth.getName();        System.out.println(\"Action by: \" + user);    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>8.7. \u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0432 WebFlux (\u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445)<\/h4>\n<p>\u0412 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 <strong>\u043d\u0435\u0442 ThreadLocal<\/strong>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 <code>SecurityContextHolder<\/code> \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e.<br \/> \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <strong>ReactiveSecurityContextHolder<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0445\u0440\u0430\u043d\u0438\u0442 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0432 Reactor Context.<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code class=\"java\">Mono&lt;String&gt; currentUser = ReactiveSecurityContextHolder.getContext()    .map(ctx -&gt; ctx.getAuthentication().getName());<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>8.8. Best Practices<\/h4>\n<ul>\n<li>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>@AuthenticationPrincipal<\/code> \u0434\u043b\u044f \u0447\u0438\u0441\u0442\u043e\u0442\u044b \u043a\u043e\u0434\u0430 \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u0445.<\/p>\n<\/li>\n<li>\n<p>\u0418\u0437\u0431\u0435\u0433\u0430\u0442\u044c \u043f\u0440\u044f\u043c\u043e\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u0430 <code>SecurityContextHolder<\/code> \u0432\u0435\u0437\u0434\u0435 \u2014 \u043b\u0443\u0447\u0448\u0435 \u0432 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u0432\u0441\u0435\u0433\u0434\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>ReactiveSecurityContextHolder<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043b\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <code>@Async<\/code>) \u2192 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>DelegatingSecurityContextExecutorService<\/code>, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0432 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u043e\u0442\u043e\u043a\u0438.<\/p>\n<\/li>\n<\/ul>\n<ul>\n<li>\n<p><code>SecurityContext<\/code> \u0445\u0440\u0430\u043d\u0438\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<\/li>\n<li>\n<p><code>SecurityContextHolder<\/code> \u0434\u0430\u0451\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043d\u0435\u043c\u0443.<\/p>\n<\/li>\n<li>\n<p>\u0412 Servlet (stateful\/stateless) \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f ThreadLocal, \u0432 WebFlux \u2014 Reactor Context.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043b\u043e\u0433\u0438\u043d\u0430 \u0432\u0441\u044f \u0438\u043d\u0444\u0430 \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435 \u0436\u0438\u0432\u0451\u0442 \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0443\u0442.<\/p>\n<\/li>\n<\/ul>\n<h3>9. \u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0432 Spring Security<\/h3>\n<p>\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441: <strong>\u00ab\u041a\u0442\u043e \u044d\u0442\u043e?\u00bb<\/strong>, \u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u2014 <strong>\u00ab\u0427\u0442\u043e \u044d\u0442\u043e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442?\u00bb<\/strong>.<\/p>\n<p>Spring Security \u0434\u0435\u043b\u0430\u0435\u0442 \u044d\u0442\u043e \u0447\u0435\u0440\u0435\u0437 \u0446\u0435\u043f\u043e\u0447\u043a\u0443: <strong>Voters \u2192 AccessDecisionManager \u2192 \u0444\u0438\u043b\u044c\u0442\u0440\u044b \/ \u043c\u0435\u0442\u043e\u0434\u044b<\/strong>.<\/p>\n<h4>9.1. \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u043e\u043d\u044f\u0442\u0438\u044f<\/h4>\n<p><strong>Authentication (\u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f)<\/strong><\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043b\u0438\u0447\u043d\u043e\u0441\u0442\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f (\u043b\u043e\u0433\u0438\u043d\/\u043f\u0430\u0440\u043e\u043b\u044c, \u0442\u043e\u043a\u0435\u043d, OAuth2).<\/p>\n<\/li>\n<\/ul>\n<p><strong>Authorization (\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f)<\/strong><\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u0440\u0430\u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 (roles\/permissions\/authorities).<\/p>\n<\/li>\n<\/ul>\n<p><strong>Principal<\/strong><\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432\u043d\u0443\u0442\u0440\u0438 <code>Authentication<\/code> (\u043e\u0431\u044b\u0447\u043d\u043e <code>UserDetails<\/code>).<\/p>\n<\/li>\n<\/ul>\n<p><strong>Authorities \/ Roles<\/strong><\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u0430\u0432\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440: <code>ROLE_USER<\/code>, <code>ROLE_ADMIN<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0437\u043d\u0438\u0446\u0430: \u0440\u043e\u043b\u044c \u2014 \u044d\u0442\u043e \u0443\u043f\u0440\u043e\u0449\u0451\u043d\u043d\u043e\u0435 \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0433\u0440\u0443\u043f\u043f\u044b \u043f\u0440\u0430\u0432, authority \u2014 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0435 \u043f\u0440\u0430\u0432\u043e (<code>READ_ACCOUNT<\/code>).<\/p>\n<\/li>\n<\/ul>\n<p><strong>AccessDecisionManager<\/strong><\/p>\n<ul>\n<li>\n<p>\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0414\u0435\u043b\u0435\u0433\u0438\u0440\u0443\u0435\u0442 \u0433\u043e\u043b\u043e\u0441\u043e\u0432\u0430\u043d\u0438\u0435 \u043a <strong>Voters<\/strong>.<\/p>\n<\/li>\n<\/ul>\n<p><strong>Voters<\/strong><\/p>\n<ul>\n<li>\n<p>\u0413\u043e\u043b\u043e\u0441\u0443\u044e\u0442 \u0437\u0430\/\u043f\u0440\u043e\u0442\u0438\u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0438\u043f\u044b:<\/p>\n<ul>\n<li>\n<p><code>RoleVoter<\/code> \u2014 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0440\u043e\u043b\u0438.<\/p>\n<\/li>\n<li>\n<p><code>AuthenticatedVoter<\/code> \u2014 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d \u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c.<\/p>\n<\/li>\n<li>\n<p><code>WebExpressionVoter<\/code> \u2014 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 SpEL-\u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f (<code>hasRole('ADMIN')<\/code>).<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h4>9.2. URL vs \u041c\u0435\u0442\u043e\u0434\u043d\u0430\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f<\/h4>\n<h4>1. URL-\u0443\u0440\u043e\u0432\u0435\u043d\u044c (HTTP \u0437\u0430\u043f\u0440\u043e\u0441\u044b)<\/h4>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0447\u0435\u0440\u0435\u0437 DSL:<\/p>\n<pre><code class=\"java\">http    .authorizeHttpRequests(auth -&gt; auth        .requestMatchers(\"\/public\/**\").permitAll()        .requestMatchers(\"\/admin\/**\").hasRole(\"ADMIN\")        .anyRequest().authenticated()    );<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442:<\/p>\n<ol>\n<li>\n<p><code>FilterSecurityInterceptor<\/code> \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0438 <code>Authentication<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442, \u043a\u0430\u043a\u043e\u0439 URL \u0437\u0430\u0442\u0440\u0430\u0433\u0438\u0432\u0430\u0435\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u043e.<\/p>\n<\/li>\n<li>\n<p>AccessDecisionManager \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 Voters \u2192 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 (grant\/deny).<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 deny \u2192 403 Forbidden.<\/p>\n<\/li>\n<\/ol>\n<h4>2. \u041c\u0435\u0442\u043e\u0434\u043d\u0430\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c<\/h4>\n<p>Spring \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 \u043f\u0440\u044f\u043c\u043e \u043d\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u044b:<\/p>\n<pre><code class=\"java\">@PreAuthorize(\"hasRole('ADMIN')\")public void deleteUser(Long id) { ... }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p>\u041f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c: AOP-\u043f\u0440\u043e\u043a\u0441\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 AccessDecisionManager.<\/p>\n<\/li>\n<li>\n<p>\u041c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f:<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"java\">@PreAuthorize(\"#userId == principal.id or hasRole('ADMIN')\")<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p><code>principal<\/code> \u2014 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c.<\/p>\n<\/li>\n<li>\n<p><code>#userId<\/code> \u2014 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u043c\u0435\u0442\u043e\u0434\u0430.<\/p>\n<\/li>\n<\/ul>\n<h4>9.3. Expression Language (SpEL)<\/h4>\n<p><code>SpEL<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0443\u0441\u043b\u043e\u0432\u0438\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 <code>Authentication<\/code>:<\/p>\n<ul>\n<li>\n<p><code>hasRole('ROLE_ADMIN')<\/code> \u2014 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0440\u043e\u043b\u0438.<\/p>\n<\/li>\n<li>\n<p><code>hasAuthority('WRITE_PRIVILEGE')<\/code> \u2014 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u0440\u0430\u0432\u0430.<\/p>\n<\/li>\n<li>\n<p><code>principal.username == 'bob'<\/code> \u2014 \u0434\u043e\u0441\u0442\u0443\u043f \u0434\u043b\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<\/li>\n<li>\n<p><code>#param == authentication.name<\/code> \u2014 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u0441 \u0442\u0435\u043a\u0443\u0449\u0438\u043c \u0438\u043c\u0435\u043d\u0435\u043c.<\/p>\n<\/li>\n<\/ul>\n<h4>9.4. \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u0440\u0438\u043d\u044f\u0442\u0438\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u0439<\/h4>\n<ol>\n<li>\n<p>\u0417\u0430\u043f\u0440\u043e\u0441 \u0434\u043e\u0448\u0451\u043b \u0434\u043e <code>FilterSecurityInterceptor<\/code> (web) \u0438\u043b\u0438 \u043c\u0435\u0442\u043e\u0434 \u0432\u044b\u0437\u0432\u0430\u043d (service).<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c <code>Authentication<\/code> \u0438\u0437 <code>SecurityContext<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043f\u0440\u0430\u0432\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, URL pattern \u0438\u043b\u0438 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044f).<\/p>\n<\/li>\n<li>\n<p>AccessDecisionManager \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0432\u0441\u0435 Voters.<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u0436\u0434\u043e\u0435 \u0433\u043e\u043b\u043e\u0441\u043e\u0432\u0430\u043d\u0438\u0435:<\/p>\n<ul>\n<li>\n<p><code>ACCESS_GRANTED<\/code> \u2192 \u043f\u043b\u044e\u0441.<\/p>\n<\/li>\n<li>\n<p><code>ACCESS_DENIED<\/code> \u2192 \u043c\u0438\u043d\u0443\u0441.<\/p>\n<\/li>\n<li>\n<p><code>ABSTAIN<\/code> \u2192 \u0438\u0433\u043d\u043e\u0440.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>\u0418\u0442\u043e\u0433\u043e\u0432\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0438:<\/p>\n<ul>\n<li>\n<p><strong>AffirmativeBased<\/strong> \u2014 \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u0438\u043d grant \u2192 \u0434\u043e\u0441\u0442\u0443\u043f \u0440\u0430\u0437\u0440\u0435\u0448\u0451\u043d.<\/p>\n<\/li>\n<li>\n<p><strong>UnanimousBased<\/strong> \u2014 \u0432\u0441\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0434\u0430\u0442\u044c grant \u2192 \u0434\u043e\u0441\u0442\u0443\u043f \u0440\u0430\u0437\u0440\u0435\u0448\u0451\u043d.<\/p>\n<\/li>\n<li>\n<p><strong>ConsensusBased<\/strong> \u2014 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e vote \u2192 grant.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<h4>9.5. \u0420\u043e\u043b\u0438 \u0438 authorities<\/h4>\n<ul>\n<li>\n<p><strong>\u0420\u043e\u043b\u044c (<\/strong><code><strong>ROLE_...<\/strong><\/code><strong>)<\/strong> \u2014 \u044d\u0442\u043e \u0433\u0440\u0443\u0431\u0430\u044f \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p><strong>Authority<\/strong> \u2014 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0435 \u043f\u0440\u0430\u0432\u043e (<code>READ_ACCOUNT<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u0412 Spring Security <code>RoleVoter<\/code> \u0438\u0449\u0435\u0442 \u043f\u0440\u0435\u0444\u0438\u043a\u0441 <code>ROLE_<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041c\u043e\u0436\u043d\u043e \u043d\u0430\u0437\u043d\u0430\u0447\u0430\u0442\u044c \u0441\u0440\u0430\u0437\u0443 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u043e\u043b\u0435\u0439\/authorities \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0432 <code>UserDetails<\/code>:<\/p>\n<pre><code class=\"java\">@Overridepublic Collection&lt;? extends GrantedAuthority&gt; getAuthorities() {    return List.of(new SimpleGrantedAuthority(\"ROLE_USER\"),                   new SimpleGrantedAuthority(\"READ_ACCOUNT\"));}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>9.6. \u0410\u0443\u0434\u0438\u0442 \u0438 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0430<\/h4>\n<ul>\n<li>\n<p>Spring Security \u0443\u043c\u0435\u0435\u0442 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c: \u043a\u0442\u043e \u043f\u043e\u043f\u044b\u0442\u0430\u043b\u0441\u044f, \u0441 \u043a\u0430\u043a\u043e\u0433\u043e IP, \u043a\u0430\u043a\u043e\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442.<\/p>\n<\/li>\n<li>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430 \u0438 \u0432\u044b\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u043e\u0437\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code class=\"java\">@Beanpublic AuditorAware&lt;String&gt; auditorProvider() {    return () -&gt; Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication().getName());}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p>\u041c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043a <code>@CreatedBy<\/code> \u0438 <code>@LastModifiedBy<\/code> \u0432 JPA.<\/p>\n<\/li>\n<\/ul>\n<h4>9.7. Best Practices<\/h4>\n<ul>\n<li>\n<p>\u041d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0442\u043e\u043b\u044c\u043a\u043e URL-\u043f\u0430\u0442\u0442\u0435\u0440\u043d\u044b \u2014 \u0432\u0441\u0435\u0433\u0434\u0430 \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u0443\u0439\u0442\u0435 \u0441 \u043c\u0435\u0442\u043e\u0434\u043d\u043e\u0439 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c\u044e.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043b\u044f REST API: \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0439\u0442\u0435 authorities, \u0430 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0440\u043e\u043b\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043b\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u043f\u043e\u043b\u0438\u0442\u0438\u043a: \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 SpEL expressions.<\/p>\n<\/li>\n<li>\n<p>\u041c\u0438\u043d\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0439\u0442\u0435 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u2014 <code>permitAll()<\/code> \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0430\u043c, \u0433\u0434\u0435 \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e.<\/p>\n<\/li>\n<li>\n<p>\u041b\u043e\u0433\u0438\u0440\u0443\u0439\u0442\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0434\u043b\u044f \u0430\u0443\u0434\u0438\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 <code>ReactiveAuthorizationManager<\/code>.<\/p>\n<\/li>\n<\/ul>\n<h4>9.8. \u041f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440<\/h4>\n<pre><code class=\"java\">@RestController@RequestMapping(\"\/accounts\")public class AccountController {    @GetMapping(\"\/{id}\")    @PreAuthorize(\"#id == principal.id or hasRole('ADMIN')\")    public Account getAccount(@PathVariable Long id) {        return accountService.getAccount(id);    }    @PostMapping(\"\/\")    @PreAuthorize(\"hasAuthority('WRITE_ACCOUNT')\")    public Account createAccount(@RequestBody Account account) {        return accountService.createAccount(account);    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p>\u041d\u0430 GET \u0434\u043e\u0441\u0442\u0443\u043f \u0438\u043c\u0435\u044e\u0442 \u043b\u0438\u0431\u043e \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u044b, \u043b\u0438\u0431\u043e \u0432\u043b\u0430\u0434\u0435\u043b\u0435\u0446.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430 POST \u2014 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435, \u0443 \u043a\u043e\u0433\u043e \u0435\u0441\u0442\u044c \u043f\u0440\u0430\u0432\u043e <code>WRITE_ACCOUNT<\/code>.<\/p>\n<\/li>\n<\/ul>\n<ul>\n<li>\n<p>URL \u0438 \u043c\u0435\u0442\u043e\u0434\u043d\u0430\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u2014 \u0434\u0432\u0430 \u0443\u0440\u043e\u0432\u043d\u044f \u0437\u0430\u0449\u0438\u0442\u044b.<\/p>\n<\/li>\n<li>\n<p>AccessDecisionManager + Voters \u2192 \u0440\u0435\u0448\u0430\u044e\u0442, \u043c\u043e\u0436\u043d\u043e \u043b\u0438.<\/p>\n<\/li>\n<li>\n<p>SpEL \u0434\u0430\u0451\u0442 \u0433\u0438\u0431\u043a\u043e\u0441\u0442\u044c \u0434\u043b\u044f \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u043f\u0440\u0430\u0432\u0438\u043b.<\/p>\n<\/li>\n<li>\n<p>\u0420\u043e\u043b\u0438 \u0438 authorities \u2014 \u0440\u0430\u0437\u043d\u044b\u0435 \u043f\u043e\u043d\u044f\u0442\u0438\u044f, \u043d\u043e \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0434\u043b\u044f fine-grained access.<\/p>\n<\/li>\n<\/ul>\n<h3>10. OAuth2, JWT \u0438 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0435 \u0442\u043e\u043a\u0435\u043d\u044b (Tokens)<\/h3>\n<p>Spring Security \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 <strong>OAuth2<\/strong> \u0438 <strong>JWT<\/strong> \u0441 \u043f\u043e\u043b\u043d\u044b\u043c \u043d\u0430\u0431\u043e\u0440\u043e\u043c \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 \u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u0449\u0438\u0449\u0430\u0442\u044c API \u0438 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0434\u0430\u0436\u0435 \u0432 stateless-\u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f\u0445 (\u0431\u0435\u0437 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0445 \u0441\u0435\u0441\u0441\u0438\u0439).<\/p>\n<h4>10.1. \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u043e\u043d\u044f\u0442\u0438\u044f<\/h4>\n<p><strong>OAuth2 (Open Authorization 2.0)<\/strong><br \/> \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442 \u0434\u0435\u043b\u0435\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438. \u041f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0431\u0435\u0437 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0435\u0433\u043e \u043f\u0430\u0440\u043e\u043b\u044f.<br \/> \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0440\u043e\u043b\u0438:<\/p>\n<ol>\n<li>\n<p><strong>Resource Owner<\/strong> \u2014 \u0432\u043b\u0430\u0434\u0435\u043b\u0435\u0446 \u0440\u0435\u0441\u0443\u0440\u0441\u0430 (\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c).<\/p>\n<\/li>\n<li>\n<p><strong>Client<\/strong> \u2014 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u044e\u0449\u0435\u0435 \u0434\u043e\u0441\u0442\u0443\u043f.<\/p>\n<\/li>\n<li>\n<p><strong>Authorization Server<\/strong> \u2014 \u0441\u0435\u0440\u0432\u0435\u0440 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u0432\u044b\u0434\u0430\u044e\u0449\u0438\u0439 \u0442\u043e\u043a\u0435\u043d\u044b.<\/p>\n<\/li>\n<li>\n<p><strong>Resource Server<\/strong> \u2014 \u0437\u0430\u0449\u0438\u0449\u0451\u043d\u043d\u044b\u0439 API, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0449\u0438\u0439 \u0442\u043e\u043a\u0435\u043d\u044b.<\/p>\n<\/li>\n<\/ol>\n<p><strong>JWT (JSON Web Token)<\/strong><br \/> \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u0442\u043e\u043a\u0435\u043d\u0430: <code>header.payload.signature<\/code>.<\/p>\n<ul>\n<li>\n<p>\u041f\u043e\u0434\u043f\u0438\u0441\u044c (HMAC, RS256, ES256) \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u0442 \u043e\u0442 \u043f\u043e\u0434\u0434\u0435\u043b\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p>Payload \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 claims: <code>sub<\/code> (subject\/\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c), <code>exp<\/code> (\u0441\u0440\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f), <code>roles<\/code>, <code>iss<\/code> (issuer), <code>aud<\/code> (audience).<\/p>\n<\/li>\n<li>\n<p>Stateless: \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0435 \u0445\u0440\u0430\u043d\u0438\u0442 \u0441\u0435\u0441\u0441\u0438\u0439, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0433\u043e \u0442\u043e\u043a\u0435\u043d\u0430.<\/p>\n<\/li>\n<\/ul>\n<p><strong>Access Token<\/strong><br \/> \u041a\u043e\u0440\u043e\u0442\u043a\u043e\u0436\u0438\u0432\u0443\u0449\u0438\u0439 \u0442\u043e\u043a\u0435\u043d, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c.<\/p>\n<p><strong>Refresh Token<\/strong><br \/> \u0414\u043e\u043b\u0433\u043e\u0436\u0438\u0432\u0443\u0449\u0438\u0439 \u0442\u043e\u043a\u0435\u043d, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0439 access token \u0431\u0435\u0437 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0439 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438.<\/p>\n<p><strong>Bearer Token<\/strong><br \/> \u041f\u0435\u0440\u0435\u0434\u0430\u0451\u0442\u0441\u044f \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435:<\/p>\n<pre><code>Authorization: Bearer &lt;token&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>10.2. \u041f\u043e\u0447\u0435\u043c\u0443 \u0442\u043e\u043a\u0435\u043d\u044b \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b<\/h4>\n<p>\u0414\u0430\u0436\u0435 \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 HTTPS \u0442\u043e\u043a\u0435\u043d\u044b \u0434\u0430\u044e\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0438:<\/p>\n<ol>\n<li>\n<p><strong>\u041f\u043e\u0434\u043f\u0438\u0441\u044c<\/strong> \u2014 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f payload \u043f\u0440\u0438\u0432\u043e\u0434\u044f\u0442 \u043a \u043d\u0435\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043f\u043e\u0434\u043f\u0438\u0441\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>\u0421\u0440\u043e\u043a \u0436\u0438\u0437\u043d\u0438 (<\/strong><code><strong>exp<\/strong><\/code><strong>)<\/strong> \u2014 \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u044b \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u044e\u0442 \u0432\u0440\u0435\u043c\u044f \u0430\u0442\u0430\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>Audience \/ Issuer (<\/strong><code><strong>aud<\/strong><\/code><strong> \/ <\/strong><code><strong>iss<\/strong><\/code><strong>)<\/strong> \u2014 \u0442\u043e\u043a\u0435\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0446\u0435\u043b\u0435\u0432\u044b\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445.<\/p>\n<\/li>\n<li>\n<p><strong>Refresh flow<\/strong> \u2014 refresh token \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 HttpOnly cookie).<\/p>\n<\/li>\n<li>\n<p><strong>Stateless<\/strong> \u2014 \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0435 \u0445\u0440\u0430\u043d\u0438\u0442 \u0442\u043e\u043a\u0435\u043d\u044b, \u0441\u043d\u0438\u0436\u0430\u0435\u0442\u0441\u044f \u0440\u0438\u0441\u043a \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0435\u0442\u0430\u0446\u0438\u0438 \u0441\u0435\u0441\u0441\u0438\u0439.<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 JWT:<\/p>\n<pre><code class=\"json\">{  \"header\": {\"alg\": \"RS256\", \"typ\": \"JWT\"},  \"payload\": {\"sub\": \"user123\", \"roles\": [\"ROLE_USER\"], \"exp\": 1700000000},  \"signature\": \"abcdef123456...\"}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>10.3. Spring Security Resource Server<\/h4>\n<p>\u041f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0430\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 JWT Resource Server:<\/p>\n<pre><code class=\"java\">@BeanSecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {    http        .authorizeHttpRequests(auth -&gt; auth.anyRequest().authenticated())        .oauth2ResourceServer(oauth2 -&gt; oauth2.jwt());    return http.build();}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p><code>BearerTokenAuthenticationFilter<\/code> \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442 <code>Authentication<\/code> \u0431\u0435\u0437 \u0441\u0435\u0441\u0441\u0438\u0438 (stateless).<\/p>\n<\/li>\n<\/ul>\n<h4>10.4. OAuth2 Authorization Server<\/h4>\n<p>\u0415\u0441\u043b\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0441\u0430\u043c\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0435\u043a\u0442 <strong>Spring Authorization Server<\/strong>.<\/p>\n<p>\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f flows:<\/p>\n<ol>\n<li>\n<p>Authorization Code (\u0441 PKCE \u0434\u043b\u044f SPA).<\/p>\n<\/li>\n<li>\n<p>Client Credentials (machine-to-machine).<\/p>\n<\/li>\n<li>\n<p>Refresh Tokens.<\/p>\n<\/li>\n<\/ol>\n<p>Best practices:<\/p>\n<ul>\n<li>\n<p>\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 client secret \u0432 \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u043c \u0432\u0438\u0434\u0435,<\/p>\n<\/li>\n<li>\n<p>\u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0436\u0438\u0432\u0443\u0449\u0438\u0435 access tokens + refresh tokens \u0432 HttpOnly cookie,<\/p>\n<\/li>\n<li>\n<p>\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 JWKs endpoint \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u0435\u0439.<\/p>\n<\/li>\n<\/ul>\n<h4>10.5. Stateful vs Stateless<\/h4>\n<p><strong>Stateful (\u0441\u0435\u0441\u0441\u0438\u0438 + cookies):<\/strong><\/p>\n<ul>\n<li>\n<p><code>SecurityContext<\/code> \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0432 <code>HttpSession<\/code>.<\/p>\n<\/li>\n<li>\n<p>Logout \u2014 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0441\u0435\u0441\u0441\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>CSRF-\u0437\u0430\u0449\u0438\u0442\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430.<\/p>\n<\/li>\n<\/ul>\n<p><strong>Stateless (JWT \/ Bearer):<\/strong><\/p>\n<ul>\n<li>\n<p>\u041d\u0435\u0442 \u0441\u0435\u0441\u0441\u0438\u0439 \u2192 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e \u0434\u043b\u044f \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>Logout \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435\u043c \u0442\u043e\u043a\u0435\u043d\u0430 \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0435.<\/p>\n<\/li>\n<li>\n<p>CSRF \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f, \u0435\u0441\u043b\u0438 \u0442\u043e\u043a\u0435\u043d \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435.<\/p>\n<\/li>\n<\/ul>\n<h4>10.6. Refresh Tokens \u0438 \u0437\u0430\u0449\u0438\u0442\u0430<\/h4>\n<ul>\n<li>\n<p><strong>Access token<\/strong>: \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0439 \u0441\u0440\u043e\u043a, \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442\u0441\u044f \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435.<\/p>\n<\/li>\n<li>\n<p><strong>Refresh token<\/strong>: \u0434\u043e\u043b\u0433\u0438\u0439 \u0441\u0440\u043e\u043a, \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0432 HttpOnly cookie.<\/p>\n<\/li>\n<li>\n<p><strong>Flow<\/strong>: \u043a\u043b\u0438\u0435\u043d\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 refresh token \u2192 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043d\u043e\u0432\u044b\u0439 access token.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 endpoint \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"java\">@PostMapping(\"\/token\/refresh\")public JwtResponse refresh(@CookieValue(\"refreshToken\") String token) {    Authentication auth = authService.verifyRefreshToken(token);    return authService.generateAccessToken(auth);}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>10.7. \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0442\u043e\u043a\u0435\u043d\u0430<\/h4>\n<p>Spring Security (\u0441 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 Nimbus) \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442:<\/p>\n<ul>\n<li>\n<p>\u043f\u043e\u0434\u043f\u0438\u0441\u044c,<\/p>\n<\/li>\n<li>\n<p>\u0441\u0440\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f (<code>exp<\/code>),<\/p>\n<\/li>\n<li>\n<p>\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f (<code>iss<\/code>),<\/p>\n<\/li>\n<li>\n<p>\u0430\u0443\u0434\u0438\u0442\u043e\u0440\u0438\u044e (<code>aud<\/code>).<\/p>\n<\/li>\n<\/ul>\n<h4>10.8. \u0422\u0438\u043f\u0438\u0447\u043d\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0438 \u0437\u0430\u0449\u0438\u0442\u0430<\/h4>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u041e\u0448\u0438\u0431\u043a\u0430<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u041f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0435<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u0420\u0435\u0448\u0435\u043d\u0438\u0435<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">JWT \u0431\u0435\u0437 \u043f\u043e\u0434\u043f\u0438\u0441\u0438<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u0430 \u043f\u043e\u0434\u0434\u0435\u043b\u043a\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c RS256\/ES256<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u0414\u043e\u043b\u0433\u043e\u0436\u0438\u0432\u0443\u0449\u0438\u0439 access token<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0414\u043e\u043b\u0433\u0438\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u043f\u0440\u0438 \u043a\u0440\u0430\u0436\u0435<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041a\u043e\u0440\u043e\u0442\u043a\u0438\u0439 TTL + refresh flow<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">Refresh token \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432 JS<\/p>\n<\/td>\n<td>\n<p align=\"left\">XSS-\u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u044c<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0425\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0432 HttpOnly cookie<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">Access token \u0432 localStorage<\/p>\n<\/td>\n<td>\n<p align=\"left\">XSS \u2192 \u043f\u043e\u0445\u0438\u0449\u0435\u043d\u0438\u0435<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0425\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438 (in-memory)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u041d\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 audience<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0422\u043e\u043a\u0435\u043d \u0447\u0443\u0436\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 <code>aud<\/code> \u0432 \u0444\u0438\u043b\u044c\u0442\u0440\u0435<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<h4>10.9. \u041f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 JWT<\/h4>\n<ol>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043b\u043e\u0433\u0438\u043d\u0438\u0442\u0441\u044f \u2192 \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u044b\u0434\u0430\u0451\u0442 access \u0438 refresh \u0442\u043e\u043a\u0435\u043d\u044b.<\/p>\n<\/li>\n<li>\n<p>\u041a\u043b\u0438\u0435\u043d\u0442 \u0445\u0440\u0430\u043d\u0438\u0442 access token \u0432 \u043f\u0430\u043c\u044f\u0442\u0438, refresh \u2014 \u0432 HttpOnly cookie.<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u0436\u0434\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441 <code>Authorization: Bearer &lt;access_token&gt;<\/code>.<\/p>\n<\/li>\n<li>\n<p>Spring Security \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043f\u043e\u0434\u043f\u0438\u0441\u044c \u0438 claims \u2192 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f <code>Authentication<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438 \u0438\u0441\u0442\u0435\u0447\u0435\u043d\u0438\u0438 access token \u043a\u043b\u0438\u0435\u043d\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 refresh token \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<\/ol>\n<h3>11. \u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0438 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043f\u0430\u0440\u043e\u043b\u0435\u0439 (Registration &amp; Password Security)<\/h3>\n<h4>11.1. \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u044b<\/h4>\n<ol>\n<li>\n<p>\u041f\u0430\u0440\u043e\u043b\u0438 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u0432\u0438\u0434\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0430\u0434\u0430\u043f\u0442\u0438\u0432\u043d\u044b\u0435 \u0445\u0435\u0448-\u0444\u0443\u043d\u043a\u0446\u0438\u0438 (BCrypt, Argon2, SCrypt).<\/p>\n<\/li>\n<li>\n<p>\u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u043e\u043b\u044c (salt).<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u043f\u0430\u0440\u043e\u043b\u0435\u0439 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0435\u0440\u0435\u0437 HTTPS.<\/p>\n<\/li>\n<li>\n<p>\u0416\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0443 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 (\u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043b\u0438\u043d\u0430, \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b, blacklist \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u043f\u0430\u0440\u043e\u043b\u0435\u0439).<\/p>\n<\/li>\n<\/ol>\n<h4>11.2. \u041f\u043e\u0442\u043e\u043a \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438<\/h4>\n<ol>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u0432\u043e\u0434\u0438\u0442 \u0438\u043c\u044f \u0438 \u043f\u0430\u0440\u043e\u043b\u044c.<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0435\u0440\u0432\u0438\u0441 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043b\u043e\u0433\u0438\u043d\u0430\/email.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0430\u0440\u043e\u043b\u044c \u0445\u0435\u0448\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 <code>PasswordEncoder<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0414\u0430\u043d\u043d\u044b\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u0411\u0414.<\/p>\n<\/li>\n<\/ol>\n<h4>11.3. \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 PasswordEncoder<\/h4>\n<pre><code class=\"java\">@Beanpublic PasswordEncoder passwordEncoder() {    return new BCryptPasswordEncoder(12); \/\/ strength=12}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p>BCrypt \u2014 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e.<\/p>\n<\/li>\n<li>\n<p>Argon2 \u2014 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u0438 \u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u044b\u0439 \u043a GPU-\u0430\u0442\u0430\u043a\u0430\u043c.<\/p>\n<\/li>\n<li>\n<p>SCrypt \u2014 \u0442\u043e\u0436\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0441 \u0432\u044b\u0441\u043e\u043a\u043e\u0439 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 brute-force.<\/p>\n<\/li>\n<\/ul>\n<h4>11.4. \u041f\u0440\u0438\u043c\u0435\u0440 UserService<\/h4>\n<pre><code class=\"java\">@Service@RequiredArgsConstructorpublic class UserService {    private final UserRepository userRepository;    private final PasswordEncoder passwordEncoder;    public User registerUser(String username, String rawPassword) {        if (userRepository.existsByUsername(username)) {            throw new IllegalArgumentException(\"\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442\");        }        User user = new User();        user.setUsername(username);        user.setPassword(passwordEncoder.encode(rawPassword));        user.setRoles(Set.of(\"ROLE_USER\"));        return userRepository.save(user);    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>11.5. \u0424\u043e\u0440\u043c\u044b \u0438 CSRF<\/h4>\n<p>\u0414\u043b\u044f stateful \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 (\u0441\u0435\u0441\u0441\u0438\u0438) CSRF-\u0442\u043e\u043a\u0435\u043d \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u0435\u043d:<\/p>\n<pre><code>&lt;form th:action=\"@{\/register}\" method=\"post\"&gt;    &lt;input type=\"hidden\" th:name=\"${_csrf.parameterName}\" th:value=\"${_csrf.token}\" \/&gt;&lt;\/form&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>11.6. \u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f + Login + JWT<\/h4>\n<ol>\n<li>\n<p>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u2192 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441 \u0445\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u043f\u0430\u0440\u043e\u043b\u0435\u043c.<\/p>\n<\/li>\n<li>\n<p>Login \u2192 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 <code>PasswordEncoder.matches()<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438 \u0443\u0441\u043f\u0435\u0445\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f <code>Authentication<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f JWT access token:<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"java\">String token = jwtService.generateToken(authentication);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ol start=\"5\">\n<li>\n<p>\u0412\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a API \u0437\u0430\u0449\u0438\u0449\u0430\u044e\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 <code>SecurityFilterChain<\/code> \u0438\u043b\u0438 <code>@PreAuthorize<\/code>.<\/p>\n<\/li>\n<\/ol>\n<h4>11.7. Best practices<\/h4>\n<ul>\n<li>\n<p>Rate-limiting \u0434\u043b\u044f \u0437\u0430\u0449\u0438\u0442\u044b \u043e\u0442 brute-force.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 email \u043f\u0435\u0440\u0435\u0434 \u0430\u043a\u0442\u0438\u0432\u0430\u0446\u0438\u0435\u0439.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0430\u0440\u043e\u043b\u0438 \u043e\u0442 12+ \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432, \u0431\u0443\u043a\u0432\u044b, \u0446\u0438\u0444\u0440\u044b, \u0441\u043f\u0435\u0446\u0441\u0438\u043c\u0432\u043e\u043b\u044b.<\/p>\n<\/li>\n<li>\n<p>Lockout \/ throttling \u043f\u0440\u0438 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u043d\u0435\u0443\u0434\u0430\u0447\u043d\u044b\u0445 \u043b\u043e\u0433\u0438\u043d\u0430\u0445.<\/p>\n<\/li>\n<li>\n<p>\u0410\u0443\u0434\u0438\u0442 \u043b\u043e\u0433\u043e\u0432 \u0434\u043b\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0438 \u0432\u0445\u043e\u0434\u043e\u0432.<\/p>\n<\/li>\n<\/ul>\n<h4>11.8. \u0420\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 (WebFlux)<\/h4>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <code>ReactiveUserDetailsService<\/code> \u0438 <code>ReactiveSecurityContextHolder<\/code>.<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code class=\"java\">Mono&lt;UserDetails&gt; findByUsername(String username) {    return userRepository.findByUsername(username)        .map(user -&gt; User.withUsername(user.getUsername())                         .password(user.getPassword())                         .roles(user.getRoles().toArray(new String[0]))                         .build());}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>11.9. \u041f\u043e\u043b\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a (Registration \u2192 Login \u2192 JWT)<\/h4>\n<ol>\n<li>\n<p>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f: \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0441 \u0445\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u043f\u0430\u0440\u043e\u043b\u0435\u043c.<\/p>\n<\/li>\n<li>\n<p>Login: \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u0430\u0440\u043e\u043b\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0423\u0441\u043f\u0435\u0448\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u2192 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f JWT.<\/p>\n<\/li>\n<li>\n<p>API-\u0437\u0430\u0449\u0438\u0442\u0430 \u0447\u0435\u0440\u0435\u0437 <code>BearerTokenAuthenticationFilter<\/code>.<\/p>\n<\/li>\n<li>\n<p>Refresh flow \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 access token \u043f\u0440\u0438 \u0435\u0433\u043e \u0438\u0441\u0442\u0435\u0447\u0435\u043d\u0438\u0438.<\/p>\n<\/li>\n<\/ol>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/946912\/\">https:\/\/habr.com\/ru\/articles\/946912\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Spring Security \u2014 \u044d\u0442\u043e \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0437\u0430\u0449\u0438\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 Spring. \u041e\u043d \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430:\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e (Authentication) \u2014 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043b\u0438\u0447\u043d\u043e\u0441\u0442\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f (\u043b\u043e\u0433\u0438\u043d\/\u043f\u0430\u0440\u043e\u043b\u044c, OAuth2-\u0442\u043e\u043a\u0435\u043d, JWT).\u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e (Authorization) \u2014 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043f\u0440\u0430\u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0430: \u0447\u0442\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442 \u0434\u0435\u043b\u0430\u0442\u044c \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435.\u0417\u0430\u0449\u0438\u0442\u0443 \u043e\u0442 \u0430\u0442\u0430\u043a: CSRF (\u043f\u043e\u0434\u0434\u0435\u043b\u043a\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432), session fixation (\u0444\u0438\u043a\u0441\u0430\u0446\u0438\u044f \u0441\u0435\u0441\u0441\u0438\u0438), clickjacking, brute-force \u0438 \u0442. \u0434.\u041f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e \u0432\u0430\u0436\u043d\u043e?\u0421\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0438\u043b\u0438 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.\u0423\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u044c \u0432 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 = \u043f\u0440\u044f\u043c\u044b\u0435 \u0443\u0431\u044b\u0442\u043a\u0438, \u0443\u0442\u0435\u0447\u043a\u0438 \u0438 \u0440\u0435\u043f\u0443\u0442\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0443\u0434\u0430\u0440.Spring Security \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043e\u043c: \u043d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f\u0448\u043d\u0438\u0439 \u0434\u0435\u043d\u044c \u043f\u043e\u0434\u0430\u0432\u043b\u044f\u044e\u0449\u0435\u0435 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 Spring \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0435\u0433\u043e.Spring Security \u0432\u0441\u0442\u0440\u043e\u0435\u043d \u0433\u043b\u0443\u0431\u043e\u043a\u043e \u0432 \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u0443 Spring Boot: \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c spring-boot-starter-security, \u0438 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432\u0441\u0451 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043e (\u0434\u043e\u0441\u0442\u0443\u043f \u0440\u0430\u0437\u0440\u0435\u0448\u0451\u043d \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c).\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u2014 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u0443\u044e \u0437\u0430\u0449\u0438\u0442\u0443 \u043f\u043e\u0434 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f: web-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u0444\u043e\u0440\u043c\u043e\u0439 \u043b\u043e\u0433\u0438\u043d\u0430, REST API \u0441 JWT, \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0441 OAuth2 \u0438 \u0442. \u0434.2. \u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 Spring Security\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 Spring Security \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u043d\u0430 \u0446\u0435\u043f\u043e\u0447\u043a\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 (Filter Chain).2.1. \u041a\u0430\u043a \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u041a\u043b\u0438\u0435\u043d\u0442 (\u0431\u0440\u0430\u0443\u0437\u0435\u0440, \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441) \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442 HTTP-\u0437\u0430\u043f\u0440\u043e\u0441.\u0415\u0441\u043b\u0438 \u0432\u043a\u043b\u044e\u0447\u0451\u043d HTTPS \u2014 \u0442\u0440\u0430\u0444\u0438\u043a \u0448\u0438\u0444\u0440\u0443\u0435\u0442\u0441\u044f.\u0417\u0430\u043f\u0440\u043e\u0441 \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c Authorization: Bearer &lt;token&gt; \u0438\u043b\u0438 Cookie: JSESSIONID.\u0421\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 (Spring Boot) \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441.\u0414\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432 \u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u0432 \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 (Filter Chain).Spring Security Filter Chain \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442:\u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d \u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c?\u043a\u0430\u043a\u0438\u0435 \u043f\u0440\u0430\u0432\u0430 \u0443 \u043d\u0435\u0433\u043e \u0435\u0441\u0442\u044c?\u0440\u0430\u0437\u0440\u0435\u0448\u0451\u043d \u043b\u0438 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0440\u0435\u0441\u0443\u0440\u0441\u0443?\u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0435 \u043f\u0440\u043e\u0439\u0434\u0435\u043d\u0430 \u2192 \u043e\u0442\u0432\u0435\u0442 401 (Unauthorized \u2014 \u043d\u0435\u0442 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438) \u0438\u043b\u0438 403 (Forbidden \u2014 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432).\u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u0430 \u2192 \u0437\u0430\u043f\u0440\u043e\u0441 \u0443\u0445\u043e\u0434\u0438\u0442 \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440, \u0441\u0435\u0440\u0432\u0438\u0441, \u0411\u0414.2.2. \u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044bDelegatingFilterProxy \u2014 \u0442\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 \u0432 Spring Security \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0441\u0435\u0440\u0432\u043b\u0435\u0442\u043e\u0432 (Tomcat, Jetty \u0438 \u0442. \u0434.).FilterChainProxy \u2014 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432.SecurityFilterChain \u2014 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430 URL (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \/api\/** \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 JWT, \u0430 \/login \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 \u0444\u043e\u0440\u043c\u0443).AuthenticationManager \u2014 \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e. \u041e\u043d \u0434\u0435\u043b\u0435\u0433\u0438\u0440\u0443\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u043c \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0430\u043c (AuthenticationProvider).UserDetailsService \u2014 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435 \u0438\u0437 \u0411\u0414 (\u043b\u043e\u0433\u0438\u043d, \u043f\u0430\u0440\u043e\u043b\u044c, \u0440\u043e\u043b\u0438).PasswordEncoder \u2014 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043f\u0430\u0440\u043e\u043b\u0435\u0439 (BCrypt \u0438 \u0442. \u0434.).SecurityContext \u2014 \u043e\u0431\u044a\u0435\u043a\u0442, \u0433\u0434\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435 (Authentication).2.3. \u041f\u0440\u0438\u043c\u0435\u0440 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 \u0446\u0435\u043f\u043e\u0447\u043a\u0438 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0441 \u0444\u043e\u0440\u043c\u043e\u0439 \u043b\u043e\u0433\u0438\u043d\u0430 Spring Security \u0441\u0442\u0440\u043e\u0438\u0442 \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442:SecurityContextPersistenceFilter \u2014 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435 \u0438\u0437 \u0441\u0435\u0441\u0441\u0438\u0438.CsrfFilter \u2014 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 CSRF-\u0442\u043e\u043a\u0435\u043d.UsernamePasswordAuthenticationFilter \u2014 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 POST \/login, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043b\u043e\u0433\u0438\u043d\/\u043f\u0430\u0440\u043e\u043b\u044c.BasicAuthenticationFilter \u2014 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a Authorization: Basic &#8230;.BearerTokenAuthenticationFilter \u2014 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 JWT \u0438\u043b\u0438 OAuth2-\u0442\u043e\u043a\u0435\u043d.AnonymousAuthenticationFilter \u2014 \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0435 \u0437\u0430\u043b\u043e\u0433\u0438\u043d\u0435\u043d, \u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u0435\u0442 \u0435\u043c\u0443 &#171;\u0430\u043d\u043e\u043d\u0438\u043c\u043d\u0443\u044e&#187; \u0440\u043e\u043b\u044c.ExceptionTranslationFilter \u2014 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0438 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438.FilterSecurityInterceptor \u2014 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u0440\u0430\u0432 \u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f.2.4. Servlet vs ReactiveServlet (Tomcat\/Jetty\/Undertow): \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0446\u0435\u043f\u043e\u0447\u043a\u0430 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 (Filter).Reactive (WebFlux\/Netty): \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f WebFilter, SecurityWebFilterChain, \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0439 ReactiveAuthenticationManager. \u041e\u0442\u043b\u0438\u0447\u0438\u0435 \u2014 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0432 reactive context, \u0430 \u043d\u0435 \u0432 ThreadLocal.3. \u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0438 \u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f3.1. \u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f (Authentication)\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f = \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043b\u0438\u0447\u043d\u043e\u0441\u0442\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. Spring Security \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441: \u043a\u0442\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441?\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438:\u0424\u043e\u0440\u043c\u0430 \u043b\u043e\u0433\u0438\u043d\u0430 (Form Login)\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 POST \/login \u0441 username \u0438 password.UsernamePasswordAuthenticationFilter \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441.AuthenticationManager \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 DaoAuthenticationProvider.UserDetailsService \u0438\u0449\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 \u0411\u0414.PasswordEncoder \u0441\u0432\u0435\u0440\u044f\u0435\u0442 \u043f\u0430\u0440\u043e\u043b\u044c (BCrypt, Argon2).\u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u0430 \u2192 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442 Authentication, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0432 SecurityContext.HTTP Basic\u0417\u0430\u043f\u0440\u043e\u0441 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 Authorization: Basic base64(user:password).\u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 REST API (\u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0435\u0440\u0435\u0437 HTTPS).JWT (Bearer Token)\u0412 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435: Authorization: Bearer &lt;jwt&gt;.\u0422\u043e\u043a\u0435\u043d \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f (exp, iss, aud, \u043f\u043e\u0434\u043f\u0438\u0441\u044c).\u0415\u0441\u043b\u0438 \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439 \u2192 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f Authentication.Stateful-\u0441\u0435\u0441\u0441\u0438\u0439 \u043d\u0435\u0442, \u043a\u0430\u0436\u0434\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u0430\u044f.OAuth2 \/ OpenID Connect\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043b\u043e\u0433\u0438\u043d\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0430 (Google, GitHub).Spring Security \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 access token \/ id token.\u0420\u0435\u0441\u0443\u0440\u0441\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 (resource server) \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d (\u043e\u0431\u044b\u0447\u043d\u043e JWT).LDAP \/ Active Directory\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438.\u041a\u0430\u0441\u0442\u043e\u043c\u043d\u0430\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f\u041c\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 AuthenticationProvider.\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 HMAC-\u043f\u043e\u0434\u043f\u0438\u0441\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438\u043b\u0438 API-\u043a\u043b\u044e\u0447\u0435\u0439.3.2. \u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f (Authorization)\u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f = \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u0440\u0430\u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0430. Spring Security \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442: \u043a\u0430\u043a\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u044b?\u0423\u0440\u043e\u0432\u043d\u0438:URL-\u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0412 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 HttpSecurity:http.authorizeHttpRequests(auth -&gt; auth    .requestMatchers(&#171;\/admin\/**&#187;).hasRole(&#171;ADMIN&#187;)    .requestMatchers(&#171;\/user\/**&#187;).hasAnyRole(&#171;USER&#187;, &#171;ADMIN&#187;)    .anyRequest().authenticated());\/admin\/** \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0442\u043e\u043b\u044c\u043a\u043e ADMIN, \/user\/** \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d USER \u0438 ADMIN, \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 URL \u0442\u0440\u0435\u0431\u0443\u044e\u0442 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438.\u041c\u0435\u0442\u043e\u0434\u043d\u044b\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 \u0432 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445:@PreAuthorize(&#171;hasRole(&#8216;ADMIN&#8217;)&#187;)public void deleteUser(Long id) { &#8230; }\u0418\u043b\u0438 \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f (SpEL):@PreAuthorize(&#171;#id == principal.id or hasRole(&#8216;ADMIN&#8217;)&#187;)public Account getAccount(Long id) { &#8230; }\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0437\u0430\u0432\u044f\u0437\u0430\u043d\u0430 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u0440\u043e\u043b\u0438, \u043d\u043e \u0438 \u043d\u0430 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0443.\u0414\u043e\u0441\u0442\u0443\u043f \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 (ACL)\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f AclService \u0438 PermissionEvaluator.\u041f\u0440\u0438\u043c\u0435\u0440: \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u0432\u0442\u043e\u0440 \u0441\u0442\u0430\u0442\u044c\u0438 \u043c\u043e\u0436\u0435\u0442 \u0435\u0451 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c.3.3. UserDetails \u0438 PasswordEncoderUserDetailsService \u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 UserDetails.\u041f\u0440\u0438\u043c\u0435\u0440 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438:@Servicepublic class CustomUserDetailsService implements UserDetailsService {    private final UserRepository userRepository;    public UserDetails loadUserByUsername(String username) {        UserEntity user = userRepository.findByUsername(username)            .orElseThrow(() -&gt; new UsernameNotFoundException(&#171;Not found&#187;));        return new org.springframework.security.core.userdetails.User(            user.getUsername(),            user.getPassword(),            user.getRoles().stream().map(SimpleGrantedAuthority::new).toList()        );    }}PasswordEncoder \u041f\u0430\u0440\u043e\u043b\u0438 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u0432\u0438\u0434\u0435.BCryptPasswordEncoder (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e).Argon2PasswordEncoder (\u0435\u0449\u0451 \u0431\u043e\u043b\u0435\u0435 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439).\u041f\u0440\u0438\u043c\u0435\u0440:@BeanPasswordEncoder passwordEncoder() {    return new BCryptPasswordEncoder();}\u041f\u0440\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u0445\u044d\u0448\u0438\u0440\u0443\u0435\u0442\u0441\u044f, \u043f\u0440\u0438 \u043b\u043e\u0433\u0438\u043d\u0435 \u2014 \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0445\u044d\u0448.3.4. \u041f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e?TLS\/HTTPS \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u0442 \u043e\u0442 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0430 \u0442\u0440\u0430\u0444\u0438\u043a\u0430 (\u0447\u0435\u043b\u043e\u0432\u0435\u043a \u043f\u043e\u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435 \u043d\u0435 \u0443\u0432\u0438\u0434\u0438\u0442 \u043f\u0430\u0440\u043e\u043b\u044c).\u041f\u0430\u0440\u043e\u043b\u0438 \u0445\u044d\u0448\u0438\u0440\u0443\u044e\u0442\u0441\u044f (bcrypt\/argon2): \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0443\u043a\u0440\u0430\u0434\u0443\u0442 \u0411\u0414, \u043f\u0430\u0440\u043e\u043b\u044c \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u0432\u0438\u0434\u0435 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c.\u0422\u043e\u043a\u0435\u043d\u044b \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f: JWT \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0446\u0438\u0444\u0440\u043e\u0432\u0443\u044e \u043f\u043e\u0434\u043f\u0438\u0441\u044c, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043d\u0435\u043b\u044c\u0437\u044f \u043f\u043e\u0434\u0434\u0435\u043b\u0430\u0442\u044c \u0431\u0435\u0437 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430.\u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u043c\u043d\u043e\u0433\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u0430\u044f: \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u0442\u043e\u043a\u0435\u043d, \u0434\u043e\u0441\u0442\u0443\u043f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d \u0440\u043e\u043b\u044f\u043c\u0438 \u0438 ACL.\u041c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u044b \u0437\u0430\u0449\u0438\u0442\u044b \u043e\u0442 \u0430\u0442\u0430\u043a: CSRF-\u0442\u043e\u043a\u0435\u043d\u044b, \u0441\u0435\u0441\u0441\u0438\u043e\u043d\u043d\u0430\u044f \u0438\u0437\u043e\u043b\u044f\u0446\u0438\u044f, \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043f\u043e\u043f\u044b\u0442\u043e\u043a \u0432\u0445\u043e\u0434\u0430.\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441 \u00ab\u043a\u0442\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441?\u00bb. \u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043d\u0430 \u0432\u043e\u043f\u0440\u043e\u0441 \u00ab\u0447\u0442\u043e \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u043e \u0434\u0435\u043b\u0430\u0442\u044c?\u00bb. \u0412\u043c\u0435\u0441\u0442\u0435 \u043e\u043d\u0438 \u043e\u0431\u0440\u0430\u0437\u0443\u044e\u0442 \u043e\u0441\u043d\u043e\u0432\u0443 Spring Security.4. \u0416\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u0439 \u0446\u0438\u043a\u043b \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 Spring Security\u0427\u0442\u043e\u0431\u044b \u0443\u0432\u0435\u0440\u0435\u043d\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441\u043e Spring Security, \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c: \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442, \u043a\u043e\u0433\u0434\u0430 \u043a\u043b\u0438\u0435\u043d\u0442 \u0434\u0435\u043b\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e.4.1. \u041e\u0431\u0449\u0430\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u041a\u043b\u0438\u0435\u043d\u0442 (\u0431\u0440\u0430\u0443\u0437\u0435\u0440, \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441) \u2192 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 (GET\/POST\/PUT \u0438 \u0442. \u0434.).\u0417\u0430\u043f\u0440\u043e\u0441 \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 (Tomcat\/Jetty\/Undertow).\u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 (Filter Chain).\u0421\u0440\u0435\u0434\u0438 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 \u0435\u0441\u0442\u044c DelegatingFilterProxy, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432 Spring Security.\u0417\u0430\u043f\u0440\u043e\u0441 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 \u0441\u0435\u0440\u0438\u044e \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 Spring Security.\u0415\u0441\u043b\u0438 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0443\u0441\u043f\u0435\u0448\u043d\u044b\u0435 \u2192 \u0437\u0430\u043f\u0440\u043e\u0441 \u0434\u043e\u0445\u043e\u0434\u0438\u0442 \u0434\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430.\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0443 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0442\u0432\u0435\u0442.\u041e\u0442\u0432\u0435\u0442 \u0441\u043d\u043e\u0432\u0430 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 \u0444\u0438\u043b\u044c\u0442\u0440\u044b (\u0447\u0430\u0441\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u0441\u0435\u0441\u0441\u0438\u044e, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438).4.2. \u0414\u0435\u0442\u0430\u043b\u044c\u043d\u043e: \u0448\u0430\u0433 \u0437\u0430 \u0448\u0430\u0433\u043e\u043c\u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f Spring Boot MVC + Form Login.\u0428\u0430\u0433 1. \u0421\u0435\u0442\u0435\u0432\u043e\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c\u041a\u043b\u0438\u0435\u043d\u0442 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \/login.TLS\/HTTPS \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435.Tomcat \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0438 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0435\u0433\u043e \u0432 HttpServletRequest.\u0428\u0430\u0433 2. \u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0444\u0438\u043b\u044c\u0442\u0440\u044bTomcat \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0432\u0441\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u044b, \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438.\u0421\u0440\u0435\u0434\u0438 \u043d\u0438\u0445 \u0435\u0441\u0442\u044c DelegatingFilterProxy(&#171;springSecurityFilterChain&#187;).\u0428\u0430\u0433 3. \u0412\u0445\u043e\u0434 \u0432 Spring Security Filter ChainFilterChainProxy \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442, \u043a\u0430\u043a\u0438\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e URL.\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \/login \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 UsernamePasswordAuthenticationFilter.\u0428\u0430\u0433 4. \u0420\u0430\u0431\u043e\u0442\u0430 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u041f\u0440\u0438\u043c\u0435\u0440\u043d\u044b\u0439 \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e):SecurityContextPersistenceFilter \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 SecurityContext \u0438\u0437 \u0441\u0435\u0441\u0441\u0438\u0438 (\u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c). \u0415\u0441\u043b\u0438 \u043d\u0435\u0442 \u2014 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043d\u043e\u0432\u044b\u0439 (\u0430\u043d\u043e\u043d\u0438\u043c\u043d\u044b\u0439).CsrfFilter \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 CSRF-\u0442\u043e\u043a\u0435\u043d\u0430 (\u0434\u043b\u044f POST\/PUT\/DELETE).LogoutFilter \u041f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \/logout, \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u0441\u0435\u0441\u0441\u0438\u044e, \u043a\u0443\u043a\u0438.UsernamePasswordAuthenticationFilter \u0415\u0441\u043b\u0438 POST \/login \u2192 \u0431\u0435\u0440\u0451\u0442 username \u0438 password. \u0421\u043e\u0437\u0434\u0430\u0451\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 UsernamePasswordAuthenticationToken. \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0435\u0433\u043e \u0432 AuthenticationManager.AuthenticationManager \u2192 AuthenticationProvider \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, DaoAuthenticationProvider. \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0447\u0435\u0440\u0435\u0437 UserDetailsService. \u0421\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u0442 \u043f\u0430\u0440\u043e\u043b\u044c \u0447\u0435\u0440\u0435\u0437 PasswordEncoder. \u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u0430 \u2192 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 Authentication \u0441 \u0440\u043e\u043b\u044f\u043c\u0438.SecurityContextHolder \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 Authentication (\u0432 ThreadLocal). \u0415\u0441\u043b\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 stateful \u2192 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0438\u0448\u0443\u0442\u0441\u044f \u0432 HttpSession.FilterSecurityInterceptor \u0424\u0438\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430: \u0435\u0441\u0442\u044c \u043b\u0438 \u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f \u043a URL\/\u043c\u0435\u0442\u043e\u0434\u0443. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 AccessDecisionManager.\u0415\u0441\u043b\u0438 \u0433\u0434\u0435-\u0442\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0430\u0440\u043e\u043b\u044c \u043d\u0435\u0432\u0435\u0440\u043d\u044b\u0439, \u0442\u043e\u043a\u0435\u043d \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439) \u2192 \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f AuthenticationException, \u0438 \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 401\/403.\u0428\u0430\u0433 5. \u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0415\u0441\u043b\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u0440\u043e\u0439\u0434\u0435\u043d\u044b, DispatcherServlet \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-475028","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/475028","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=475028"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/475028\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=475028"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=475028"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=475028"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}