{"id":364567,"date":"2024-05-21T02:19:29","date_gmt":"2024-05-21T02:19:29","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=364567"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-05-21T02:19:29","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=364567","title":{"rendered":"<span>\u0421\u0442\u0440\u043e\u0438\u043c \u0441\u0432\u043e\u0439 SSO. \u0427\u0430\u0441\u0442\u044c 4: Vue.js, \u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f, \u0421\u0431\u0440\u043e\u0441 \u043f\u0430\u0440\u043e\u043b\u044f<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h3>\u0421\u043f\u0438\u0441\u043e\u043a \u0441\u0442\u0430\u0442\u0435\u0439 \u044d\u0442\u043e\u0439 \u0441\u0435\u0440\u0438\u0438<\/h3>\n<ul>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/737548\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 1: \u0421\u0442\u0440\u043e\u0438\u043c \u0441\u0432\u043e\u0439 SSO \u0441\u0435\u0440\u0432\u0435\u0440, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f Spring Authorization Server<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/746698\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 2: \u0421\u0442\u0440\u043e\u0438\u043c \u0441\u0432\u043e\u0439 SSO. PostgreSQL \u0438 \u0440\u043e\u043b\u0435\u0432\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/748584\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 3: \u0421\u0442\u0440\u043e\u0438\u043c \u0441\u0432\u043e\u0439 SSO. Redis, Swagger, Vue.js<\/a><\/p>\n<\/li>\n<li>\n<p>\u0427\u0430\u0441\u0442\u044c 4: \u0421\u0442\u0440\u043e\u0438\u043c \u0441\u0432\u043e\u0439 SSO. Vue.js, \u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f, \u0421\u0431\u0440\u043e\u0441 \u043f\u0430\u0440\u043e\u043b\u044f<\/p>\n<\/li>\n<\/ul>\n<h3>\u0412\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435<\/h3>\n<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442, \u043c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 SSO Server. \u041d\u043e \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u043c, \u0447\u0442\u043e \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u0432 <a href=\"https:\/\/habr.com\/ru\/articles\/748584\/\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435<\/a>:<\/p>\n<ul>\n<li>\n<p>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043b\u0438 Redis<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u043b\u0438 Swagger<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043b\u0438 \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f <code>j-sso<\/code> \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <code>Vue.js<\/code><\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u0440\u0438 \u0440\u0430\u0437\u0431\u043e\u0440\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 Redis \u0431\u044b\u043b \u0443\u043f\u0443\u0449\u0435\u043d \u043e\u0447\u0435\u043d\u044c \u0432\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442. \u041a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u044f <code>OAuth2AuthorizationService oAuth2AuthorizationService()<\/code> \u0431\u0438\u043d\u0430, \u043f\u0435\u0440\u0435\u0432\u043e\u0434 \u0435\u0433\u043e \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 Redis. \u041d\u0435\u0434\u0430\u0432\u043d\u043e \u043e\u043d \u0431\u044b\u043b \u043e\u0431\u043d\u043e\u0432\u043b\u0451\u043d, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0441\u043b\u0438 \u0412\u044b \u0435\u0449\u0451 \u043d\u0435 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043b\u0438 \u0435\u0433\u043e, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430 \u0432\u0435\u0440\u043d\u0438\u0442\u0435\u0441\u044c \u043a \u0440\u0430\u0437\u0434\u0435\u043b\u0443 <a href=\"https:\/\/habr.com\/ru\/articles\/748584\/\" rel=\"noopener noreferrer nofollow\"><strong>\u0420\u0430\u0437\u0434\u0435\u043b 3.1: \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c Redis<\/strong><\/a> \u0438 \u043f\u0440\u043e\u0447\u0442\u0438\u0442\u0435 \u0435\u0433\u043e \u0435\u0449\u0451 \u0440\u0430\u0437.<\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u0443\u043d\u043a\u0442\u044b:<\/p>\n<ul>\n<li>\n<p>\u0414\u0435\u0442\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c frontend \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0447\u0435\u0440\u0435\u0437 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0444\u043e\u0440\u043c\u0443 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043d\u0430 SSO<\/p>\n<\/li>\n<li>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e &#171;\u0417\u0430\u0431\u044b\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c&#187;<\/p>\n<\/li>\n<\/ul>\n<p>\u0418\u0442\u0430\u043a, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c!<\/p>\n<h3>\u0420\u0430\u0437\u0434\u0435\u043b 4.1: \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 frontend \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h3>\n<p>\u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0443\u0436\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b\u0438 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <code>vue-cli<\/code>. \u0410 \u0442\u0430\u043a\u0436\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438, \u0447\u0442\u043e \u0438\u0437 \u0441\u0435\u0431\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u0431\u043e\u0440\u043a\u0430 frontend \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u0435\u0435 \u043f\u043e\u0433\u0440\u0443\u0437\u0438\u0442\u044c\u0441\u044f \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0435 \u0435\u0433\u043e \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0435.<\/p>\n<p>\u0421\u0440\u0430\u0437\u0443 \u0441\u043a\u0430\u0436\u0443, \u044f \u0443\u043b\u0443\u0447\u0448\u0438\u043b \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043f\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044e \u0441 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435\u0439. \u0422\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u0440\u044f\u0434 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u043f\u0440\u0438 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412\u0441\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/tree\/chapter-4.1\/j-sso\/client\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a><\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u0437\u0433\u043b\u044f\u043d\u0435\u043c \u043d\u0430 \u043d\u0430\u0448 <code>package.json<\/code> \u0444\u0430\u0439\u043b. \u0412 \u043d\u0451\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0422\u0430\u043a\u0436\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u044b \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0438 \u0441\u0431\u043e\u0440\u043a\u0438. \u0418 \u0435\u0449\u0451 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043c\u0435\u0442\u0430\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u0441\u0438\u0441\u0442\u0435\u043c \u0441\u0431\u043e\u0440\u043a\u0438 frontend \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p><code><strong>package.json<\/strong><\/code><\/p>\n<pre><code class=\"json\">{     \"name\": \"client\",     \"version\": \"0.1.0\",     \"private\": true,     \"scripts\": {         \"serve\": \"vue-cli-service serve --mode=development\",         \"build\": \"vue-cli-service build --mode=development\",         \"build-prod\": \"vue-cli-service build --mode=production\",         \"build-test\": \"vue-cli-service build --mode=testing\",         \"build-dev-java\": \"vue-cli-service build --mode=dev-java\"     },     \"dependencies\": {         \"@dlabs71\/d-dto\": \"^1.1.0\",         \"@kyvg\/vue3-notification\": \"^2.9.1\",         \"@mdi\/font\": \"^7.2.96\",         \"@vee-validate\/i18n\": \"^4.9.5\",         \"@vee-validate\/rules\": \"^4.9.5\",         \"@vuepic\/vue-datepicker\": \"^5.1.2\",         \"axios\": \"^1.4.0\",         \"core-js\": \"^3.30.2\",         \"moment\": \"^2.29.4\",         \"roboto-fontface\": \"*\",         \"uuid\": \"^9.0.0\",         \"vee-validate\": \"^4.9.5\",         \"vue\": \"^3.3.4\",         \"vue-router\": \"^4.2.2\",         \"vuetify\": \"^3.3.1\",         \"vuex\": \"^4.1.0\",         \"vuex-persist\": \"^3.1.3\",         \"webfontloader\": \"^1.6.28\"     },     \"devDependencies\": {         \"@babel\/core\": \"^7.22.1\",         \"@babel\/preset-env\": \"^7.22.2\",         \"@vue\/cli-plugin-babel\": \"~5.0.8\",         \"@vue\/cli-plugin-router\": \"~5.0.8\",         \"@vue\/cli-plugin-vuex\": \"~5.0.8\",         \"@vue\/cli-service\": \"~5.0.8\",         \"sass\": \"^1.62.1\",         \"sass-loader\": \"^13.3.1\",         \"vue-cli-plugin-vuetify\": \"~2.5.8\",         \"webpack-plugin-vuetify\": \"^2.0.1\"     },     \"engines\": {         \"npm\": \">=8.0.0\",         \"node\": \">=16.0.0\"     },     \"browserslist\": [         \"> 1%\",         \"last 2 versions\",         \"not dead\",         \"not ie 11\"     ] } <\/code><\/pre>\n<p>\u0414\u0435\u0442\u0430\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431\u043e \u0432\u0441\u0435\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u044d\u0442\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 <a href=\"https:\/\/docs.npmjs.com\/cli\/v10\/configuring-npm\/package-json\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>. \u041a\u043e\u043c\u0430\u043d\u0434\u044b \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u0432 \u0441\u0435\u043a\u0446\u0438\u0438 <code>\"scripts\"<\/code> \u0443\u0436\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b\u0438\u0441\u044c \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430 \u043d\u0438\u0445 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u0431\u0443\u0434\u0435\u043c. \u0421\u0440\u0430\u0437\u0443 \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c \u0432 \u0441\u0435\u043a\u0446\u0438\u0438 <code>\"dependencies\"<\/code>. \u041d\u0438\u0436\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<ul>\n<li>\n<p><code>@dlabs71\/d-dto<\/code> &#8212; \u044d\u0442\u043e \u043c\u043d\u043e\u044e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u043b\u0430\u0441\u0441\u043e\u0432 DTO, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438 \u0438\u0437 json \u0432 dto \u043a\u043b\u0430\u0441\u0441 \u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e. \u041e\u043d\u0430 \u043d\u0430\u043c \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0440\u0430\u0437\u0434\u0435\u043b\u0430\u0445 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u043f\u0440\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 API.<\/p>\n<\/li>\n<li>\n<p><code>@kyvg\/vue3-notification<\/code> &#8212; \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0438\u0445 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p><code>@vuepic\/vue-datepicker<\/code> &#8212; \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u043e\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 \u0434\u0430\u0442\u044b.<\/p>\n<\/li>\n<li>\n<p><code>axios<\/code> &#8212; \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f HTTP \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p><code>vee-validate<\/code> &#8212; \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u043e\u0432 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0444\u043e\u0440\u043c.<\/p>\n<\/li>\n<li>\n<p><code>vue<\/code> &#8212; \u0441\u0430\u043c VUE \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u043f\u0435\u0440\u0441\u043e\u043d\u043e\u0439<\/p>\n<\/li>\n<li>\n<p><code>vue-router<\/code> &#8212; \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u043e\u0432 \u0440\u043e\u0443\u0442\u0438\u043d\u0433\u0430 (\u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438).<\/p>\n<\/li>\n<li>\n<p><code>vuetify<\/code> &#8212; \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0432\u0441\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u0438 \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0444\u043e\u0440\u043c.<\/p>\n<\/li>\n<li>\n<p><code>vuex<\/code> &#8212; \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u0441\u0435\u043a\u0446\u0438\u0438 <code>devDependencies<\/code> \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0422\u0443\u0442 \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u043f\u043b\u0430\u0433\u0438\u043d\u044b <code>vue<\/code>, <code>vuetify<\/code>, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043f\u0440\u0435\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 <code>sass<\/code>.<\/p>\n<p>\u0412\u0441\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u043d\u0430 \u0441\u0430\u0439\u0442\u0435 <a href=\"https:\/\/www.npmjs.com\/\" rel=\"noopener noreferrer nofollow\">npmjs<\/a>.<\/p>\n<p>\u0421\u0442\u043e\u0438\u0442 \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043b\u043e\u0432 \u043f\u0440\u043e \u0441\u0435\u043a\u0446\u0438\u044e <code>\"browserslist\"<\/code>. \u0412 \u043d\u0435\u0439 \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u0432 \u0434\u043b\u044f \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041f\u043e\u043b\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043d\u0451\u043c \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 <a href=\"https:\/\/github.com\/browserslist\/browserslist\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0434\u043b\u044f \u043d\u0430\u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u043c \u0444\u0430\u0439\u043b\u043e\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <code>vue.config.js<\/code>. \u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0432\u0441\u044e \u043e\u0441\u043d\u043e\u0432\u043d\u0443\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u043d\u0430\u0448\u0435\u0433\u043e Vue \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0418\u0437\u0443\u0447\u0438\u0442\u044c \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e \u0435\u0451 \u043c\u043e\u0436\u043d\u043e <a href=\"https:\/\/cli.vuejs.org\/config\/#vue-config-js\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>. \u041d\u0443 \u0430 \u043c\u044b \u043f\u0440\u043e\u0439\u0434\u0451\u043c\u0441\u044f \u043f\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u043c \u043d\u0430\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c:<\/p>\n<p><code><strong>vue.config.js<\/strong><\/code><\/p>\n<pre><code>const {defineConfig} = require('@vue\/cli-service');  module.exports = defineConfig({     transpileDependencies: [\"vuetify\"],     publicPath: process.env.VUE_APP_NODE_ENV !== \"development\" ? \"\/static\" : \"\/\",      devServer: {         port: 8080     },      pluginOptions: {         vuetify: {             styles: {                 configFile: \"src\/assets\/scss\/settings.scss\"             }         }     } }); <\/code><\/pre>\n<ul>\n<li>\n<p><code>transpileDependencies<\/code> &#8212; \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043a\u0430\u043a\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0443\u0436\u043d\u043e \u0442\u0440\u0430\u043d\u0441\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0442\u0430\u043a \u043a\u0430\u043a \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e <code>babel-loader<\/code> \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0435\u0442 \u0432\u0441\u0435 \u0444\u0430\u0439\u043b\u044b \u0438\u0437 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>node_modules<\/code><\/p>\n<\/li>\n<li>\n<p><code>publicPath<\/code> &#8212; \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b\u0438 \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435. \u041d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043f\u0443\u0442\u0438 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043f\u0440\u0438 \u0441\u0431\u043e\u0440\u043a\u0435.<\/p>\n<\/li>\n<li>\n<p><code>devServer<\/code> &#8212; \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043b\u044f <code>nodejs<\/code> \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 \u0435\u0433\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u0423\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043f\u043e\u0440\u0442 <code>8080<\/code>.<\/p>\n<\/li>\n<li>\n<p><code>pluginOptions<\/code> &#8212; \u0437\u0434\u0435\u0441\u044c \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u0445 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a <code>vuetify<\/code>. \u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0434\u043b\u044f \u043f\u043b\u0430\u0433\u0438\u043d\u0430 <code>vue-cli-plugin-vuetify<\/code> \u0444\u0430\u0439\u043b \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0441\u0442\u0438\u043b\u0435\u0439. \u0423\u0437\u043d\u0430\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0441\u0442\u0438\u043b\u0435\u0439 <code>vuetify<\/code> \u043c\u043e\u0436\u043d\u043e <a href=\"https:\/\/vuetifyjs.com\/en\/features\/sass-variables\/#installation\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a>.<\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u0442\u043e\u0438\u0442 \u0441\u0440\u0430\u0437\u0443 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0433\u0434\u0435 \u0443 \u043d\u0430\u0441 \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u044e\u0442\u0441\u044f <code>css<\/code> \u0441\u0442\u0438\u043b\u0438 (\u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043f\u0440\u0435\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 <code>sass<\/code> \u0441\u043e \u0441\u0442\u0438\u043b\u0435\u043c <code>scss<\/code>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0443 \u043d\u0430\u0441 <code>.scss<\/code> \u0444\u0430\u0439\u043b\u044b). \u041e\u043d\u0438 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>src\/assets\/css<\/code>. \u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <code>src\/assets<\/code> \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u0442\u0438\u043b\u0435\u0439, \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439, \u0448\u0440\u0438\u0444\u0442\u043e\u0432 \u0438 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0443 \u043d\u0430\u0441 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438 \u0441\u0442\u0438\u043b\u0438.<\/p>\n<p>\u0412\u0441\u0435 <code>.env<\/code> \u0444\u0430\u0439\u043b\u044b \u043c\u044b \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b\u0438 \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435. \u041e\u043d\u0438 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u044b \u0433\u043b\u0430\u0432\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0441\u0440\u0435\u0434\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0437\u0433\u043b\u044f\u043d\u0435\u043c \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0444\u0430\u0439\u043b\u044b:<\/p>\n<ul>\n<li>\n<p><code>babel.config.js<\/code> &#8212; \u0445\u0440\u0430\u043d\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e babel (\u043f\u043e\u043f\u0440\u043e\u0441\u0442\u0443 \u0433\u043e\u0432\u043e\u0440\u044f js \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440). \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043d\u0451\u043c \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 <a href=\"https:\/\/babeljs.io\/docs\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<\/li>\n<li>\n<p><code>jsconfig.json<\/code> &#8212; \u044d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u0445\u0440\u0430\u043d\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u043c\u043e\u0433\u0430\u044e\u0442 \u0432\u0430\u0448\u0435\u043c\u0443 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0443 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u0442\u044c \u043f\u0443\u0442\u0438 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0421\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <code>vue-cli<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <code>public<\/code> &#8212; \u0445\u0440\u0430\u043d\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 html \u0444\u0430\u0439\u043b \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0430 \u0442\u0430\u043a\u0436\u0435 <code>favicon.ico<\/code> \u0438\u043a\u043e\u043d\u043a\u0443, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0443\u044e \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u0445 \u044d\u0442\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u0418\u0442\u0430\u043a, \u0432\u0441\u0435 \u0441\u043e\u043f\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0444\u0430\u0439\u043b\u044b \u0438 \u0444\u0430\u0439\u043b\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043c\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438. \u041d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u0441\u0430\u043c\u043e\u043c\u0443 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u043c\u0443 &#8212; \u044d\u0442\u043e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <code>src<\/code>. \u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432\u0441\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u043d\u0430\u0448\u0435\u0433\u043e frontend \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041a\u0430\u043a \u0443\u0436\u0435 \u0433\u043e\u0432\u043e\u0440\u0438\u043b\u043e\u0441\u044c \u0432\u044b\u0448\u0435, \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <code>assets<\/code> \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u043d\u043e\u0433\u043e \u0440\u043e\u0434\u0430 \u0441\u0442\u0430\u0442\u0438\u043a\u0438 \u0438 \u0441\u0442\u0438\u043b\u0435\u0439, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0435\u0451 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b\u0430. \u0418\u0442\u0430\u043a, \u0441 \u043d\u0435\u0439 \u0432\u0441\u0451 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e. \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u043e\u0431\u0440\u0430\u0437\u0443\u044e\u0442 \u0432\u0441\u0435 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u043e\u0439\u0434\u0451\u043c\u0441\u044f \u043f\u043e \u043d\u0438\u043c.<\/p>\n<p>\u0422\u043e\u0447\u043a\u043e\u0439 \u0432\u0445\u043e\u0434\u0430 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0444\u0430\u0439\u043b <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/blob\/chapter-4.1\/j-sso\/client\/src\/main.js\" rel=\"noopener noreferrer nofollow\"><code>main.js<\/code><\/a>. \u0412 \u043d\u0451\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 <code>vue plugins<\/code>, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0445 \u0432 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f\u0445, \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u0430\u043c\u043e\u0433\u043e <code>vue<\/code> \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/blob\/chapter-4.1\/j-sso\/client\/src\/App.vue\" rel=\"noopener noreferrer nofollow\"><code>App.vue<\/code><\/a> &#8212; \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043d\u0430\u0448\u0435\u0433\u043e SPA \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0432 <code>main.js<\/code>. \u0412 \u043d\u0451\u043c \u0443\u043a\u0430\u0437\u0430\u043d \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0448\u0430\u0431\u043b\u043e\u043d \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b:<\/p>\n<ul>\n<li>\n<p><code>&lt;j-exception\/><\/code> &#8212; \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043d\u0430\u0448 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 (\u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u043e 500-\u044b\u0445 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430).<\/p>\n<\/li>\n<li>\n<p><code>&lt;notifications group=\"main\"\/><\/code> &#8212; \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043c\u0435\u0441\u0442\u043e\u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u0430 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0438\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p><code>&lt;router-view\/><\/code> &#8212; \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0437 <code>vue-router<\/code>.<\/p>\n<\/li>\n<\/ul>\n<p>\u041c\u043e\u0436\u043d\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 <code>App.vue<\/code> \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u0448\u0430\u0431\u043b\u043e\u043d wrapper \u0434\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438, \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u0443\u044e\u0449\u0438\u0435 \u0432 \u0441\u0435\u0431\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0440\u043e\u0443\u0442\u0438\u043d\u0433\u0430 \u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430. \u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <code>router<\/code> &#8212; \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u043e\u0434\u0438\u043d \u0444\u0430\u0439\u043b <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/blob\/chapter-4.1\/j-sso\/client\/src\/router\/index.js\" rel=\"noopener noreferrer nofollow\"><code>index.js<\/code><\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <code>vue-router<\/code>. \u0422\u0430\u043a\u0436\u0435 \u0432 \u043d\u0435\u0439 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 <code>Router<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u0444\u0430\u0439\u043b\u0435 <code>main.js<\/code>. \u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 <code>vue-router<\/code> \u043c\u043e\u0436\u043d\u043e \u043d\u0430 \u0438\u0445 <a href=\"https:\/\/router.vuejs.org\/guide\/\" rel=\"noopener noreferrer nofollow\">\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u043c \u0441\u0430\u0439\u0442\u0435<\/a>.<\/p>\n<p>\u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <code>store<\/code> &#8212; \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u0444\u0430\u0439\u043b <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/blob\/chapter-4.1\/j-sso\/client\/src\/store\/index.js\" rel=\"noopener noreferrer nofollow\"><code>index.js<\/code><\/a>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 <code>vuex<\/code>. \u0414\u0430\u043d\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043e \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043c\u0435\u0436\u0434\u0443 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430\u043c\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446. \u0412\u043d\u0443\u0442\u0440\u0438 \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>sessionStorage<\/code> \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0439 \u0432 \u043b\u044e\u0431\u043e\u043c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435. \u0422\u0430\u043a\u0436\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u043c\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u043f\u043b\u0430\u0433\u0438\u043d <code>VuexPersistence<\/code>&#8212; \u043e\u043d \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 (\u0442\u0430\u043a \u043a\u0430\u043a <code>sessionStorage<\/code> \u0431\u0443\u0434\u0435\u0442 \u043e\u0447\u0438\u0449\u0435\u043d \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c). \u041e\u0431\u044b\u0447\u043d\u043e \u0442\u0430\u043a\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435: \u0435\u0433\u043e \u0442\u043e\u043a\u0435\u043d\u044b \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0438 \u0442.\u0434. \u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u043c\u043e\u0436\u043d\u043e \u0438 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u044d\u0442\u0443 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 <code>localStorage<\/code> \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430, \u0438\u043b\u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c <code>vuex<\/code>, \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0441\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 <code>localStorage<\/code>. \u041d\u043e \u043d\u0430\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0441\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e <code>sessionStorage<\/code>. \u0410 \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0438\u0437\u043e\u0431\u0440\u0435\u0442\u0430\u0442\u044c &#171;\u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434\u043e\u0432&#187;, \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u043b\u0430\u0433\u0438\u043d \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u0442\u0440\u043e\u0433\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043c\u0435\u0436\u0434\u0443 \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430\u043c\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b.<\/p>\n<p>\u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <code>modules<\/code> \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c\u044b\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e <code>vuex<\/code>. \u042d\u0442\u0438 \u043c\u043e\u0434\u0443\u043b\u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0441\u043e\u0431\u043e\u0439 js \u0444\u0430\u0439\u043b\u044b, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u043f\u0438\u0441\u0430\u043d \u0431\u043b\u043e\u043a \u0445\u0440\u0430\u043d\u0438\u043c\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0441 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0435\u044e. \u0411\u043e\u043b\u0435\u0435 \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043c\u043e\u0434\u0443\u043b\u044f\u0445 <code>vuex<\/code> \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u0432 <a href=\"https:\/\/vuex.vuejs.org\/guide\/modules.html\" rel=\"noopener noreferrer nofollow\">\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/a>. \u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u043e\u0434\u0438\u043d \u043c\u043e\u0434\u0443\u043b\u044c &#8212; <code>security<\/code>. \u041e\u043d \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435 \u0438 \u0435\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0435 \u043f\u0440\u0438\u0432\u0438\u043b\u0435\u0433\u0438\u0439.<\/p>\n<p>\u041d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c \u043e\u0431 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>global<\/code>. \u042d\u0442\u043e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445: vue \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432, \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432, \u043c\u0438\u043a\u0441\u0438\u043d\u043e\u0432 \u0438 \u0442.\u0434. \u041a\u0430\u0436\u0434\u044b\u0439 \u0442\u0438\u043f \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0441\u0432\u043e\u0435\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0438 \u0438\u043c\u0435\u0435\u0442 \u0432 \u043d\u0435\u0439 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0444\u0430\u0439\u043b, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0433\u043e \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438. \u042d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 vue \u043f\u043b\u0430\u0433\u0438\u043d. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>components<\/code> \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0444\u0430\u0439\u043b <code>components-lib-plugin.js<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043d\u0438\u0436\u0435. \u041a\u0430\u043a \u043c\u044b \u0432\u0438\u0434\u0438\u043c, \u043e\u043d \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p><code><strong>components-lib-plugin.js<\/strong><\/code><\/p>\n<pre><code>import JTextField from '.\/uikit\/j-textfield.vue'; import JDatePicker from \".\/uikit\/j-date-picker.vue\"; import JReqDoneIndicator from \".\/uikit\/j-req-done-indicator.vue\"; import JSectionDivider from \".\/uikit\/j-section-divider.vue\"; import JAvatar from \".\/uikit\/img\/j-avatar.vue\"; import JImg from \".\/uikit\/img\/j-img.vue\"; import JExceptionPlugin from \".\/uikit\/j-exception\/j-exception-plugin\";  import JLogo from \".\/specified\/j-logo.vue\";  export default {      install(Vue, opts) {         Vue.component(JTextField.name, JTextField);         Vue.component(JDatePicker.name, JDatePicker);         Vue.component(JReqDoneIndicator.name, JReqDoneIndicator);         Vue.component(JSectionDivider.name, JSectionDivider);         Vue.component(JAvatar.name, JAvatar);         Vue.component(JImg.name, JImg);         Vue.use(JExceptionPlugin, opts);          Vue.component(JLogo.name, JLogo);     } } <\/code><\/pre>\n<p>\u0412\u0441\u0435 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u044e\u0442\u0441\u044f \u0432 \u0444\u0430\u0439\u043b\u0435 <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/blob\/chapter-4.1\/j-sso\/client\/src\/global\/global-lib-plugin.js\" rel=\"noopener noreferrer nofollow\"><code>global-lib-plugin.js<\/code><\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0444\u0430\u0439\u043b\u0435 <code>main.js<\/code>. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0443\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0432\u0435\u0441\u044c \u0445\u0430\u043e\u0441 \u0441 \u0438\u043c\u043f\u043e\u0440\u0442\u0430\u043c\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f, \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0435\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0438 \u0442.\u0434., \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u0435\u0448\u0430\u0435\u0442 \u0432\u0438\u0434\u0435\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u043d\u0443\u044e \u0441\u0443\u0442\u044c, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0438 \u0440\u0430\u0437\u0432\u0438\u0442\u0438\u0435 \u044d\u0442\u043e\u0433\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u044f. \u0421\u0442\u043e\u0438\u0442 \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0440\u043e \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u043f\u043b\u0430\u0433\u0438\u043d\u0443. \u042d\u0442\u0438\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u044e\u0442 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 <code>Vuex<\/code> \u0438 <code>Vue-Router<\/code>. \u0423\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043e\u043d\u0438 \u043f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u0432 <code>main.js<\/code>:<\/p>\n<p><code><strong>main.js<\/strong><\/code><\/p>\n<pre><code>\/\/ ..... createApp(App)         .use(router)         .use(store)         .use(GlobalLib, {             store: store,             router: router         })         .mount('#app'); \/\/ ..... <\/code><\/pre>\n<p>\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432 \u043c\u0438\u043a\u0441\u0438\u043d\u0430\u0445, \u043f\u043b\u0430\u0433\u0438\u043d\u0430\u0445 \u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u0445, \u043a\u0430\u043a \u0432\u044b \u0443\u0432\u0438\u0434\u0438\u0442\u0435 \u0434\u0430\u043b\u0435\u0435.<\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0447\u0443\u0442\u044c \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u0435\u0439 \u043f\u043e\u0433\u0440\u0443\u0437\u0438\u043c\u0441\u044f \u0432 \u043a\u0430\u0436\u0434\u0443\u044e \u0438\u0437 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0439, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043d\u044f\u0442\u044c, \u0447\u0442\u043e \u0432 \u043d\u0435\u0439 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f. \u041f\u0435\u0440\u0432\u0430\u044f \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u044d\u0442\u043e <code>components<\/code>. \u041a\u0430\u043a \u0443\u0436\u0435 \u0431\u044b\u043b\u043e \u0441\u043a\u0430\u0437\u0430\u043d\u043e, \u0432 \u043d\u0435\u0439 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/49b\/78b\/478\/49b78b478d3c097af27bce1ade82d116.png\" alt=\"\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 global\" title=\"\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 global\" width=\"1200\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/49b\/78b\/478\/49b78b478d3c097af27bce1ade82d116.png\"\/><\/p>\n<div><figcaption>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 global<\/figcaption><\/div>\n<\/figure>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434\u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0439 &#8212; <code>uikit<\/code> \u0438 <code>app<\/code>. \u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>uikit<\/code> \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043e\u0431\u0440\u0430\u0437\u0443\u044e\u0449\u0438\u0435 \u043e\u0431\u0449\u0438\u0439 \u043d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f ui \u0444\u043e\u0440\u043c, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a: \u043f\u043e\u043b\u044f \u0432\u0432\u043e\u0434\u0430, \u043a\u043d\u043e\u043f\u043a\u0438, \u0434\u0440\u0443\u0433\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f. \u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>app<\/code> \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044b\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0438 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043e\u0442\u043d\u043e\u0441\u044f\u0449\u0438\u0435\u0441\u044f \u043b\u0438\u0431\u043e \u043a \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0435, \u043b\u0438\u0431\u043e \u043a \u043e\u0444\u043e\u0440\u043c\u043b\u0435\u043d\u0438\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0421\u043c\u044b\u0441\u043b \u0442\u0430\u043a\u043e\u0433\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>uikit<\/code> \u0432 \u0434\u0440\u0443\u0433\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435.<\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u0435\u0439 \u0432\u0437\u0433\u043b\u044f\u043d\u0435\u043c \u043d\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>uikit<\/code>.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/cfa\/c4a\/d71\/cfac4ad71a40d7ac0b678db4a3d24c9d.png\" alt=\"\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 components\" title=\"\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 components\" width=\"1200\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/cfa\/c4a\/d71\/cfac4ad71a40d7ac0b678db4a3d24c9d.png\"\/><\/p>\n<div><figcaption>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 components<\/figcaption><\/div>\n<\/figure>\n<p>\u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0442\u0443\u0442 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u044f\u0432\u043b\u044f\u044e\u0449\u0438\u0435\u0441\u044f \u043e\u0431\u0451\u0440\u0442\u043a\u0430\u043c\u0438 \u0434\u043b\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 <code>vuetify<\/code>. \u0417\u0430\u0447\u0435\u043c \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u043d\u043e? \u0421\u0434\u0435\u043b\u0430\u043d\u043e \u044d\u0442\u043e \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u043d\u0430 \u0444\u043e\u0440\u043c\u0435 \u0438 \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043e\u0434\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0441\u0432\u0435\u0441\u0442\u0438 \u043a \u0435\u0434\u0438\u043d\u043e\u043c\u0443 \u0441\u0442\u0438\u043b\u044e. \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b <code>vuetify<\/code> \u0441\u043b\u0430\u0432\u044f\u0442\u0441\u044f \u0441\u0432\u043e\u0438\u043c \u0431\u043e\u0433\u0430\u0442\u044b\u043c \u043d\u0430\u0431\u043e\u0440\u043e\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0434\u043b\u044f \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u0438, \u0438 \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u0438\u0437-\u0437\u0430 \u044d\u0442\u043e\u0433\u043e \u043d\u0430 \u0444\u043e\u0440\u043c\u0430\u0445 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u043b\u043d\u044b\u0439 \u0445\u0430\u043e\u0441 \u0438 \u043d\u0435\u0440\u0430\u0437\u0431\u0435\u0440\u0438\u0445\u0430. \u0414\u0430 \u0435\u0449\u0451 \u0438 \u043a\u043e\u0434 \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0444\u043e\u0440\u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0433\u0440\u043e\u043c\u043d\u044b\u043c, \u043d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u043d\u0430 \u043d\u0435\u0439 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432\u0441\u0435\u0433\u043e \u043f\u0430\u0440\u0443 \u043f\u043e\u043b\u0435\u0439. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0432\u0441\u0435\u0433\u0434\u0430 \u0432 \u0441\u0432\u043e\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e \u0434\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0441 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c\u0438-\u043e\u0431\u0451\u0440\u0442\u043a\u0430\u043c\u0438.<\/p>\n<p>\u0418\u043d\u043e\u0433\u0434\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0441 \u043d\u0443\u043b\u044f \u0438 \u0432\u0434\u043e\u0431\u0430\u0432\u043e\u043a \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043c\u043e\u0434\u0443\u043b\u044f \u0434\u043b\u044f <code>store<\/code>. \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u0445\u043e\u0434 \u043a\u0430\u043a \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435 <code>j-exception<\/code>. \u0412 \u043d\u0451\u043c \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0444\u0430\u0439\u043b \u0441 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u043c vue, \u043c\u043e\u0434\u0443\u043b\u044c \u0434\u043b\u044f vuex, \u0430 \u0442\u0430\u043a\u0436\u0435 vue-\u043f\u043b\u0430\u0433\u0438\u043d, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0435\u0433\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435. \u0414\u0430\u043b\u0435\u0435 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>components-lib-plugin.js<\/code> \u043c\u044b \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u0443\u0436\u0435 \u0441\u0430\u043c \u043f\u043b\u0430\u0433\u0438\u043d.<\/p>\n<p>\u041d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u0434\u0430\u043d\u043d\u044b\u0439 vue-\u043f\u043b\u0430\u0433\u0438\u043d \u0441 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u043c\u0438. \u041c\u043e\u0434\u0443\u043b\u044c \u0434\u043b\u044f vuex \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438. \u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u043b\u0430\u0433\u0438\u043d\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 Vuex \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 <code>store<\/code>. \u0418\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u0435\u0437\u0434\u0435 \u043c\u044b \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u0435\u043c <code>options<\/code> \u0434\u043b\u044f \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432.<\/p>\n<p><code><strong>j-exception-plugin.js<\/strong><\/code><\/p>\n<pre><code>import JException from '.\/j-exception.vue'; import exceptionStoreModule from '.\/j-exception-store-module';  export default {     install(Vue, options) {         options = options || {};          \/\/ \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0438\u0437 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 vuex         let store = options.store;          \/\/ \u0435\u0441\u043b\u0438 \u043d\u0435\u0442, \u0442\u043e \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0435\u0433\u043e \u0438\u0437 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 Vue.         if (!store) {             store = Vue.$store;         }          \/\/ \u0435\u0441\u043b\u0438 \u043d\u0435\u0442, \u0442\u043e \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u043c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435         if (!store) {             throw new TypeError(\"store is required in options, if not define in Vue instance\");         }          \/\/ \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c store \u043c\u043e\u0434\u0443\u043b\u044c         store.registerModule('exceptionStoreModule', exceptionStoreModule);          \/\/ \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442         Vue.component(JException.name, JException);     } } <\/code><\/pre>\n<p>\u0421\u043f\u0438\u0441\u043e\u043a \u0432\u0441\u0435\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0438 \u0437\u0430\u0447\u0435\u043c \u043e\u043d\u0438 \u043d\u0443\u0436\u043d\u044b \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043d\u0438\u0436\u0435:<\/p>\n<ul>\n<li>\n<p><code>j-exception<\/code> &#8212; \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044b\u0439 \u0434\u043b\u044f \u0432\u044b\u0432\u043e\u0434\u0430 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438 http \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445. \u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0438 stacktrace, \u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 vuex \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435. \u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 \u0441\u0432\u044f\u0437\u043a\u0435 \u0441 <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/blob\/chapter-4.1\/j-sso\/client\/src\/global\/plugins\/axios-plugin.js\" rel=\"noopener noreferrer nofollow\"><code>axios-plugin.js<\/code><\/a>.<\/p>\n<\/li>\n<li>\n<p><code>j-date-picker.vue<\/code> &#8212; \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043f\u0440\u0435\u0434-\u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u043f\u043e\u043b\u044f \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 \u0434\u0430\u0442\u044b. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <code>@vuepic\/vue-datepicker<\/code>.<\/p>\n<\/li>\n<li>\n<p><code>j-req-done-indicator.vue<\/code> &#8212; \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u0430.<\/p>\n<\/li>\n<li>\n<p><code>j-section-divider.vue<\/code> &#8212; \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043b\u0438\u043d\u0438\u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p><code>j-textfield.vue<\/code> &#8212; \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u043f\u043e\u0432\u0435\u0440\u0445 <code>v-text-field<\/code> \u0438\u0437 <code>vuetify<\/code> \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u043e\u043b\u044f \u0432\u0432\u043e\u0434\u0430 \u0442\u0435\u043a\u0441\u0442\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c, \u0447\u0442\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>plugins<\/code>:<\/p>\n<ul>\n<li>\n<p><code>plugins-lib-plugin.js<\/code> &#8212; \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0430\u0439\u043b \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p><code>axios-plugin.js<\/code> &#8212; \u0442\u0443\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 axios \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c\u0438 \u0438\u043d\u0442\u0435\u0440\u0446\u0435\u043f\u0442\u043e\u0440\u0430\u043c\u0438 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u043e\u0448\u0438\u0431\u043e\u043a http \u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/p>\n<\/li>\n<li>\n<p><code>vee-validate.js<\/code> &#8212; \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <code>vee-validate<\/code> \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u043e\u0432 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0444\u043e\u0440\u043c.<\/p>\n<\/li>\n<li>\n<p><code>vuetify-plugin.js<\/code> &#8212; \u043f\u043b\u0430\u0433\u0438\u043d \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 <code>vuetify<\/code>.<\/p>\n<\/li>\n<\/ul>\n<p>\u0423 \u0432\u0430\u0441 \u043c\u043e\u0436\u0435\u0442 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0443\u0442\u044c \u0432\u043e\u043f\u0440\u043e\u0441: \u0437\u0430\u0447\u0435\u043c \u043d\u0430\u043c <code>mixin<\/code> \u0438 <code>functions<\/code>, \u0438 \u043a\u0430\u043a \u043e\u043d\u0438 \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0431\u043e\u0439 \u0441\u0432\u044f\u0437\u0430\u043d\u044b. \u0414\u0435\u043b\u043e \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 <code>Vue 3<\/code> \u0443 \u043d\u0430\u0441 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f <a href=\"https:\/\/v3.ru.vuejs.org\/ru\/api\/composition-api.html\" rel=\"noopener noreferrer nofollow\">Composition API<\/a>. \u041f\u0440\u0438 \u0442\u0430\u043a\u043e\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u0435 \u043c\u0438\u043a\u0441\u0438\u043d\u044b \u043d\u0435 \u043d\u0443\u0436\u043d\u044b, \u0430 \u043d\u0443\u0436\u043d\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u044b \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b\u0438 \u0442\u0435 \u0436\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f functions, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f js \u0444\u0430\u0439\u043b\u044b \u0441 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438, \u0438 \u0435\u0441\u0442\u044c mixin \u0434\u043b\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f Options API. \u041d\u0438\u0436\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u0434\u043b\u044f \u0447\u0435\u0433\u043e \u043e\u043d\u0438 \u043d\u0443\u0436\u043d\u044b:<\/p>\n<ul>\n<li>\n<p><code>notification-funcs.js<\/code> \u0438 <code>notification-mixin.js<\/code> &#8212; \u0443\u0434\u043e\u0431\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0438\u0445 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p><code>date-helper-funcs.js<\/code> &#8212; \u0443\u0434\u043e\u0431\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0430\u0442\u043e\u0439 \u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 <code>moment<\/code>.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u043c\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438 \u0432\u0441\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u044b, \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438 \u0442.\u0434. \u043d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0435\u0439 <code>views<\/code>. \u041a\u0430\u043a \u043f\u043e\u043d\u044f\u0442\u043d\u043e \u0438\u0437 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f, \u043e\u043d\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432\u0441\u0435 \u0444\u043e\u0440\u043c\u044b \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0415\u0441\u0442\u044c \u043d\u0435\u043a\u0430\u044f \u0438\u0434\u0435\u043e\u043b\u043e\u0433\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u044f \u0437\u0430\u043b\u043e\u0436\u0438\u043b \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u044d\u0442\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438. \u041e\u043d\u0430 \u0433\u043b\u0430\u0441\u0438\u0442, \u0447\u0442\u043e \u043a\u0430\u0436\u0434\u0430\u044f \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0444\u043e\u0440\u043c\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 &#171;\u043c\u0438\u043a\u0440\u043e-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435&#187; \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0432 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438. \u041e\u043d\u043e \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437:<\/p>\n<ul>\n<li>\n<p>\u043e\u0434\u043d\u043e\u0439 (\u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0434\u043b\u044f \u0441\u0435\u0431\u044f) \u0444\u043e\u0440\u043c\u044b \u0432 \u0432\u0438\u0434\u0435 vue \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430<\/p>\n<\/li>\n<li>\n<p>\u0441\u0432\u043e\u0435\u0433\u043e \u0441\u043b\u043e\u044f <code>service<\/code>, \u0433\u0434\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u043f\u043e HTTP \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p>\u0430 \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043c\u0438\u043a\u0441\u0438\u043d\u044b, utility \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0431\u044f\u0437\u0430\u043d\u044b \u0431\u044b\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0434\u0430\u043d\u043d\u043e\u0433\u043e &#171;\u043c\u0438\u043a\u0440\u043e-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f&#187;.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0444\u043e\u0440\u043c\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0435\u0431\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u0435\u0449\u0451 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0444\u043e\u0440\u043c. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440: \u0444\u043e\u0440\u043c\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u043c\u0435\u044e\u0442 \u043e\u0431\u0449\u0438\u0439 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440. \u0414\u0430\u043d\u043d\u044b\u0435 \u0444\u043e\u0440\u043c\u044b (&#171;\u043c\u0438\u043a\u0440\u043e-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f&#187;) \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u044b \u0432 \u043e\u0434\u043d\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0440\u043e\u0443\u0442\u0438\u043d\u0433\u0430 \u0432 <code>router\/index.js<\/code>.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/87f\/f21\/5d6\/87ff215d6264e88a8cda00ea75373247.png\" alt=\"\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 components\" title=\"\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 components\" width=\"1200\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/87f\/f21\/5d6\/87ff215d6264e88a8cda00ea75373247.png\"\/><\/p>\n<div><figcaption>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 components<\/figcaption><\/div>\n<\/figure>\n<p>\u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0434\u0432\u0435 \u043f\u043e\u0434\u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438:<\/p>\n<ul>\n<li>\n<p><code>sing-view<\/code> &#8212; \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u0434\u043b\u044f \u0432\u0441\u0435\u0433\u043e \u0447\u0442\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e \u0441 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0435\u0439 \u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0435\u0439.<\/p>\n<\/li>\n<li>\n<p><code>home<\/code>&#8212; \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u0434\u043b\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u043b\u0435 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438.<\/p>\n<\/li>\n<\/ul>\n<p><code>sing-view<\/code> \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0444\u0430\u0439\u043b <code>sign-view.vue<\/code> (\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440) \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>login<\/code> \u0438 <code>components<\/code>. \u0412 <code>components<\/code> \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u0444\u043e\u0440\u043c. <code>login<\/code> &#8212; \u044d\u0442\u043e &#171;\u043c\u0438\u043a\u0440\u043e-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435&#187;, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u0443\u0435\u0442 \u0432 \u0441\u0435\u0431\u0435 \u0432\u0441\u0451, \u0447\u0442\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e \u0441 \u0444\u043e\u0440\u043c\u043e\u0439 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438. \u0414\u0430\u043b\u0435\u0435, \u043d\u0430\u0440\u0430\u0432\u043d\u0435 \u0441 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0435\u0439 <code>login<\/code>, \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <code>registration<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432 \u0441\u0435\u0431\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0432\u0441\u0451, \u0447\u0442\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e \u0441 \u0444\u043e\u0440\u043c\u043e\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 (\u0441\u0432\u043e\u0438 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u0441\u043b\u043e\u0439 service \u0438 \u0442.\u0434.). \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>sign-view\/components<\/code>, \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u044b \u043a\u0430\u043a \u0432 <code>login<\/code>, \u0442\u0430\u043a \u0438 \u0432 <code>registration<\/code>. \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043e\u0431\u0449\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u044d\u0442\u0438\u043c\u0438 \u0444\u043e\u0440\u043c\u0430\u043c\u0438 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0441\u043b\u043e\u0439 service, \u043c\u0438\u043ac\u0438\u043d\u044b \u0438 \u0442.\u0434.<\/p>\n<p>\u0414\u043b\u044f \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0439 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u043d\u0430\u0448\u0435\u0433\u043e <code>j-sso<\/code> \u0431\u044b\u043b\u0430 \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430. \u0412 \u043d\u0435\u0439 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u043b\u043e\u0433\u0438\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u043c\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0438 \u0432\u044b\u0432\u043e\u0434 \u0438\u0445 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u043a\u0430\u043a \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d \u0441\u043b\u043e\u0439 <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/tree\/chapter-4.1\/j-sso\/client\/src\/views\/home\/service\" rel=\"noopener noreferrer nofollow\">service<\/a> \u0434\u043b\u044f \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <code>@dlabs71\/d-dto<\/code>, \u043c\u044b \u0432\u043d\u0430\u0447\u0430\u043b\u0435 \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u043b\u0438 \u043c\u043e\u0434\u0435\u043b\u044c \u043e\u0442\u0432\u0435\u0442\u0430 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0430 \u043f\u043e\u0442\u043e\u043c \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u043b\u0438 \u043c\u0435\u0442\u043e\u0434 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u0412\u0441\u044e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0443\u044e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u043f\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e \u044d\u0442\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 <a href=\"https:\/\/www.npmjs.com\/package\/@dlabs71\/d-dto\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<p>\u041d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0434\u0430\u043d\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c:<\/p>\n<p><code><strong>home-model.js<\/strong><\/code><\/p>\n<pre><code> import {DATA_TYPE, JsonField, TypeArr, TypeNumber, TypeString} from \"@dlabs71\/d-dto\";  export class UserModel {     @JsonField(\"id\") @TypeString id;     @JsonField(\"firstName\") @TypeString firstName;     @JsonField(\"lastName\") @TypeString lastName;     @JsonField(\"middleName\") @TypeString middleName;     @JsonField(\"birthday\") @TypeString birthday;     @JsonField(\"username\") @TypeString username;     @JsonField(\"email\") @TypeString email;     @JsonField(\"authorities\") @TypeArr(DATA_TYPE.STRING) authorities = [];     @JsonField(\"avatarUrl\") @TypeString avatarUrl; }  <\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043f\u0440\u0438 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0438 \u043a\u043b\u0430\u0441\u0441\u0430 API \u0432 \u0444\u0430\u0439\u043b\u0435 <code>home-service.js<\/code> \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u0432\u044b\u0448\u0435\u0443\u043a\u0430\u0437\u0430\u043d\u043d\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0438 \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u043e\u0447\u0435\u043d\u044c \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439 \u0438 \u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u0414\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043d\u0438\u0436\u0435. \u041f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440\u0430 <code>@GetMapper(UserModel)<\/code> \u043c\u0435\u0442\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c <code>Promise&lt;UserModel><\/code>. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044f \u0441\u0440\u0430\u0437\u0443 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0442\u0435\u043b\u043e\u043c \u043e\u0442\u0432\u0435\u0442\u0430.<\/p>\n<p><code><strong>home-service.js<\/strong><\/code><\/p>\n<pre><code>import axios from 'axios'; import {GetMapper} from \"@dlabs71\/d-dto\"; import {UserModel} from \"@\/views\/home\/service\/home-model\";  export class HomeAPI {      static __USER_DATA_URL = \"\/security-session\/user\";      @GetMapper(UserModel) getCurrentUser() {         return axios.get(HomeAPI.__USER_DATA_URL);     } } <\/code><\/pre>\n<p>\u041d\u0430 \u0431\u044d\u043a\u0435 <code>j-sso<\/code> \u0434\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0439 endpoint \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0435 <code>UIController<\/code>.<\/p>\n<p><code><strong>UIController.java<\/strong><\/code><\/p>\n<pre><code class=\"java\"> @Controller public class UIController {      @GetMapping(\"\/login\")     public String login() {         return \"index\";     }      \/\/ \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u043d\u043e\u0432\u044b\u0439 \u043f\u0443\u0442\u044c, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043f\u0443\u0442\u0438 \u0434\u043b\u044f \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b.     @GetMapping(\"\/home\")     public String home() {         return \"index\";     } } <\/code><\/pre>\n<p>\u0410 \u0442\u0430\u043a\u0436\u0435 \u043d\u0443\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u043f\u0435\u0440\u0442\u0438 <code>spring.security.oauth2.authorizationserver.authentication-success-url<\/code> \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0430\u0441 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u043b\u043e \u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443.<\/p>\n<p><code><strong>application.yml<\/strong><\/code><\/p>\n<pre><code class=\"yaml\">spring:     \/\/ .....     security:         oauth2:             authorizationserver:                 issuer-url: http:\/\/localhost:7777                 introspection-endpoint: \/oauth2\/token-info                 authentication-success-url: http:\/\/localhost:7777\/home # \u0431\u044b\u043b\u043e http:\/\/localhost:7777\/                 custom-handler-header-name: J-Sso-Next-Location      \/\/ ..... <\/code><\/pre>\n<p>\u041f\u043e\u043c\u0438\u043c\u043e \u0432\u0441\u0435\u0433\u043e \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u043c <code>SessionController<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0441\u0435\u0439\u0447\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d endpoint.<\/p>\n<p><code><strong>SessionController.java<\/strong><\/code><\/p>\n<pre><code class=\"java\"> @RestController @RequiredArgsConstructor @RequestMapping(\"\/security-session\") public class SessionController {      @GetMapping(\"\/user\")     public AuthorizedUserDto getCurrentUser() {         AuthorizedUser authorizedUser = SecurityUtils.getAuthUser();         return AuthorizedUserDto.build(authorizedUser);     } } <\/code><\/pre>\n<p>\u041d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043e, \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432\u0435\u0441\u044c \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/79a\/ce1\/bb1\/79ace1bb16e74e2fa8de2ea92d3f5764.gif\" alt=\"\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\" title=\"\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\" width=\"1200\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/79a\/ce1\/bb1\/79ace1bb16e74e2fa8de2ea92d3f5764.gif\"\/><\/p>\n<div><figcaption>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/figcaption><\/div>\n<\/figure>\n<p>\u0418\u0442\u0430\u043a, \u043c\u044b \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 frontend \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u0431\u043e\u043b\u0435\u0435 \u0443\u0432\u043b\u0435\u043a\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 &#8212; \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438.<\/p>\n<blockquote>\n<p>\u0418\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/tree\/chapter-4.1\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<\/blockquote>\n<h3>\u0420\u0430\u0437\u0434\u0435\u043b 4.2: \u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u043d\u0435\u043a\u0438\u0435 \u043e\u0431\u0449\u0435\u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u043f\u043b\u044e\u0448\u043a\u0438<\/h3>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0441\u0440\u0430\u0437\u0443 \u043a\u0438\u0434\u0430\u0442\u044c\u0441\u044f \u0438 \u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0444\u043e\u0440\u043c\u0443 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0434\u0443\u043c\u0430\u0442\u044c \u0432\u0435\u0441\u044c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c. \u041e\u043d \u043d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439, \u043a\u0430\u043a \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434. \u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c, \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0444\u043e\u0440\u043c\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0438 \u043d\u0443\u0436\u043d\u044b\u0439 endpoint \u0434\u043b\u044f \u043f\u0440\u0438\u0451\u043c\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u043a\u0430\u043a\u0438\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0442\u0443\u0442 \u043d\u0430\u0441 \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u0434\u0436\u0438\u0434\u0430\u0442\u044c?<\/p>\n<ol>\n<li>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e endpoint \u043d\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044e, \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0432\u044b\u0432\u0435\u0434\u0435\u043d \u0438\u0437 \u043f\u043e\u0434 security. \u042d\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u043d\u0435\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e, \u0435\u0441\u043b\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0441\u0440\u0430\u0437\u0443 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043c\u0435\u0449\u0430\u0442\u044c\u0441\u044f \u0432 \u0411\u0414.<\/p>\n<\/li>\n<li>\n<p>\u0418\u0437-\u0437\u0430 \u043f\u0443\u043d\u043a\u0442\u0430 (1) \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u044f\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0433\u0440\u043e\u043c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043d\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0448\u0430\u0442\u044c, \u043a\u0430\u043a \u0443\u0434\u0430\u043b\u044f\u0442\u044c \u0435\u0451.<\/p>\n<\/li>\n<\/ol>\n<p>\u0420\u0435\u0448\u0438\u0442\u044c \u0432\u0442\u043e\u0440\u0443\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438. \u0410 \u043a\u0430\u043a \u0440\u0435\u0448\u0438\u0442\u044c \u043f\u0435\u0440\u0432\u0443\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443? \u041a\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0432 \u0411\u0414? \u0421\u0442\u043e\u0438\u0442 \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u043c\u044b \u0432 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a Redis. \u0412\u043e\u0442 \u0437\u0434\u0435\u0441\u044c \u043e\u043d \u043d\u0430\u043c \u0438 \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f. \u041f\u0440\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0432\u0441\u044e \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 Redis. \u0422\u0430\u043a\u0436\u0435 \u043e\u043d \u0441\u0440\u0430\u0437\u0443 \u0441\u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043c\u043e\u0447\u044c \u0440\u0435\u0448\u0438\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u043d\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0437\u0430 \u0441\u0447\u0451\u0442 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0432 Redis \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u0436\u0438\u0437\u043d\u0438 \u0437\u0430\u043f\u0438\u0441\u0438.<\/p>\n<p>\u041a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438? \u0422\u0430\u043a \u043a\u0430\u043a \u043f\u043e\u043c\u0438\u043c\u043e <code>user_id<\/code>, \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u043c \u043a\u043b\u044e\u0447\u043e\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u044e\u0449\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c <code>email<\/code>, \u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c OTP (One Time Password, \u041e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c). \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c, \u043f\u043e\u0441\u043b\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0441\u044b\u043b\u0430\u0442\u044c\u0441\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043d\u0430 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 email \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441 \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u043c \u043f\u0430\u0440\u043e\u043b\u0435\u043c. \u041a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u0430\u043b\u0435\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u0432\u0435\u0441\u0442\u0438 \u0433\u0434\u0435-\u0442\u043e \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044e.<\/p>\n<p>\u0418\u0437 \u0432\u0441\u0435\u0433\u043e \u0432\u044b\u0448\u0435\u0441\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/7ef\/7b8\/792\/7ef7b879261fdf35e2f766a8ee9b3075.svg\" alt=\"UML \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438\" title=\"UML \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438\" width=\"1200\"\/><\/p>\n<div><figcaption>UML \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438<\/figcaption><\/div>\n<\/figure>\n<ol>\n<li>\n<p>\u0417\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0444\u043e\u0440\u043c\u0435 (email, \u0424\u0418\u041e, \u0434\u0430\u0442\u0430 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f, \u043f\u0430\u0440\u043e\u043b\u044c).<\/p>\n<\/li>\n<li>\n<p>\u0414\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c\u0443 endpoint-\u0443<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043c\u0435\u0449\u0430\u044e\u0442\u0441\u044f \u0432 Redis \u043a\u0430\u043a \u0435\u0441\u0442\u044c, \u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432\u0440\u0435\u043c\u044f \u0436\u0438\u0437\u043d\u0438 \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 (T)<\/p>\n<\/li>\n<li>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c\u0441\u044f email \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u043c \u043f\u0430\u0440\u043e\u043b\u0435\u043c (OTP)<\/p>\n<\/li>\n<li>\n<p>\u0421\u0438\u0441\u0442\u0435\u043c\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u0444\u043e\u0440\u043c\u0443 \u0434\u043b\u044f \u0432\u0432\u043e\u0434\u0430 OTP<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0441\u0432\u043e\u044e email \u043f\u043e\u0447\u0442\u0443, \u0431\u0435\u0440\u0451\u0442 OTP, \u0432\u0432\u043e\u0434\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c \u043d\u0430 \u0444\u043e\u0440\u043c\u0435<\/p>\n<\/li>\n<li>\n<p>\u0421\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0441\u0442\u044c \u043f\u0430\u0440\u043e\u043b\u044f. \u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u0432\u0441\u0435 \u0441\u043e\u043f\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0433\u043e \u0435\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f<\/p>\n<\/li>\n<li>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0444\u043e\u0440\u043c\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u044e\u0449\u0430\u044f \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<\/ol>\n<h4>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0444\u043e\u0440\u043c\u044b<\/h4>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0434\u0443\u043c\u0430\u0435\u043c, \u043a\u0430\u043a \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c. \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u043c \u043f\u0440\u043e \u0442\u043e, \u0447\u0442\u043e \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432 \u043f\u0435\u0440\u0432\u044b\u0439 \u0440\u0430\u0437 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043d\u0430\u0448\u0435\u043c j-sso \u0447\u0435\u0440\u0435\u0437 yandex, google \u0438\u043b\u0438 github, \u043e\u043d \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d. \u0422\u0430\u043a \u043a\u0430\u043a \u0447\u0435\u0440\u0435\u0437 \u0434\u0430\u043d\u043d\u044b\u0439 \u0442\u0438\u043f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u0440\u043e\u043c\u0435 \u043a\u0430\u043a \u0447\u0435\u0440\u0435\u0437 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0447\u0442\u043e\u0432\u044b\u0439 \u044f\u0449\u0438\u043a, \u0442\u043e \u044d\u0442\u0430\u043f \u0441 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435\u043c \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438, \u0434\u0443\u043c\u0430\u044e, \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u0438\u0437\u043b\u0438\u0448\u0435\u043d. \u041f\u043e\u044d\u0442\u043e\u043c\u0443, \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u044b\u0431\u0435\u0440\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044e \u0447\u0435\u0440\u0435\u0437 social oauth, \u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0442\u0432\u0435\u0442\u0430 \u043e\u0442 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438, \u043c\u043e\u0436\u043d\u043e \u0441\u043c\u0435\u043b\u043e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0435\u0433\u043e \u0432 \u0411\u0414. \u041f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441\u0440\u0430\u0437\u0443 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c.<\/p>\n<p>\u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043f\u0435\u0440\u0432\u0430\u044f \u0444\u043e\u0440\u043c\u0430 \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043f\u0430\u0441\u0442\u044c, \u043d\u0430\u0436\u0430\u0432 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 &#171;\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f&#187;, \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0444\u043e\u0440\u043c\u0430 \u0441 \u0432\u044b\u0431\u043e\u0440\u043e\u043c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 (\u043b\u0438\u0431\u043e \u0447\u0435\u0440\u0435\u0437 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0444\u043e\u0440\u043c\u0443, \u043b\u0438\u0431\u043e \u0447\u0435\u0440\u0435\u0437 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u044b). \u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0443\u044e \u043a\u043d\u043e\u043f\u043a\u0443 \u043d\u0430 \u0444\u043e\u0440\u043c\u0435 \u043b\u043e\u0433\u0438\u043d\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u043e \u0441\u0443\u0442\u0438 \u043f\u0440\u043e\u0439\u0434\u0451\u0442 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e, \u043d\u043e \u044d\u0442\u043e \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u043d\u0435\u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0431\u044b \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043b \u0443\u0431\u0440\u0430\u0442\u044c \u044d\u0442\u0443 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441 \u0444\u043e\u0440\u043c\u044b \u043b\u043e\u0433\u0438\u043d\u0430. \u0412 \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043c\u044b \u0441 \u044d\u0442\u0438\u043c \u043f\u043e\u043a\u0430 \u0437\u0430\u043c\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u0431\u0443\u0434\u0435\u043c.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u0441 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0435\u0439 \u0447\u0435\u0440\u0435\u0437 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0432\u0441\u0451 \u044f\u0441\u043d\u043e. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u043e\u0434\u0443\u043c\u0430\u0435\u043c, \u043a\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0444\u043e\u0440\u043c\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438, \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0437\u0430\u0445\u043e\u0447\u0435\u0442 \u043f\u0440\u043e\u0439\u0442\u0438 \u0435\u0451 \u0447\u0435\u0440\u0435\u0437 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0444\u043e\u0440\u043c\u0443. \u041f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u0432\u0435\u0441\u0442\u0438 \u0441\u0432\u043e\u0438 \u0434\u0430\u043d\u043d\u044b\u0435. \u0418\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u043d\u0430\u0448\u0435\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b <code>sso.users<\/code> \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u0432\u0435\u0441\u0442\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435:<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u041f\u043e\u043b\u0435<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u0422\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">e-mail \u0430\u0434\u0440\u0435\u0441<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0414\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0421\u0442\u0440\u043e\u043a\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0443\u0436\u043d\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u043e \u043c\u0430\u0441\u043a\u0435 \u0432\u0432\u043e\u0434\u0430 \u0434\u043b\u044f e-mail \u0430\u0434\u0440\u0435\u0441\u0430<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u0418\u043c\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0414\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0421\u0442\u0440\u043e\u043a\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0435 \u0431\u043e\u043b\u0435\u0435 100 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u0424\u0430\u043c\u0438\u043b\u0438\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0414\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0421\u0442\u0440\u043e\u043a\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0435 \u0431\u043e\u043b\u0435\u0435 100 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u041e\u0442\u0447\u0435\u0441\u0442\u0432\u043e<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0435\u0442<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0421\u0442\u0440\u043e\u043a\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0435 \u0431\u043e\u043b\u0435\u0435 100 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u0414\u0430\u0442\u0430 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0435\u0442<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0414\u0430\u0442\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u041f\u0430\u0440\u043e\u043b\u044c<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0414\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0421\u0442\u0440\u043e\u043a\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0435 \u0431\u043e\u043b\u0435\u0435 100 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u043f\u0430\u0440\u043e\u043b\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0414\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0421\u0442\u0440\u043e\u043a\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0435 \u0431\u043e\u043b\u0435\u0435 100 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u042f \u0445\u043e\u0447\u0443 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e \u043d\u0435 \u043e\u0434\u043d\u043e\u0439 \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0444\u043e\u0440\u043c\u043e\u0439, \u0430 \u043d\u0430 \u0444\u043e\u0440\u043c\u0435 \u0442\u0430\u043a\u043e\u0433\u043e \u0436\u0435 \u0440\u0430\u0437\u043c\u0435\u0440\u0430, \u043a\u0430\u043a \u0438 \u0444\u043e\u0440\u043c\u0430 \u043b\u043e\u0433\u0438\u043d\u0430. \u0412\u0441\u0435 \u043f\u043e\u043b\u044f \u0432 \u0442\u0430\u043a\u0443\u044e \u0444\u043e\u0440\u043c\u0443 \u043d\u0435 \u0432\u043b\u0435\u0437\u0443\u0442, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0430\u0437\u043e\u0431\u044c\u0451\u043c \u043d\u0430 \u0434\u0432\u0430 \u044d\u0442\u0430\u043f\u0430. \u041f\u0435\u0440\u0432\u044b\u043c \u044d\u0442\u0430\u043f\u043e\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u0432\u043e\u0434\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u0441\u0435\u0431\u0435, \u0432\u0442\u043e\u0440\u044b\u043c \u044d\u0442\u0430\u043f\u043e\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u0440\u0438\u0434\u0443\u043c\u044b\u0432\u0430\u0435\u0442 \u043f\u0430\u0440\u043e\u043b\u044c.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u0432\u0435\u0434\u0451\u0442 \u0432\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u0441\u0435\u0431\u0435, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0438\u0445 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440. \u041d\u0430\u0448 j-sso \u043f\u043e\u043b\u043e\u0436\u0438\u0442 \u0438\u0445 \u0432 Redis \u0441 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u043c TTL (Time To Live), \u043f\u0443\u0441\u0442\u044c \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 180 \u0441\u0435\u043a\u0443\u043d\u0434. \u0414\u0430\u043b\u0435\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438. \u0421\u0430\u043c\u044b\u043c \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u0432\u0438\u0434\u0438\u0442\u0441\u044f \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0447\u0435\u0440\u0435\u0437 email, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0439 \u043f\u0440\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438. \u041d\u0430 \u043d\u0435\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0439 \u043f\u0430\u0440\u043e\u043b\u044c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u0432\u0435\u0441\u0442\u0438 \u0433\u0434\u0435-\u0442\u043e \u0432 \u043d\u0430\u0448\u0435\u043c <code>j-sso<\/code>. \u0412\u0441\u0451 \u044d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u0432\u0432\u043e\u0434\u0430 \u0432\u0441\u0435\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u043e\u0442\u043a\u0440\u044b\u0442\u044c\u0441\u044f \u0444\u043e\u0440\u043c\u0430 \u0434\u043b\u044f \u0432\u0432\u043e\u0434\u0430 \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043f\u0430\u0440\u043e\u043b\u044f. \u0421\u0435\u0440\u0432\u0435\u0440, \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u043a\u0438\u0439 \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0439 \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u043d\u0430 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0447\u0442\u043e\u0432\u044b\u0439 \u044f\u0449\u0438\u043a \u043f\u0440\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438. \u041e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c \u0442\u043e\u0436\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u0441\u0432\u043e\u0439 TTL. \u0420\u0430\u0437 \u0443 \u043d\u0430\u0441 \u0434\u0430\u043d\u043d\u044b\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f 180 \u0441\u0435\u043a\u0443\u043d\u0434, \u0442\u043e \u043f\u0443\u0441\u0442\u044c \u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0436\u0435.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u0432\u0432\u043e\u0434\u0430 \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043f\u0430\u0440\u043e\u043b\u044f \u043d\u0430 \u0444\u043e\u0440\u043c\u0435 \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u0411\u0414 \u043e\u0431 \u044d\u0442\u043e\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435. \u041f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0438\u043d\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u043c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0438 \u0435\u0433\u043e \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d \u043d\u0430 \u0444\u043e\u0440\u043c\u0443 \u043b\u043e\u0433\u0438\u043d\u0430. \u041d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u043c\u0430\u043a\u0435\u0442\u044b \u0444\u043e\u0440\u043c:<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/0e8\/bee\/2f6\/0e8bee2f680820c71946e8ba7c4811fb.png\" alt=\"\u041c\u0430\u043a\u0435\u0442\u044b \u0444\u043e\u0440\u043c\" title=\"\u041c\u0430\u043a\u0435\u0442\u044b \u0444\u043e\u0440\u043c\" width=\"1200\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/0e8\/bee\/2f6\/0e8bee2f680820c71946e8ba7c4811fb.png\"\/><\/p>\n<div><figcaption>\u041c\u0430\u043a\u0435\u0442\u044b \u0444\u043e\u0440\u043c<\/figcaption><\/div>\n<\/figure>\n<ol>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0430 \u043b\u043e\u0433\u0438\u043d\u0430<\/p>\n<\/li>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0430 \u0432\u044b\u0431\u043e\u0440\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0430 \u0432\u0432\u043e\u0434\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445<\/p>\n<\/li>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0430 \u0432\u0432\u043e\u0434\u0430 \u043f\u0430\u0440\u043e\u043b\u044f<\/p>\n<\/li>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0430 \u0432\u0432\u043e\u0434\u0430 OTP<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u0432\u0435\u0440\u0448\u0430\u044e\u0449\u0430\u044f \u0444\u043e\u0440\u043c\u0430<\/p>\n<\/li>\n<\/ol>\n<p>\u0412\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0432\u0441\u0451 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0434\u0432\u0435\u0434\u0451\u043c \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0439 \u0438\u0442\u043e\u0433 \u0432\u0441\u0435\u0433\u043e \u0432\u044b\u0448\u0435\u0441\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e:<\/p>\n<ul>\n<li>\n<p>\u0444\u043e\u0440\u043c\u0443 \u043b\u044e\u0431\u0443\u044e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u0431\u0435\u0437 \u043e\u0441\u043e\u0431\u044b\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 Redis \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043d\u0430\u043c\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u0443\u044e \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c <code>spring-boot-starter-data-redis<\/code>. \u0423\u043a\u0430\u0437\u0430\u0442\u044c TTL \u043f\u0440\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0438 \u0442\u043e\u0436\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e.<\/p>\n<\/li>\n<li>\n<p>\u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0411\u0414 \u043c\u044b \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u043b\u0438 \u0432 \u043f\u0440\u043e\u0448\u043b\u044b\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445<\/p>\n<\/li>\n<li>\n<p>\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c OTP \u043c\u043e\u0436\u043d\u043e \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <code>org.apache.commons.lang3.RandomStringUtils<\/code>, \u043b\u0438\u0431\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0432 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 <code>java.util.Random<\/code><\/p>\n<\/li>\n<\/ul>\n<p>\u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435, \u0447\u0442\u043e \u043c\u044b \u043d\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b\u0438 \u0442\u0430\u043a \u044d\u0442\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 email \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u041d\u043e \u0441 \u044d\u0442\u0438\u043c \u0442\u043e\u0436\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u043e\u0441\u043e\u0431\u044b\u0445 \u043d\u0435\u0442, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 <a href=\"https:\/\/jakarta.ee\/specifications\/mail\/2.0\/jakarta-mail-spec-2.0\" rel=\"noopener noreferrer nofollow\"><code>Jakarta Mail<\/code><\/a> \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e. \u041d\u0443 \u0430 \u044f \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u043b \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0439 \u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0445 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430\u0445, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0451. \u041e\u043d\u0430 \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d\u0430 \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 Maven Central <a href=\"https:\/\/mvnrepository.com\/artifact\/ru.dlabs71.library\/d-email\" rel=\"noopener noreferrer nofollow\"><code>d-email<\/code><\/a>. \u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u043f\u043e \u043d\u0435\u0439 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u0432 \u0435\u0451 <a href=\"https:\/\/github.com\/dlabs71\/d-email\" rel=\"noopener noreferrer nofollow\">github \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/a>.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0438\u0445 \u0444\u0430\u043a\u0442\u043e\u0440\u043e\u0432 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 \u0443 \u043d\u0430\u0441 \u043d\u0435\u0442. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0444\u043e\u0440\u043c\u044b. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>registration<\/code> \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>views\/sign-view<\/code>. \u0412 \u043d\u0435\u0439 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u0442\u044c\u0441\u044f \u0432\u0441\u0451, \u0447\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u0444\u043e\u0440\u043c \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438. \u0421\u0430\u043c\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0443 \u043d\u0430\u0441 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 5 \u044d\u0442\u0430\u043f\u043e\u0432 (\u0444\u043e\u0440\u043c\u044b \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u044b \u0447\u0443\u0442\u044c \u0432\u044b\u0448\u0435). \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0432 \u0444\u0430\u0439\u043b\u0435 <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/blob\/chapter-4.2\/j-sso\/client\/src\/views\/sign-view\/registration\/registration.vue\" rel=\"noopener noreferrer nofollow\"><code>registration.vue<\/code><\/a> \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u0432\u0441\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u0444\u043e\u0440\u043c\u0430\u043c\u0438. \u041e\u043d\u0430 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430\u044f, \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043d\u0435\u0439 \u043d\u0435 \u0431\u0443\u0434\u0435\u043c. \u0421\u0430\u043c\u0438 \u0444\u043e\u0440\u043c\u044b \u044d\u0442\u0430\u043f\u043e\u0432 \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u044e\u0442\u0441\u044f \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/tree\/chapter-4.2\/j-sso\/client\/src\/views\/sign-view\/registration\/forms\" rel=\"noopener noreferrer nofollow\"><code>views\/sign-view\/registration\/forms<\/code><\/a>. \u0412 \u043a\u0430\u0436\u0434\u043e\u0439 \u0438\u0437 \u043d\u0438\u0445 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u043f\u043e\u043b\u0435\u0439 \u0444\u043e\u0440\u043c\u044b \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0438\u0445 \u043b\u0438\u0431\u043e \u0432\u043e vuex, \u043b\u0438\u0431\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440.<\/p>\n<ol>\n<li>\n<p><code>mode-step-registration.vue<\/code> &#8212; \u044d\u0442\u0430\u043f \u0432\u044b\u0431\u043e\u0440\u0430 \u0442\u0438\u043f\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p><code>data-step-registration.vue<\/code> &#8212; \u044d\u0442\u0430\u043f \u0432\u0432\u043e\u0434\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445<\/p>\n<\/li>\n<li>\n<p><code>password-step-registration.vue<\/code> &#8212; \u044d\u0442\u0430\u043f \u0432\u0432\u043e\u0434\u0430 \u043f\u0430\u0440\u043e\u043b\u044f \u0438 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u043f\u0430\u0440\u043e\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/p>\n<\/li>\n<li>\n<p><code>confirm-step-registration.vue<\/code> &#8212; \u044d\u0442\u0430\u043f \u0432\u0432\u043e\u0434\u0430 OTP<\/p>\n<\/li>\n<li>\n<p><code>success-step-registration.vue<\/code> &#8212; \u044d\u0442\u0430\u043f \u0438\u043d\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<\/ol>\n<p>\u0414\u0430, \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u0435\u0436\u0434\u0443 \u044d\u0442\u0430\u043f\u0430\u043c\u0438 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c vuex, \u0438 \u043c\u043e\u0434\u0443\u043b\u044c \u0435\u0433\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>views\/sign-view\/registration\/store<\/code>. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u043d\u0430\u0448\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0435 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>store<\/code>. \u0412\u0441\u044f \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 API \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>views\/sign-view\/registration\/service<\/code>.<\/p>\n<ul>\n<li>\n<p><code>registration-service.js<\/code> &#8212; \u0432 \u043d\u0451\u043c \u043c\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0441\u0430\u043c\u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 API \u043f\u043e \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c axios.<\/p>\n<\/li>\n<li>\n<p><code>models.js<\/code> &#8212; \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f DTO \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438. \u0412\u0441\u0451 \u044d\u0442\u043e \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u043f\u043e \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <code>@dlabs71\/d-dto<\/code> (\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u043f\u043e \u043d\u0435\u0439 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 <a href=\"https:\/\/www.npmjs.com\/package\/@dlabs71\/d-dto\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>).<\/p>\n<\/li>\n<\/ul>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0432\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043d\u0430 \u0444\u043e\u0440\u043c\u044b \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>forms<\/code>, \u0442\u043e \u0432\u044b \u043c\u043e\u0433\u043b\u0438 \u0437\u0430\u043c\u0435\u0441\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0438\u0437 \u043d\u0438\u0445 \u043b\u043e\u0433\u0438\u043a\u0430 \u0432\u044b\u043d\u0435\u0441\u0435\u043d\u0430 \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f <code>views\/sign-view\/components<\/code>. \u042d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u043d\u043e &#171;\u043d\u0430 \u0431\u0443\u0434\u0443\u0449\u0435\u0435&#187;. \u041a\u0430\u043a \u0432\u044b \u0434\u0430\u043b\u044c\u0448\u0435 \u0443\u0432\u0438\u0434\u0438\u0442\u0435 \u0432 \u0441\u0442\u0430\u0442\u044c\u0435, \u044d\u0442\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u044b \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 &#171;\u0417\u0430\u0431\u044b\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c&#187;. \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043e \u043d\u0438\u0436\u0435:<\/p>\n<ol>\n<li>\n<p><code>password-form.vue<\/code> &#8212; \u0432\u0432\u043e\u0434 \u043f\u0430\u0440\u043e\u043b\u044f \u0438 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u043f\u0430\u0440\u043e\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/p>\n<\/li>\n<li>\n<p><code>confirm-form.vue<\/code> &#8212; \u0432\u0432\u043e\u0434 OTP<\/p>\n<\/li>\n<li>\n<p><code>success-form.vue<\/code> &#8212; \u0444\u043e\u0440\u043c\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u044e\u0449\u0430\u044f \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<\/ol>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0435\u043c \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e <code>router.js<\/code>. \u041e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c\u0441\u044f \u043d\u0430 \u043d\u0435\u0439 \u0447\u0443\u0442\u044c \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u0435\u0439:<\/p>\n<p><code><strong>router.js<\/strong><\/code><\/p>\n<pre><code>const routes = [     {         \/\/ \u0432\u0441\u0451 \u0447\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \/ \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043f\u043e \u043f\u0443\u0442\u0438 '\/auth'         path: '\/auth',         component: SignView,         children: [             {                 path: 'login',                 name: 'login',                 component: LoginForm,             },              \/\/ \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u0443\u0442\u044c \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u044b \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438             {                 path: 'registration',                 name: 'registration',                 component: RegistrationForm,             },         ]     },     {         path: '\/home',         component: HomeView     } ];  const router = createRouter({      \/\/ \u0414\u043e\u0431\u0430\u0432\u0438\u043c \"\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\" \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430     history: createWebHistory(\"\/client\"),     routes, });  \/\/ \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0445\u0443\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d \u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c. \/\/ \u0415\u0441\u043b\u0438 \u043d\u0435\u0442, \u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0432\u0435\u0440\u0448\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0432\u0445\u043e\u0434\u0430. router.beforeEach((to, from, next) => {     if (to.name &amp;&amp; to.path) {          \/\/ \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d \u0438 \u043c\u044b \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043d\u0430 \u043b\u044e\u0431\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u043a\u0440\u043e\u043c\u0435 \"login\" \u0438 \"registration\",         \/\/ \u0442\u043e \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u0430\u0441 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \"login\"         if (!store.getters.isAuth &amp;&amp; ![\"login\", \"registration\"].includes(to.name)) {             router.replace({name: 'login'});             return;         }         next();     } });  export default router; <\/code><\/pre>\n<p>\u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u0443\u0442\u044c \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u044b \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438. \u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0445\u0443\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d \u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c. \u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d, \u0442\u043e \u0432 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u043b\u043e\u0433\u0438\u043d\u0430. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0438\u043b\u0438 \u043d\u0435\u0442 \u0431\u0443\u0434\u0435\u043c \u043f\u043e \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c getter-\u0430 <code>isAuth<\/code> \u0438\u0437 vuex \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 (\u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u0439 \u043c\u043e\u0434\u0443\u043b\u044c <code>security.js<\/code>). \u0421\u0430\u043c\u043e\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435 \u043d\u0430\u0441 \u0436\u0434\u0451\u0442 \u0432 \u0441\u0442\u0440\u043e\u0447\u043a\u0435 <code>createWebHistory(\"\/client\")<\/code>, \u0437\u0434\u0435\u0441\u044c \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c &#171;\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442&#187; \u043d\u0430\u0448\u0435\u0433\u043e frontend \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041d\u043e \u044d\u0442\u043e \u0432\u0441\u0451 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0442\u0430\u043a. \u0412\u0441\u043f\u043e\u043c\u043d\u0438\u043c, \u0447\u0442\u043e \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u043b frontend \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e \u043f\u0443\u0442\u0438 <code>\/login<\/code>, endpoint \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u044b\u043b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d \u0432 <code>UIController<\/code>. \u041d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043e \u043a\u0430\u043a \u043e\u043d \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b:<\/p>\n<p><code><strong>UIController.java<\/strong><\/code><\/p>\n<pre><code class=\"java\"> @Controller public class UIController {      @GetMapping(\"\/login\")     public String index() {         return \"index\";     } } <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0436\u0435, \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430\u0447\u0430\u043b\u043e \u0440\u0430\u0441\u0442\u0438, \u0432 \u043d\u0451\u043c \u0441\u0442\u0430\u043b\u0438 \u043f\u043e\u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043d\u043e\u0432\u044b\u0435 \u043f\u0443\u0442\u0438 \u0438 \u0444\u043e\u0440\u043c\u044b. \u0418 \u043e\u0434\u0438\u043d \u044d\u0442\u043e\u0442 \u0431\u0435\u0434\u043d\u044b\u0439 endpoint \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0432\u0441\u0435\u0445 \u043d\u043e\u0432\u044b\u0445 \u043f\u0443\u0442\u0435\u0439 \u043a\u043b\u0438\u0435\u043d\u0442\u0430. \u0414\u0435\u043b\u0430\u0442\u044c \u043f\u043e\u0434 \u043a\u0430\u0436\u0434\u0443\u044e \u043d\u043e\u0432\u0443\u044e \u0444\u043e\u0440\u043c\u0443 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 endpoint \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043f\u043b\u043e\u0445\u043e\u0435. \u042d\u0442\u043e \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0443\u0441\u043b\u043e\u0436\u043d\u044f\u0435\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0438 \u0440\u0430\u0437\u0432\u0438\u0442\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u0438\u0434\u0451\u043c \u043d\u0430 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0443\u044e \u0445\u0438\u0442\u0440\u043e\u0441\u0442\u044c \u0438 \u0443 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c &#171;\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442&#187; (\u0438\u043b\u0438 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043f\u0443\u0442\u044c), \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0443\u0442 \u043d\u0430\u0447\u0438\u0442\u0430\u0442\u044c\u0441\u044f \u0432\u0441\u0435 \u043f\u0443\u0442\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u043c\u044b \u0438\u0437\u043c\u0435\u043d\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442. \u0418 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0435\u0433\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c:<\/p>\n<p><code><strong>ClientController.java<\/strong><\/code><\/p>\n<pre><code class=\"java\"> @Controller public class ClientController {      @GetMapping(\"\/client\/**\")     public String index() {         return \"index\";     } } <\/code><\/pre>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043b\u044e\u0431\u043e\u0439 \u043f\u0443\u0442\u044c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0447\u0438\u043d\u0430\u0442\u044c\u0441\u044f \u0441 <code>client\/...<\/code>, \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043f\u0430\u0434\u0430\u0442\u044c \u043d\u0430 \u0432\u044b\u0448\u0435-\u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0439 endpoint \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0414\u0430\u043b\u0435\u0435 \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043d\u0430\u0448 router \u043f\u043e\u0434\u0445\u0432\u0430\u0442\u0438\u0442 \u043f\u0443\u0442\u044c \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0443\u044e \u0444\u043e\u0440\u043c\u0443.<\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0440\u0430\u0437\u0431\u043e\u0440 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u044b \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043c \u0438 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u0440\u0430\u0437\u0431\u043e\u0440\u0443 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438. \u041d\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f\u0445 \u043d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u0432\u0441\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u0444\u043e\u0440\u043c\u044b frontend \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/post_images\/a05\/b28\/c88\/a05b28c88aa3bca9a681e28645bb5671.jpg\" alt=\"\u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0444\u043e\u0440\u043c\" title=\"\u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0444\u043e\u0440\u043c\" width=\"1200\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/a05\/b28\/c88\/a05b28c88aa3bca9a681e28645bb5671.jpg\" data-blurred=\"true\"\/><\/p>\n<div><figcaption>\u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0444\u043e\u0440\u043c<\/figcaption><\/div>\n<\/figure>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043c\u044b \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u0440\u0430\u0437\u0431\u043e\u0440\u0443 \u043b\u043e\u0433\u0438\u043a\u0438 \u0440\u0430\u0431\u043e\u0442\u044b endpoint-\u043e\u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u043e\u0435 \u043e\u0442\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435 \u0438 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e\u0431\u0449\u0435\u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0435\u0449\u0451 \u043d\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b\u0438. \u042d\u0442\u043e ExceptionHandling \u0438 ResourceBundle.<\/p>\n<h4>ResourceBundle<\/h4>\n<p>\u0412 \u043b\u044e\u0431\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0433\u0434\u0435-\u0442\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0434\u0440. \u0411\u043e\u043b\u0435\u0435 \u0442\u043e\u0433\u043e, \u0438\u043d\u043e\u0433\u0434\u0430 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0438\u0445 \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 \u043f\u0430\u043a\u0435\u0442\u0435 <code>java.util<\/code> \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043a\u043b\u0430\u0441\u0441 <a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/17\/docs\/api\/java.base\/java\/util\/ResourceBundle.html\" rel=\"noopener noreferrer nofollow\"><code>ResourceBundle<\/code><\/a>. \u0410 \u0432 Spring \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 <a href=\"https:\/\/docs.spring.io\/spring-framework\/docs\/current\/javadoc-api\/org\/springframework\/context\/support\/ResourceBundleMessageSource.html\" rel=\"noopener noreferrer nofollow\"><code>ResourceBundleMessageSource<\/code><\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043c\u0435\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c\u0438 \u0438 \u043e\u043f\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e <code>ResourceBundle<\/code>. \u0422\u0430\u043a \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0435\u0433\u043e \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0442.\u0434. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0431\u0438\u043d <code>ResourceBundleMessageSource messageSource()<\/code> \u0432 <code>RootConfig<\/code>.<\/p>\n<p><code><strong>RootAppConfig.java<\/strong><\/code><\/p>\n<pre><code class=\"java\"> public class RootAppConfig {     \/\/ ......      \/**      * \u0411\u0438\u043d \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0439 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u0445\u0440\u0430\u043d\u0438\u043c\u044b\u043c\u0438 \u0432 .properties \u0444\u0430\u0439\u043b\u0430\u0445.      *\/     @Bean     public ResourceBundleMessageSource messageSource() {         ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();         messageSource.setBasenames(\"messages\");         messageSource.setDefaultEncoding(\"UTF-8\");         return messageSource;     }      \/\/ ..... }  <\/code><\/pre>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u043c\u044b \u0443\u043a\u0430\u0437\u0430\u043b\u0438 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 basename \u0440\u0430\u0432\u043d\u044b\u0439 <code>messages<\/code>. \u0422\u043e \u0432 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u0445 \u043d\u0430\u0448\u0435\u0433\u043e <code>j-sso<\/code> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c Resource Bundle \u0441 \u0438\u043c\u0435\u043d\u0435\u043c <code>messages.properties<\/code>. \u0422\u0430\u043a\u0436\u0435 \u0443\u043a\u0430\u0436\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0440\u0443\u0441\u0441\u043a\u0443\u044e \u043b\u043e\u043a\u0430\u043b\u044c \u0438 \u0431\u0443\u0434\u0435\u043c \u0435\u0451 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u043f\u043e \u043c\u0435\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 \u043c\u043e\u0436\u043d\u043e \u0432 <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/blob\/chapter-4.2\/j-sso\/src\/main\/resources\/messages_ru_RU.properties\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/a>.<\/p>\n<p>\u041f\u043e\u043c\u0438\u043c\u043e \u044d\u0442\u043e\u0433\u043e, \u0445\u043e\u0440\u043e\u0448\u043e \u0431\u044b \u0438\u043c\u0435\u0442\u044c \u043d\u0435\u043a\u0438\u0439 \u043a\u043b\u0430\u0441\u0441-\u0441\u0435\u0440\u0432\u0438\u0441, \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u0438 \u0431\u044b\u0441\u0442\u0440\u043e \u0434\u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u043e \u0438\u0445 \u043a\u043e\u0434\u0443. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c <code>MessageService<\/code>.<\/p>\n<p><code><strong>MessageService.java<\/strong><\/code><\/p>\n<pre><code class=\"java\"> @Slf4j @Service @RequiredArgsConstructor public class MessageService {      public static Locale russian = new Locale(\"ru\", \"RU\");     private final ResourceBundleMessageSource messageSource;      \/**      * \u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u043e \u0435\u0433\u043e \u043a\u043e\u0434\u0443.      *      * @return \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 \u043a\u043e\u0434\u0443 \u0438\u043b\u0438 \u043f\u0440\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441\u0430\u043c \u043a\u043e\u0434.      *\/     public String getMessage(String code) {         return getMessage(code, russian);     }      \/**      * \u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u043e \u0435\u0433\u043e \u043a\u043e\u0434\u0443 \u0438 \u043b\u043e\u043a\u0430\u043b\u0438      *      * @return \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 \u043a\u043e\u0434\u0443 \u0438\u043b\u0438 \u043f\u0440\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441\u0430\u043c \u043a\u043e\u0434.      *\/     public String getMessage(String code, Locale locale) {         try {             return messageSource.getMessage(code, null, Optional.ofNullable(locale).orElse(russian));         } catch (Exception e) {             log.warn(\"Get message key='\" + code + \"' error:\" + e.getMessage());         }         return code;     }      \/**      * \u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u043e \u0435\u0433\u043e \u043a\u043e\u0434\u0443 \u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f args.      *      * @return \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 \u043a\u043e\u0434\u0443 \u0438\u043b\u0438 \u043f\u0440\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441\u0430\u043c \u043a\u043e\u0434.      *\/     public String getMessage(String code, Object... args) {         return messageSource.getMessage(code, args, russian);     } } <\/code><\/pre>\n<p>\u0418\u0442\u0430\u043a, \u0442\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0442.\u0434. \u0432 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 <code>.property<\/code> \u0444\u0430\u0439\u043b\u0430\u0445. \u0415\u0441\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0445 \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0435\u0441\u0442\u044c \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0430\u043d\u043d\u044b\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435\u043c.<\/p>\n<h4>ExceptionHandle<\/h4>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043e\u0431 ExceptionHandle. \u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u0440\u0430\u0437\u0433\u043e\u0432\u043e\u0440 \u043e\u0431 \u044d\u0442\u043e\u043c \u0432\u044b\u0445\u043e\u0434\u0438\u0442 \u0437\u0430 \u0440\u0430\u043c\u043a\u0438 \u043d\u0430\u0448\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0438, \u0434\u0443\u043c\u0430\u044e, \u043f\u043e\u0437\u0436\u0435 \u044f \u043d\u0430\u043f\u0438\u0448\u0443 \u043e\u0431 \u044d\u0442\u043e\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u0441\u0432\u043e\u0439 \u043e\u043f\u044b\u0442 \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 Exception \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445. \u0410 \u0442\u0430\u043a\u0436\u0435, \u043a\u0430\u043a \u0438 \u043a\u0430\u043a\u0438\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u043b\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c, \u043a\u0430\u043a \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0443\u0434\u043e\u0431\u043d\u0443\u044e \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u044e \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u0434\u043b\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438, \u0438 \u043a\u0430\u043a \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u043d\u0430 \u0444\u0440\u043e\u043d\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c.<\/p>\n<p>\u041d\u043e \u0441\u0435\u0439\u0447\u0430\u0441 \u043d\u0430\u043c \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u044d\u0442\u043e, \u0442\u0430\u043a \u043a\u0430\u043a \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0440\u0430\u0441\u0442\u0451\u0442, \u0438 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0430 \u0435\u0433\u043e \u043d\u0430\u0447\u043d\u0451\u0442 \u0441\u043a\u043e\u0440\u043e \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0443 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 \u043d\u0430 \u0444\u0440\u043e\u043d\u0442. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0440\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0445\u043e\u0440\u043e\u0448\u043e \u0431\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438 \u0443\u0436\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 email \u0438\u043b\u0438 \u043d\u0435\u0442, \u0438 \u0435\u0441\u043b\u0438 \u0434\u0430, \u0442\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043e\u0431 \u044d\u0442\u043e\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043d\u0430 \u0444\u0440\u043e\u043d\u0442. \u0418\u043b\u0438 \u043f\u0440\u0438 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u0447\u0442\u043e \u043b\u043e\u0433\u0438\u043d \u0438\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u043d\u0435 \u0432\u0435\u0440\u043d\u044b.<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441\u044b \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043e\u043f\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0438\u0445 \u0438\u043c\u0435\u043d\u0443\u044e\u0442 <code>ServiceException<\/code> \u0438\u043b\u0438 <code>BusinessLogicException<\/code>. \u041c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c <code>ServiceException<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0443\u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d \u043e\u0442 <code>RuntimeException<\/code>, \u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p><code><strong>ServiceException.java<\/strong><\/code><\/p>\n<pre><code class=\"java\"> @Getter @Setter public class ServiceException extends RuntimeException {      private String description;      public ServiceException(String description, Throwable cause) {         super(cause.getMessage(), cause);         this.description = description;     }      public static InformationException.InformationExceptionBuilder builder(String description, Throwable throwable) {         return new InformationException.InformationExceptionBuilder()                 .description(description)                 .throwable(throwable);     }      public static InformationException.InformationExceptionBuilder builder(String description) {         return new InformationException.InformationExceptionBuilder()                 .description(description);     }      @Setter     @Accessors(chain = true, fluent = true)     public static class ServiceExceptionBuilder {          private String description;         private Throwable throwable;          ServiceExceptionBuilder() {         }          public ServiceException build() {             return new ServiceException(description, throwable);         }     } } <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0434\u0443\u043c\u0430\u0435\u043c, \u0430 \u043a\u0430\u043a \u0434\u043e\u043b\u0436\u043d\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430 <code>j-sso<\/code> \u043f\u0440\u0438 \u043e\u0448\u0438\u0431\u043a\u0430\u0445. \u041a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0442\u0430\u043c \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0438 stacktrace. \u041d\u043e \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u043c, \u043a\u0430\u043a \u0444\u0440\u043e\u043d\u0442 \u0443 \u043d\u0430\u0441 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u0432 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0443 \u043d\u0430\u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 <code>j-exception<\/code>, \u0438 \u0432\u0441\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0438\u043d\u0442\u0435\u0440\u0446\u0435\u043f\u0442\u043e\u0440\u0435 axios. \u041d\u0438\u0436\u0435 \u043e\u043d\u0430 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u0430:<\/p>\n<p><code><strong>axios-plugin.js<\/strong><\/code><\/p>\n<pre><code>axios.interceptors.response.use(         (response) => {             return response;         },         (data) => {              let response = data.response;              \/\/ \u0435\u0441\u043b\u0438 \u043d\u0435\u0442 \u0432\u043e\u043e\u0431\u0449\u0435 \u0441\u0435\u0442\u0438             if (\"ERR_NETWORK\" === data.code) {                 let payload = {                     level: \"ERROR\",                     description: \"\u0421\u0435\u0440\u0432\u0438\u0441 \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0441\u0435\u0442\u0438 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0438\u043b\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043f\u043e\u0437\u0434\u043d\u0435\u0435\",                     stacktrace: []                 };                  \/\/ \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0438\u043c \u0447\u0435\u0440\u0435\u0437 j-exception                 store.dispatch('setException', payload);                 return Promise.reject(response);             }              \/\/ \u0435\u0441\u043b\u0438 \u043c\u044b \u043d\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u044b             if (response.status === 401) {                  \/\/ \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0432\u0445\u043e\u0434\u0430                 router.replace({name: \"login\"});                 return Promise.reject(response);             }              \/\/ \u0435\u0441\u043b\u0438 \u0443 \u043d\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0430             if (response.status === 403) {                 let payload = {                     level: \"ERROR\",                     message: \"\u041e\u0442\u043a\u0430\u0437\u0430\u043d\u043e \u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\",                 }                  \/\/ \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u043c \u0447\u0435\u0440\u0435\u0437 \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0438\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f                 store.dispatch('setNotification', payload);                 return Promise.reject(response);             }              \/\/ \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0430 500-\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435             let exception = response.data;             if (!!exception) {                 let payload = {                     level: \"ERROR\",                     description: \"\u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u044f\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\",                     stacktrace: []                 };                  if (!!exception.message) {                     payload.description = exception.message;                 }                 if (!!exception.stacktrace) {                     payload.stacktrace = exception.stacktrace;                 }                  \/\/ \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u043c \u0447\u0435\u0440\u0435\u0437 j-exception                 store.dispatch('setException', payload);             }             return Promise.reject(response);         }); <\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u043d\u043e \u0438\u0437 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430, \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u0432\u0438\u0434\u0430 \u043e\u0448\u0438\u0431\u043e\u043a. \u041f\u0435\u0440\u0432\u044b\u0435 \u0438\u0437 \u043d\u0438\u0445 \u043c\u044b \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c \u0447\u0435\u0440\u0435\u0437 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0435 \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f. \u0410 \u0432\u0442\u043e\u0440\u044b\u0435 &#8212; \u044d\u0442\u043e &#171;\u0442\u044f\u0436\u0435\u043b\u043e\u0432\u0435\u0441\u043d\u044b\u0435&#187; \u043e\u0448\u0438\u0431\u043a\u0438 (\u043e\u0431\u044b\u0447\u043d\u043e 500-\u0435 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430), \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c \u0447\u0435\u0440\u0435\u0437 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0435 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0435 \u043e\u043a\u043d\u043e. \u0412 \u043d\u0451\u043c \u043c\u044b \u0432\u044b\u0432\u043e\u0434\u0438\u043c stacktrace \u0434\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b. \u041d\u043e \u0441\u0442\u043e\u0438\u0442 \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e 500-\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u043c \u043e \u0431\u0430\u0433\u0435, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u044d\u0442\u043e \u043e\u0448\u0438\u0431\u043a\u0430 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0437-\u0437\u0430 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0432\u0432\u0435\u0434\u0451\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0418\u043b\u0438, \u043a\u0430\u043a \u043c\u044b \u0432\u044b\u0448\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b\u0438, \u0438\u0437-\u0437\u0430 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e email \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0435\u0449\u0451 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c. \u041f\u0443\u0441\u0442\u044c \u0432 \u0442\u0435\u043b\u0435 \u043e\u0442\u0432\u0435\u0442\u0430 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043f\u0440\u0438 \u043e\u0448\u0438\u0431\u043a\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u043d\u0435\u043a\u0438\u0439 \u0444\u043b\u0430\u0433 <code>information<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043b \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u044d\u0442\u043e \u043e\u0448\u0438\u0431\u043a\u0430 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438, \u0438 \u0447\u0442\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0432\u043e \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0435\u043c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0438. \u0422\u0430\u043a\u0436\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c <code>ERROR<\/code>, \u0430 \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 <code>WARNING<\/code>. \u0412 \u0441\u0432\u044f\u0437\u0438 \u0441 \u044d\u0442\u0438\u043c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e DTO:<\/p>\n<p><code><strong>ErrorResponseDto.java<\/strong><\/code><\/p>\n<pre><code class=\"java\"> @Getter @Setter @Builder @AllArgsConstructor public class ErrorResponseDto {      private boolean informative;     private ErrorLevel level;     private String message;     @JsonSerialize(using = StackElementSerializer.class)     private StackTraceElement[] stacktrace;      public static ErrorResponseDtoBuilder builder(String message, Throwable cause) {         return new ErrorResponseDtoBuilder()                 .message(message)                 .stacktrace(cause.getStackTrace())                 .informative(false);     }      public static ErrorResponseDtoBuilder builder(String message) {         return new ErrorResponseDtoBuilder()                 .message(message)                 .informative(false);     }      public static ErrorResponseDtoBuilder builder() {         return new ErrorResponseDtoBuilder();     } } <\/code><\/pre>\n<p>\u0423\u0447\u0438\u0442\u044b\u0432\u0430\u044f \u0432\u0441\u0451 \u0432\u044b\u0448\u0435\u0441\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0435, \u043d\u0443\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0442\u0430\u043a\u0436\u0435 \u0438\u043d\u0442\u0435\u0440\u0446\u0435\u043f\u0442\u043e\u0440 \u0434\u043b\u044f axios:<\/p>\n<p><code><strong>axios-plugin.js<\/strong><\/code><\/p>\n<pre><code>axios.interceptors.response.use(         (response) => {             return response;         },         (data) => {             let response = data.response;              \/\/ \u0435\u0441\u043b\u0438 \u043d\u0435\u0442 \u0432\u043e\u043e\u0431\u0449\u0435 \u0441\u0435\u0442\u0438             if (\"ERR_NETWORK\" === data.code) {                 let payload = {                     level: \"ERROR\",                     description: \"\u0421\u0435\u0440\u0432\u0438\u0441 \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d. \u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0441\u0435\u0442\u0438 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442 \u0438\u043b\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043f\u043e\u0437\u0434\u043d\u0435\u0435\",                     stacktrace: []                 };                  \/\/ \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0438\u043c \u0447\u0435\u0440\u0435\u0437 j-exception                 store.dispatch('setException', payload);                 return Promise.reject(response);             }              let exception = response.data;              \/\/ \u0435\u0441\u043b\u0438 \u0443\u043a\u0430\u0437\u0430\u043d\u043e \u0447\u0442\u043e \u043e\u0448\u0438\u0431\u043a\u0430 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0447\u0435\u0440\u0435\u0437 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f             if (exception.informative) {                 let payload = {                     level: exception.level,                     message: exception.message,                 }                  \/\/ \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u043c \u0447\u0435\u0440\u0435\u0437 \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0438\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f                 store.dispatch('setNotification', payload);                 return Promise.reject(response);             }              \/\/ \u0435\u0441\u043b\u0438 \u043c\u044b \u043d\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u044b             if (response.status === 401) {                  \/\/ \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0432\u0445\u043e\u0434\u0430                 router.replace({name: \"login\"});                 return Promise.reject(response);             }              \/\/ \u0435\u0441\u043b\u0438 \u0443 \u043d\u0430\u0441 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0430             if (response.status === 403) {                 let payload = {                     level: \"ERROR\",                     message: \"\u041e\u0442\u043a\u0430\u0437\u0430\u043d\u043e \u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\",                 }                  \/\/ \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u043c \u0447\u0435\u0440\u0435\u0437 \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0438\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f                 store.dispatch('setNotification', payload);                 return Promise.reject(response);             }              \/\/ \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0430 500-\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435             if (!!exception.message || !!exception.stacktrace) {                 let payload = {                     level: \"ERROR\",                     description: \"\u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u044f\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\",                     stacktrace: []                 };                 if (!!exception.level) {                     payload.level = exception.level;                 }                 if (!!exception.message) {                     payload.description = exception.message;                 }                 if (!!exception.stacktrace) {                     payload.stacktrace = exception.stacktrace;                 }                  \/\/ \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u043c \u0447\u0435\u0440\u0435\u0437 j-exception                 store.dispatch('setException', payload);             }             return Promise.reject(response);         }); <\/code><\/pre>\n<p>\u0418\u0442\u0430\u043a, \u043c\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0442\u0435\u043b\u043e \u043e\u0442\u0432\u0435\u0442\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043f\u0440\u0438 \u043e\u0448\u0438\u0431\u043a\u0430\u0445. \u0422\u0430\u043a\u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u0435\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043d\u0430 \u0444\u0440\u043e\u043d\u0442\u0435. \u0421\u043e\u0437\u0434\u0430\u043b\u0438 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u0432 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0435 &#8212; <code>ServiceException<\/code>. \u041d\u043e \u0441\u043e\u0433\u043b\u0430\u0441\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u043d\u0435 \u0432\u0441\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u044b \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0447\u0435\u0440\u0435\u0437 \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0438\u0435 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0442\u0430\u043a\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438, \u043a\u0430\u043a \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0439 \u0442\u0438\u043f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0438\u043b\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043d\u0443\u0436\u043d\u043e\u0439 \u0441\u0432\u044f\u0437\u0438 \u0432 \u0411\u0414, \u0432\u0441\u0451-\u0442\u0430\u043a\u0438 \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c, \u043a\u0430\u043a \u043e\u0448\u0438\u0431\u043a\u0443 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u0435\u0440\u0432\u0435\u0440\u0430 (\u0442.\u0435. \u0431\u0430\u0433). \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0435\u0449\u0451 \u043e\u0434\u0438\u043d \u043a\u043b\u0430\u0441\u0441 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 <code>InformationException<\/code>, \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0434\u043b\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439.<\/p>\n<p><code><strong>InformationException.java<\/strong><\/code><\/p>\n<pre><code class=\"java\"> @Getter @Setter public class InformationException extends RuntimeException {      private ErrorLevel level;     private String description;      public InformationException(String description, Throwable cause, ErrorLevel level) {         super(cause != null ? cause.getMessage() : description, cause);         this.level = level;         this.description = description;     }      public static InformationExceptionBuilder builder(String description, Throwable throwable) {         return new InformationExceptionBuilder()                 .description(description)                 .throwable(throwable);     }      public static InformationExceptionBuilder builder(String description) {         return new InformationExceptionBuilder()                 .description(description);     }      public static InformationExceptionBuilder builder(String description, ErrorLevel level) {         return new InformationExceptionBuilder()                 .description(description)                 .level(level);     }      @Setter     @Accessors(chain = true, fluent = true)     public static class InformationExceptionBuilder {          private ErrorLevel level = ErrorLevel.ERROR;         private String description;         private Throwable throwable;          InformationExceptionBuilder() {         }          public InformationException build() {             return new InformationException(description, throwable, level);         }     } } <\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d enum <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/blob\/chapter-4.2\/j-sso\/src\/main\/java\/ru\/dlabs\/sas\/example\/jsso\/type\/ErrorLevel.java\" rel=\"noopener noreferrer nofollow\"><code>ErrorLevel<\/code><\/a> \u0441 \u0443\u0440\u043e\u0432\u043d\u044f\u043c\u0438 \u043e\u0448\u0438\u0431\u043a\u0438. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d <code>RegistrationException<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442\u0441\u044f \u043e\u0442 <code>InformationException<\/code>, \u0438 \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0435\u043b\u043e \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0437\u0430 \u043c\u0430\u043b\u044b\u043c, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u0441\u0435\u0433\u043e \u043b\u0438\u0448\u044c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u044d\u0442\u0438\u0445 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u0438 \u043f\u043e\u0434\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0442\u044c \u0432 \u043e\u0442\u0432\u0435\u0442\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u0443\u044e DTO <code>ErrorResponseDto<\/code>. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 Spring \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 <code>@RestControllerAdvice<\/code> \u0438 <code>@ExceptionHandler<\/code>. \u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u043f\u043e \u043d\u0438\u043c \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 <a href=\"https:\/\/docs.spring.io\/spring-framework\/docs\/current\/javadoc-api\/org\/springframework\/web\/bind\/annotation\/RestControllerAdvice.html\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<p>\u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043b\u0430\u0441\u0441 <code>GlobalExceptionHandler<\/code>.<\/p>\n<p><code><strong>GlobalExceptionHandler.java<\/strong><\/code><\/p>\n<pre><code class=\"java\"> @Slf4j @RestControllerAdvice public class GlobalExceptionHandler {      private final MessageService messageService;     private final ErrorResponseBuilder errorResponseBuilder;     private final boolean enableStacktrace;      \/**      * \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043a\u043b\u0430\u0441\u0441\u0430      *      * @param includeStacktrace \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0438\u043b\u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 stacktrace \u0432 \u043e\u0442\u0432\u0435\u0442\u0435.      *                          always - \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c, never \u0432\u044b\u043a\u043b\u044e\u0447\u0438\u0442\u044c.      * @param messageService    \u0431\u0438\u043d MessageService      *\/     public GlobalExceptionHandler(             @Value(\"${server.error.include-stacktrace}\") String includeStacktrace,             @Autowired MessageService messageService     ) {         this.enableStacktrace = \"always\".equals(includeStacktrace);         this.messageService = messageService;         this.errorResponseBuilder = new ErrorResponseBuilder(messageService);     }      @ExceptionHandler(InformationException.class)     public ResponseEntity&lt;ErrorResponseDto> resolveInformationException(             HttpServletRequest request,             InformationException exception     ) {         logRequestException(request, exception);          String description;         if (!StringUtils.hasLength(exception.getDescription())) {             description = messageService.getMessage(\"common.exception\", exception.getMessage());         } else {             description = exception.getDescription();             if (description.startsWith(\"$\")) {                 description = messageService.getMessage(description.substring(1), exception.getMessage());             }         }          return new ResponseEntity&lt;>(                 ErrorResponseDto.builder()                         .informative(true)                         .level(exception.getLevel())                         .message(description)                         .stacktrace(enableStacktrace ? exception.getStackTrace() : null)                         .build(),                 HttpStatus.INTERNAL_SERVER_ERROR         );     }      @ExceptionHandler(ServiceException.class)     public ResponseEntity&lt;ErrorResponseDto> resolveServiceException(             HttpServletRequest request,             ServiceException exception     ) {         logRequestException(request, exception);          String description;         if (!StringUtils.hasLength(exception.getDescription())) {             description = messageService.getMessage(\"common.exception\", exception.getMessage());         } else {             description = exception.getDescription();         }          return new ResponseEntity&lt;>(                 ErrorResponseDto.builder()                         .informative(false)                         .message(description)                         .stacktrace(enableStacktrace ? exception.getStackTrace() : null)                         .build(),                 HttpStatus.INTERNAL_SERVER_ERROR         );     }      @ExceptionHandler({NoResultException.class, EmptyResultDataAccessException.class})     public ResponseEntity&lt;ErrorResponseDto> resolveNoResult(HttpServletRequest request, Exception exception) {         logRequestException(request, exception);         return errorResponseBuilder.makeResponse(\"entity.empty.exception\", exception);     }      @ExceptionHandler({EntityNotFoundException.class})     public ResponseEntity&lt;ErrorResponseDto> resolveEntityNotFound(HttpServletRequest request, Exception exception) {         logRequestException(request, exception);         return errorResponseBuilder.makeResponse(\"entity.not.found.exception\", exception);     }      @ExceptionHandler(AccessDeniedException.class)     public ResponseEntity&lt;ErrorResponseDto> resolveAccessDeniedException(             HttpServletRequest request,             Exception exception     ) {         logRequestException(request, exception);         return errorResponseBuilder.makeResponse(\"access.denied.exception\", HttpStatus.FORBIDDEN, exception, true);     }      @ExceptionHandler(Exception.class)     protected ResponseEntity&lt;ErrorResponseDto> resolveException(HttpServletRequest request, Exception exception) {         logRequestException(request, exception);         return errorResponseBuilder.makeResponse(\"common.exception\", exception);     }      private void logRequestException(HttpServletRequest request, Exception exception) {         log.debug(\"Unexpected exception processing request: \" + request.getRequestURI());         log.error(\"Exception: \", exception);     } } <\/code><\/pre>\n<p>\u0412 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 \u043f\u043e\u043c\u0438\u043c\u043e \u043e\u0431\u0440\u0430\u0442\u043a\u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 <code>InformationException<\/code> \u0438 <code>ServiceException<\/code>, \u0442\u0430\u043a\u0436\u0435 \u0435\u0441\u0442\u044c \u0440\u044f\u0434 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439. \u0418 \u0441\u0430\u043c\u043e\u0435 \u0432\u0430\u0436\u043d\u043e\u0435, \u0447\u0442\u043e \u0435\u0441\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 <code>Exception.class<\/code>. \u041e\u043d\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0442\u043b\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u043b\u044e\u0431\u043e\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043d\u0435 \u043e\u0442\u043b\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432\u044b\u0448\u0435. \u0412 \u0444\u0430\u0439\u043b <code>messages_ru_RU.properties<\/code> \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 <code>InformationException<\/code> \u0438 <code>ServiceException<\/code>. \u0415\u0441\u043b\u0438 \u0432 \u043f\u043e\u043b\u0435 <code>description<\/code> \u0443\u043a\u0430\u0437\u0430\u043d\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0435\u0435\u0441\u044f \u0441\u043e \u0437\u043d\u0430\u043a\u0430 &#8216;$&#8217;, \u0442\u043e \u043c\u044b \u0441\u0447\u0438\u0442\u0430\u0435\u043c,\u0447\u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0437\u043d\u0430\u043a\u0430 \u0438\u0434\u0451\u0442 \u043a\u043e\u0434 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438 \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0435\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c <code>messageService<\/code>. \u041d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043e, \u043a\u0430\u043a \u044d\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u0445:<\/p>\n<p><code><strong>DefaultUserService.java<\/strong><\/code><\/p>\n<pre><code class=\"java\"> @Service @RequiredArgsConstructor public class DefaultUserService implements UserService {      \/\/ .....      private void validateRegistrationDto(RegistrationDto dto) {         if (dto.getEmail() == null) {             throw new RegistrationException(\"$validation.email\");         }         if (dto.getFirstName() == null) {             throw new RegistrationException(\"$validation.firstname\");         }         if (dto.getSecondName() == null) {             throw new RegistrationException(\"$validation.lastname\");         }         if (dto.getPassword() == null) {             throw new RegistrationException(\"$validation.password\");         }          UserEntity user = this.userRepository.findByEmail(dto.getEmail());         if (user != null) {             throw new RegistrationException(\"$account.already.exist\");         }     }      \/\/ ..... }  <\/code><\/pre>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043c\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438. \u041f\u0440\u0438\u043c\u0435\u0440 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c 500-\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043d\u0438\u0436\u0435:<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/641\/393\/331\/6413933318642c8663dbf3eb5db4ed73.png\" alt=\"\u041e\u0442\u0432\u0435\u0442 \u043f\u0440\u0438 \u043e\u0448\u0438\u0431\u043a\u0435\" title=\"\u041e\u0442\u0432\u0435\u0442 \u043f\u0440\u0438 \u043e\u0448\u0438\u0431\u043a\u0435\" width=\"1200\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/641\/393\/331\/6413933318642c8663dbf3eb5db4ed73.png\"\/><\/p>\n<div><figcaption>\u041e\u0442\u0432\u0435\u0442 \u043f\u0440\u0438 \u043e\u0448\u0438\u0431\u043a\u0435<\/figcaption><\/div>\n<\/figure>\n<h4>\u0415\u0449\u0451 \u043e\u0434\u043d\u043e \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u043e\u0435 \u043e\u0442\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435<\/h4>\n<p>\u041c\u043d\u0435 \u043f\u043e\u0440\u044f\u0434\u043a\u043e\u043c \u043d\u0430\u0434\u043e\u0435\u043b\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043c\u0435\u043d\u044f\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 <code>application.yml<\/code>. \u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u044d\u0442\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u0441\u0442\u0435\u043d\u0434\u0430\u0445, \u043d\u0430\u043c \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043f\u043e\u0434\u043c\u0435\u043d\u044b \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439. \u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f spring profiles (\u0432 \u043f\u0440\u043e\u0448\u043b\u044b\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u043c\u044b \u044d\u0442\u043e \u0443\u0436\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b\u0438, \u043d\u043e \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0442\u0430\u043a\u0436\u0435 \u0435\u0449\u0451 \u0440\u0430\u0437 \u044d\u0442\u043e \u043f\u0440\u043e\u0447\u0435\u0441\u0442\u044c <a href=\"https:\/\/docs.spring.io\/spring-boot\/docs\/1.2.0.M1\/reference\/html\/boot-features-profiles.html#boot-features-profiles\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a> \u0438 <a href=\"https:\/\/docs.spring.io\/spring-boot\/docs\/1.2.0.M1\/reference\/html\/howto-properties-and-configuration.html#howto-change-configuration-depending-on-the-environment\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>). \u0418\u043b\u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0442\u044c \u043d\u0443\u0436\u043d\u044b\u0439 <code>application.yml<\/code> \u0444\u0430\u0439\u043b \u043f\u0440\u0438 \u0441\u0442\u0430\u0440\u0442\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (\u043e\u0431 \u044d\u0442\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/docs.spring.io\/spring-boot\/docs\/1.5.6.RELEASE\/reference\/html\/boot-features-external-config.html#boot-features-external-config-application-property-files\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>).<\/p>\n<p>\u041d\u043e \u044f \u0445\u043e\u0447\u0443 \u0432\u0430\u043c \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0435\u0449\u0451 \u043e\u0434\u0438\u043d \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431. \u041e\u043d \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 Environment Variables. \u042d\u0442\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0443\u0434\u043e\u0431\u043d\u043e \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0434\u043b\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u043b\u043e\u0433\u0438\u043d\u043e\u0432\/\u043f\u0430\u0440\u043e\u043b\u0435\u0439, IP \u0430\u0434\u0440\u0435\u0441\u043e\u0432 \u0438 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0434\u043e\u043b\u0436\u0435\u043d \u0437\u043d\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440 \u0441\u0435\u0440\u0432\u0438\u0441\u0430. \u0410 \u0442\u0430\u043a\u0436\u0435 \u044d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0431\u044b\u0441\u0442\u0440\u043e \u043c\u0435\u043d\u044f\u0442\u044c \u0442\u0430\u043a\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043d\u0435 \u043f\u0440\u0438\u0431\u0435\u0433\u0430\u044f \u043a \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<p>\u0421\u043c\u044b\u0441\u043b \u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043d\u0430 placeholder-\u044b \u0441 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0441\u0440\u0435\u0434\u044b. \u041d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043e\u0431\u043d\u043e\u0432\u043b\u0451\u043d\u043d\u044b\u0439 <code>application.yml<\/code>:<\/p>\n<pre><code class=\"yaml\"># .......  security:     oauth2:         authorizationserver:             issuer-url: http:\/\/localhost:7777             introspection-endpoint: \/oauth2\/token-info             authentication-success-url: http:\/\/localhost:7777\/client\/home             custom-handler-header-name: J-Sso-Next-Location             authorization-ttl: 720000             authorization-consent-ttl: 720000         client:             registration:                 github:                     clientId: ${JSSO_GITHUB_CLIENT_ID}                     clientSecret: ${JSSO_GITHUB_CLIENT_SECRET}                  google:                     clientId: ${JSSO_GOOGLE_CLIENT_ID}                     clientSecret: ${JSSO_GOOGLE_CLIENT_SECRET}                     scope:                         - email                         - profile                  yandex:                     provider: yandex                     clientId: ${JSSO_YANDEX_CLIENT_ID}                     clientSecret: ${JSSO_YANDEX_CLIENT_SECRET}                     redirect-uri: http:\/\/localhost:7777\/login\/oauth2\/code\/yandex                     authorizationGrantType: authorization_code                     clientName: Yandex              provider:                 yandex:                     authorization-uri: https:\/\/oauth.yandex.ru\/authorize                     token-uri: https:\/\/oauth.yandex.ru\/token                     user-name-attribute: default_email                     userInfoUri: https:\/\/login.yandex.ru\/info  # ....... <\/code><\/pre>\n<p>\u041a\u0430\u043a \u0432\u044b \u0432\u0438\u0434\u0438\u0442\u0435, \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0434\u043b\u044f <code>clientId<\/code> \u0438 <code>clientSecret<\/code> \u0431\u044b\u043b\u0438 \u0437\u0430\u043c\u0435\u043d\u0435\u043d\u044b \u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0438\u043c\u0435\u043d\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0441\u0440\u0435\u0434\u044b. \u0422\u0430\u043a\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c <a href=\"http:\/\/README.md\" rel=\"noopener noreferrer nofollow\">README.md<\/a> \u0444\u0430\u0439\u043b\u0430 \u0432 \u043a\u043e\u0440\u043d\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430. \u0414\u0430\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b \u0434\u043b\u044f <code>j-sso<\/code> \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/blob\/chapter-4.2\/j-sso\/README.md\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 Environment Variables. \u0415\u0441\u043b\u0438 \u0432\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 Intellij IDEA, \u0442\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0438\u0445 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0443\u044e \u0441\u0435\u043a\u0446\u0438\u044e.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/ba7\/dc3\/773\/ba7dc377302ddd965b47ede5a8ee540f.png\" alt=\"\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0432 IDEA\" title=\"\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0432 IDEA\" width=\"1200\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/ba7\/dc3\/773\/ba7dc377302ddd965b47ede5a8ee540f.png\"\/><\/p>\n<div><figcaption>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0432 IDEA<\/figcaption><\/div>\n<\/figure>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/0b2\/187\/d1a\/0b2187d1a635dc969f32358207b8a441.png\" alt=\"Environment Variables \u0432 IDEA\" title=\"Environment Variables \u0432 IDEA\" width=\"1200\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/0b2\/187\/d1a\/0b2187d1a635dc969f32358207b8a441.png\"\/><\/p>\n<div><figcaption>Environment Variables \u0432 IDEA<\/figcaption><\/div>\n<\/figure>\n<h4>\u0421\u0442\u0440\u043e\u0438\u043c backend<\/h4>\n<p>\u0418\u0442\u0430\u043a, \u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u043c\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b\u0438 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u044e\u0449\u0438\u0435 \u043e\u0431\u0449\u0435\u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u044b, \u043d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441\u0430\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 <code>RegistrationController<\/code>, \u0432 \u043d\u0451\u043c \u043e\u0431\u044a\u044f\u0432\u0438\u043c \u0434\u0432\u0430 endpoint-\u0430.<\/p>\n<ol>\n<li>\n<p><code>\/registration\/init<\/code> &#8212; \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438. \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0432\u0441\u0435\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f OTP, \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u043f\u043e email.<\/p>\n<\/li>\n<li>\n<p><code>\/registration\/confirm<\/code> &#8212; \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438. \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 OTP, \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430, \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0411\u0414 \u043e \u043d\u043e\u0432\u043e\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435.<\/p>\n<\/li>\n<\/ol>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0441\u0435\u0440\u0432\u0438\u0441 <code>RegistrationService<\/code> \u0438 \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e <code>DefaultRegistrationService<\/code>. \u0412 \u0441\u0430\u043c\u043e\u043c \u0441\u0435\u0440\u0432\u0438\u0441\u0435 \u043b\u043e\u0433\u0438\u043a\u0430 \u0431\u0430\u043d\u0430\u043b\u044c\u043d\u0430 \u0438 \u0432\u044b \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u0438 \u0431\u0435\u0437 \u043e\u0441\u043e\u0431\u043e\u0433\u043e \u0442\u0440\u0443\u0434\u0430 \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0435\u0451 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c. \u0418\u043d\u0442\u0435\u0440\u0435\u0441 \u0442\u0443\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b <code>**Store<\/code>.<\/p>\n<p><code>OTPStore<\/code> &#8212; \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u0443\u0435\u0442 \u0432 \u0441\u0435\u0431\u0435 \u0432\u0441\u044e \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 OTP. \u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f, \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f, \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0438 \u0442.\u0434.<\/p>\n<p><code><strong>OTPStore.java<\/strong><\/code><\/p>\n<pre><code class=\"java\">public interface OTPStore {      \/**      * \u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f OTP      *\/     GenerationResult generate(HttpServletResponse response);      \/**      * \u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f OTP      *\/     boolean validate(String otp, HttpServletRequest request);      \/**      * \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 session Id \u0438\u0437 HttpServletRequest      *\/     String getSessionId(HttpServletRequest request);      \/**      * \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u0443\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e      *\/     Config getConfig();      \/**      * \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 OTP. \u0421\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u0443\u044e ID \u0441\u0435\u0441\u0441\u0438\u0438 \u0438 \u0441\u0430\u043c OTP.      *\/     record GenerationResult(String sessionId, String otp) {     }      \/**      * \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0441\u0442\u043e\u0440\u0430      *      * @param cookieName   \u043d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 cookie      * @param cookieDomain \u0434\u043e\u043c\u0435\u043d cookie      * @param cookieMaxAge \u0432\u0440\u0435\u043c\u044f \u0436\u0438\u0437\u043d\u0438 \u043a\u0443\u043a\u0438 cookie \u0438 \u0441\u0430\u043c\u043e\u0433\u043e OTP      *\/     record Config(String cookieName, String cookieDomain, int cookieMaxAge) {     } } <\/code><\/pre>\n<p>\u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 &#8212; <code>RedisOTPStore<\/code>. \u0421\u0430\u043c \u0431\u0438\u043d <code>OTPStore<\/code> \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 <code>BeanConfig<\/code>. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e. \u0412 \u043d\u0435\u0439 \u043c\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 Cookie. \u041f\u0440\u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 OTP \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0441\u0435\u0441\u0441\u0438\u0438, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0438\u0442 \u044d\u0442\u043e\u0442 OTP, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0442\u043e\u043c \u043c\u044b \u043c\u043e\u0433\u043b\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0432\u0430\u043b\u0438\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 <code>generate()<\/code> \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <code>HttpServletResponse response<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f Cookie \u0441 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c. \u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0438\u0437 \u0441\u0435\u0431\u044f \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0431\u0430\u043d\u0430\u043b\u044c\u043d\u044b\u0439 UUID. \u041d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043c\u0435\u0442\u043e\u0434\u0430 <code>generate()<\/code> \u0441 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u043c\u0438:<\/p>\n<p><code><strong>RedisOTPStore.java<\/strong><\/code><\/p>\n<pre><code class=\"java\"> @Slf4j public class RedisOTPStore implements OTPStore {     \/\/ ....      @Override     public GenerationResult generate(HttpServletResponse response) {          \/\/ \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c         String otp = RandomStringUtils.randomNumeric(6);          \/\/ \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0441\u0435\u0441\u0441\u0438\u0438         String sessionId = this.generateSessionId();         log.info(\"Generate OTP = \" + otp + \". Generate sessionId = \" + sessionId);          \/\/ \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043f\u0430\u0440\u043e\u043b\u044c \u0432 Redis         store.set(SESSION_ID_TO_OTP + sessionId, otp, config.cookieMaxAge(), TimeUnit.SECONDS);          \/\/ \u0441\u043e\u0437\u0434\u0430\u0451\u043c Cookie         Cookie cookie = new Cookie(config.cookieName(), sessionId);         cookie.setMaxAge(config.cookieMaxAge());         cookie.setDomain(config.cookieDomain());         cookie.setHttpOnly(true);          \/\/ \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0435 Cookie \u0432 Servlet Response         response.addCookie(cookie);          log.info(\"Add cookie to response = \" + cookie);         return new GenerationResult(sessionId, otp);     }      \/\/ .... } <\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442 email \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 OTP \u043a\u043e\u0434\u043e\u043c \u0438 \u0432\u0432\u0435\u0434\u0451\u0442 \u0435\u0433\u043e \u043d\u0430 \u0444\u043e\u0440\u043c\u0435 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438, \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 <code>validate()<\/code>. \u041f\u0435\u0440\u0432\u044b\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f OTP \u0432\u0432\u0435\u0434\u0451\u043d\u043d\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c, \u0430 \u0432\u0442\u043e\u0440\u044b\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c <code>HttpServletRequest request<\/code>, \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043d\u0430\u0448\u0438 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 Cookie. \u0414\u0430\u043b\u0435\u0435 \u0432\u043e\u0437\u044c\u043c\u0451\u043c \u0438\u0437 \u043d\u0438\u0445 \u043d\u0430\u0448 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0441\u0442\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u043e \u043f\u043e\u0447\u0442\u0435 OTP \u0438 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<p>\u0412\u0442\u043e\u0440\u044b\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <code>RegistrationStore<\/code>. \u041e\u043d \u0432 \u0441\u0435\u0431\u0435 \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u0443\u0435\u0442 \u0432\u0441\u044e \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u0435\u0449\u0451 \u043d\u0435 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043d\u043d\u044b\u043c\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<p><code><strong>RegistrationStore.java<\/strong><\/code><\/p>\n<pre><code class=\"java\">public interface RegistrationStore {      \/**      * \u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435      *      * @param dto       \u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c      * @param sessionId \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0441\u0435\u0441\u0441\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f      *\/     void save(RegistrationDto dto, String sessionId) throws Exception;      \/**      * \u0412\u0437\u044f\u0442\u044c \u0438 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0438\u0437 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e sessionId      *      * @param sessionId \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0441\u0435\u0441\u0441\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f      *      * @return \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u043b\u0438 null      *\/     RegistrationDto take(String sessionId) throws Exception; } <\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434\u044b \u0443 \u043d\u0435\u0433\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u0438 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0435. \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u044d\u0442\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043b\u0430\u0441\u0441 <code>RedisRegistrationStore<\/code>. \u0415\u0433\u043e \u0431\u0438\u043d \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 <code>BeanConfig<\/code>. \u041d\u0430\u0432\u0435\u0440\u043d\u043e \u0441\u0442\u043e\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 <code>sessionId<\/code>. \u042d\u0442\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0441\u0435\u0441c\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442\u0435\u043d \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e\u043c\u0443 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0443 \u0432 <code>OTPStore<\/code>. \u0414\u0440\u0443\u0433\u0438\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438 \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0438\u0437 <code>OTPStore<\/code>. \u041d\u0443 \u044d\u0442\u043e \u0438 \u043b\u043e\u0433\u0438\u0447\u043d\u043e, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c OTP \u0438 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435. \u041f\u0440\u043e\u0449\u0435 \u0432\u0441\u0435\u0433\u043e \u0432\u0441\u0451 \u044d\u0442\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043f\u043e\u0434 \u043e\u0434\u043d\u0438\u043c \u043a\u043b\u044e\u0447\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0442\u043e\u043c \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0432\u0441\u0451 \u044d\u0442\u043e \u043b\u0435\u0433\u043a\u043e \u0438 \u0431\u044b\u0441\u0442\u0440\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u044c. \u0410 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043a\u043b\u044e\u0447\u0430 \u043c\u0435\u0436\u0434\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438 \u0434\u043b\u044f <code>RegistrationStore<\/code> \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0437\u0430 \u0441\u0447\u0451\u0442 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 <code>OTPStore<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u0432\u044b\u0448\u0435.<\/p>\n<p>\u0421\u043a\u0430\u0436\u0435\u043c \u0442\u0430\u043a\u0436\u0435 \u043f\u0430\u0440\u0443 \u0441\u043b\u043e\u0432 \u043e\u0431 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043f\u043e email. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432\u0437\u0433\u043b\u044f\u043d\u0435\u043c \u043d\u0430 \u043c\u0435\u0442\u043e\u0434 <code>register()<\/code> \u0438\u0437 \u043a\u043b\u0430\u0441\u0441\u0430 <code>DefaultRegistrationService<\/code>.<\/p>\n<p><code><strong>DefaultRegistrationService.java<\/strong><\/code><\/p>\n<pre><code class=\"java\"> @Service @RequiredArgsConstructor public class DefaultRegistrationService implements RegistrationService {      \/\/ .....      @Override     public void register(RegistrationDto registrationDto, HttpServletResponse response) {         \/\/ \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0447\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441 \u0442\u0430\u043a\u0438\u043c email \u0435\u0449\u0451 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442         if (userService.existByEmail(registrationDto.getEmail())) {             throw InformationException.builder(\"$account.already.exist\").build();         }          \/\/ \u0421\u043e\u0437\u0434\u0430\u0451\u043c OTP         OTPStore.GenerationResult generationResult = otpStore.generate(response);          \/\/ \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435         try {             registrationStore.save(registrationDto, generationResult.sessionId());         } catch (Exception e) {             throw InformationException.builder(\"$happened.unexpected.error\").build();         }          \/\/ \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c OTP \u043f\u043e email         emailSender.sendHtmlTemplated(                 registrationDto.getEmail(),                 messageService.getMessage(\"email.subject.confirm.registration\"),                 \"classpath:mail-templates\/registration-confirmed.html\",                 ImmutableMap.&lt;String, Object>builder()                         .put(\"firstName\", registrationDto.getFirstName())                         .put(\"otp\", generationResult.otp())                         .build()         );     }      \/\/ ..... }  <\/code><\/pre>\n<p>\u0421\u0430\u043c\u043e email \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043d\u0435 \u0441\u043a\u0443\u0447\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442, \u0430 \u043a\u0440\u0430\u0441\u0438\u0432\u0443\u044e (\u043d\u0430 \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u044d\u0442\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e ?) HTML \u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0430 \u0432 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u043e \u043f\u0443\u0442\u0438 <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/blob\/chapter-4.2\/j-sso\/src\/main\/resources\/mail-templates\/registration-confirmed.html\" rel=\"noopener noreferrer nofollow\"><code>resources\/mail-templates\/registration-confirmed.html<\/code><\/a>. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <code>d-email<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u0442\u0430\u043a \u043a\u0430\u043a \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0435\u0431\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0448\u0430\u0431\u043b\u043e\u043d\u0438\u0437\u0430\u0442\u043e\u0440 <code>Apache Velocity Template<\/code>. \u041d\u043e \u0431\u0443\u0434\u044c\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u044b, \u0432\u0435\u0440\u0441\u0442\u043a\u0430 email \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u044d\u0442\u043e \u043d\u0435 \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435, \u0447\u0442\u043e \u0432\u0435\u0440\u0441\u0442\u043a\u0430 \u0444\u043e\u0440\u043c \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435. \u041f\u0440\u0438 \u0432\u0451\u0440\u0441\u0442\u043a\u0435 email \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u043a\u0430\u043a \u043f\u043e \u0441\u0442\u0438\u043b\u044f\u043c, \u0442\u0430\u043a \u0438 \u043f\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0443. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u043c \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u043c \u043f\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e HTML \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043a\u043e\u0438\u0445 \u043d\u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0440\u0430\u0445 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u043e\u0433\u0440\u043e\u043c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u043d\u0430 \u044d\u0442\u043e\u043c \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043e\u0431\u0437\u043e\u0440 \u0432\u0441\u0435\u0433\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043c\u044b \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u043c. \u041d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u043f\u0440\u0438\u043c\u0435\u0440 \u0440\u0430\u0431\u043e\u0442\u044b \u0432\u0441\u0435\u0433\u043e \u0432\u044b\u0448\u0435\u043e\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0433\u043e.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/1e9\/27e\/e26\/1e927ee26c09ba236bc5d90e356c7d35.gif\" alt=\"\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438\" title=\"\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438\" width=\"1200\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/1e9\/27e\/e26\/1e927ee26c09ba236bc5d90e356c7d35.gif\"\/><\/p>\n<div><figcaption>\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438<\/figcaption><\/div>\n<\/figure>\n<blockquote>\n<p>\u0418\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/tree\/chapter-4.2\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<\/blockquote>\n<h3>\u0420\u0430\u0437\u0434\u0435\u043b 4.3: \u0424\u0443\u043d\u043a\u0446\u0438\u044f &#171;\u0437\u0430\u0431\u044b\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c&#187;<\/h3>\n<p>\u041b\u044e\u0431\u043e\u0439 \u0447\u0435\u043b\u043e\u0432\u0435\u043a \u0445\u043e\u0442\u044f \u0431\u044b \u0440\u0430\u0437 \u0434\u0430 \u0437\u0430\u0431\u044b\u0432\u0430\u043b \u043f\u0430\u0440\u043e\u043b\u044c \u043e\u0442 \u0442\u043e\u0433\u043e \u0438\u043b\u0438 \u0438\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0432 \u0441\u0432\u043e\u0435\u0439 \u0436\u0438\u0437\u043d\u0438. \u0415\u0449\u0451 \u0431\u044b, \u0441\u0435\u0439\u0447\u0430\u0441 \u044d\u0442\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u043f\u043e\u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f, \u043a\u0430\u043a \u0433\u0440\u0438\u0431\u044b \u043f\u043e\u0441\u043b\u0435 \u0434\u043e\u0436\u0434\u044f. \u0414\u0430 \u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u043f\u0430\u0440\u043e\u043b\u044f\u043c \u0432\u0441\u0451 \u0432\u044b\u0448\u0435 \u0438 \u0432\u044b\u0448\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u043d\u0435 \u043c\u043e\u0433 \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0432 \u0431\u0435\u0437\u0432\u044b\u0445\u043e\u0434\u043d\u043e\u043c \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0438 \u043d\u0435 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0443\u044e \u043a\u043d\u043e\u043f\u043e\u0447\u043a\u0443 &#8212; &#171;\u0417\u0430\u0431\u044b\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c&#187;. \u041a \u0442\u043e\u043c\u0443 \u0436\u0435 \u0434\u0430\u043d\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043e\u0447\u0435\u043d\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430 \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0434\u0443\u043c\u0430\u0435\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0435\u0451 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c.<\/p>\n<p>\u041f\u0435\u0440\u0432\u043e\u0435, \u0447\u0442\u043e \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u0443\u043c: \u043f\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044e \u043a\u043d\u043e\u043f\u043a\u0438 &#171;\u0417\u0430\u0431\u044b\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c&#187; \u043d\u0430 \u0444\u043e\u0440\u043c\u0435 \u0432\u0445\u043e\u0434\u0430, \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u043f\u0430\u0434\u0430\u0442\u044c \u043d\u0430 \u0444\u043e\u0440\u043c\u0443 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f email \u0430\u0434\u0440\u0435\u0441\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0441\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0430\u0440\u043e\u043b\u044c. \u041d\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0441\u0440\u0430\u0437\u0443 \u0434\u0430\u0434\u0438\u043c \u0432\u0432\u0435\u0441\u0442\u0438 \u043f\u0430\u0440\u043e\u043b\u044c, \u0442\u043e \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e, \u0442\u0430\u043a \u043a\u0430\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c-\u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u0441\u043c\u043e\u0436\u0435\u0442 \u043c\u0435\u043d\u044f\u0442\u044c \u043f\u0430\u0440\u043e\u043b\u044c \u043a\u043e\u043c\u0443 \u0443\u0433\u043e\u0434\u043d\u043e, \u0437\u043d\u0430\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d email \u0430\u0434\u0440\u0435\u0441. \u0422\u0435\u043c \u0441\u0430\u043c\u044b\u043c \u0432\u0437\u043b\u0430\u043c\u044b\u0432\u0430\u044f \u0443\u0447\u0435\u0442\u043a\u0438. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u043e\u0435 \u0438 \u0432 \u0442\u043e \u0436\u0435 \u0432\u0440\u0435\u043c\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0435 \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u041f\u0440\u043e\u0441\u0442\u043e \u043c\u0435\u043d\u044f\u0442\u044c \u043f\u0430\u0440\u043e\u043b\u044c \u0442\u043e\u0447\u043d\u043e \u0442\u0430\u043a \u0436\u0435, \u043a\u0430\u043a \u0438 \u043f\u0440\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0447\u0435\u0440\u0435\u0437 OTP \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u043c\u043e\u0436\u043d\u043e, \u043d\u043e \u0442\u0430\u043a\u043e\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0441\u043c\u0435\u043d\u044b \u043f\u0430\u0440\u043e\u043b\u044f \u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0441\u044f \u043a\u0430\u043a-\u0442\u043e \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e. \u0422\u0430\u043a \u043a\u0430\u043a \u0432 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0435 \u043f\u0440\u0438 \u0434\u043e\u043b\u0436\u043d\u043e\u043c \u0432\u043b\u0430\u0434\u0435\u043d\u0438\u0438 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0438 \u043f\u0430\u0440\u043e\u0439 \u0432\u0438\u0434\u0435\u043e\u043a\u0430\u0440\u0442 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e \u043f\u043e\u0434\u043e\u0431\u0440\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443, \u0434\u0443\u043c\u0430\u044e, \u0447\u0443\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c:<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/a44\/0c9\/7f4\/a440c97f494c1b292e24f7d253507ac2.svg\" alt=\"UML \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0441\u0431\u0440\u043e\u0441\u0430 \u043f\u0430\u0440\u043e\u043b\u044f\" title=\"UML \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0441\u0431\u0440\u043e\u0441\u0430 \u043f\u0430\u0440\u043e\u043b\u044f\" width=\"1200\"\/><\/p>\n<div><figcaption>UML \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0441\u0431\u0440\u043e\u0441\u0430 \u043f\u0430\u0440\u043e\u043b\u044f<\/figcaption><\/div>\n<\/figure>\n<ol>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u0432\u043e\u0434\u0438\u0442 email \u0430\u0434\u0440\u0435\u0441 \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c \u043f\u0430\u0440\u043e\u043b\u044c<\/p>\n<\/li>\n<li>\n<p>\u0421\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e email \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 OTP \u043f\u0430\u0440\u043e\u043b\u0435\u043c<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0430 \u0444\u043e\u0440\u043c\u0435 \u0432\u0432\u043e\u0434\u0438\u0442 OTP \u043f\u0430\u0440\u043e\u043b\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043f\u043e \u043f\u043e\u0447\u0442\u0435. \u0422\u0435\u043c \u0441\u0430\u043c\u044b\u043c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u044f, \u0447\u0442\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0439 email \u0430\u0434\u0440\u0435\u0441 \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0438\u0442 \u0435\u043c\u0443.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f OTP, \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043e\u0442\u0441\u044b\u043b\u0430\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0435\u0449\u0451 \u043e\u0434\u043d\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441\u043e \u0441\u0441\u044b\u043b\u043a\u043e\u0439 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0441\u043c\u0435\u043d\u044b \u043f\u0430\u0440\u043e\u043b\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0441\u044b\u043b\u043a\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043f\u0443\u0442\u044c \u0434\u043e \u043d\u0443\u0436\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043d\u0435\u043a\u0438\u0439 \u0441\u043b\u043e\u0436\u043d\u044b\u0439, \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u044e\u0449\u0438\u0439 \u043c\u0435\u043d\u044f\u0442\u044c \u043f\u0430\u0440\u043e\u043b\u044c \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u043d\u0430 \u043f\u0435\u0440\u0432\u043e\u043c \u044d\u0442\u0430\u043f\u0435.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u0432\u043e\u0434\u0438\u0442 \u043d\u043e\u0432\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0435\u0433\u043e.<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u043e\u0434\u0445\u043e\u0434 \u0441\u043e \u0441\u0441\u044b\u043b\u043a\u043e\u0439 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0441\u043c\u0435\u043d\u044b \u043f\u0430\u0440\u043e\u043b\u044f \u043f\u043e \u0441\u0432\u043e\u0435\u0439 \u0441\u0443\u0442\u0438 \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u0445\u043e\u0436 \u043d\u0430 \u043f\u043e\u0434\u0445\u043e\u0434 \u0441 \u043f\u0440\u043e\u0441\u0442\u044b\u043c OTP \u043a\u043e\u0434\u043e\u043c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f \u0441\u043c\u0435\u043d\u044b \u043f\u0430\u0440\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u043b\u0438. \u041d\u043e \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u043d\u0435\u0433\u043e, \u0437\u0434\u0435\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0434\u043b\u0438\u043d\u043d\u044b\u0439 \u0438 \u0441\u043b\u043e\u0436\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0442\u0430\u043a\u0436\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u041f\u043e\u0434\u0431\u043e\u0440 \u0442\u0430\u043a\u043e\u0433\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0437\u0430\u0439\u043c\u0451\u0442 \u0443 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0430 \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a\u043e\u0432 \u0431\u043e\u043b\u044c\u0448\u0435\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0435\u0436\u0435\u043b\u0438 \u0432\u0440\u0435\u043c\u044f \u0435\u0433\u043e \u0436\u0438\u0437\u043d\u0438. \u041f\u043e\u043c\u0438\u043c\u043e \u044d\u0442\u043e\u0433\u043e, \u043c\u044b \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u043e\u0436\u0435\u043c \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0431\u0435\u0437 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0434\u043b\u044f \u043d\u0430\u0448\u0438\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u0432\u044b\u0448\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0441\u0447\u0438\u0442\u0430\u044e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043d\u0430\u0434\u0451\u0436\u043d\u044b\u043c \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e <code>j-sso<\/code>. \u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u043c\u043e\u0436\u043d\u043e \u0434\u0430\u0436\u0435 \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u0431\u0435\u0437 \u0448\u0430\u0433\u0430 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f email \u0430\u0434\u0440\u0435\u0441\u0430 \u0447\u0435\u0440\u0435\u0437 OTP. \u041d\u043e \u0434\u0443\u043c\u0430\u044e \u0434\u0430\u043d\u043d\u044b\u0439 \u0448\u0430\u0433 \u043d\u0430\u0441 \u043e\u0433\u0440\u0430\u0434\u0438\u0442 \u043e\u0442 \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0445 \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a\u043e\u0432. \u0412 \u043b\u044e\u0431\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u043e\u0436\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u0443\u0431\u0440\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u0448\u0430\u0433 \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438. \u041d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u043c\u0430\u043a\u0435\u0442\u044b \u0444\u043e\u0440\u043c.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/9f0\/af8\/360\/9f0af83607fb4a83b71dfaf903e10361.png\" alt=\"\u041c\u0430\u043a\u0435\u0442\u044b \u0444\u043e\u0440\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 '\u0417\u0430\u0431\u044b\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c'\" title=\"\u041c\u0430\u043a\u0435\u0442\u044b \u0444\u043e\u0440\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 '\u0417\u0430\u0431\u044b\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c'\" width=\"1200\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/9f0\/af8\/360\/9f0af83607fb4a83b71dfaf903e10361.png\"\/><\/p>\n<div><figcaption>\u041c\u0430\u043a\u0435\u0442\u044b \u0444\u043e\u0440\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 &#8216;\u0417\u0430\u0431\u044b\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c&#8217;<\/figcaption><\/div>\n<\/figure>\n<ol>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0430 \u043b\u043e\u0433\u0438\u043d\u0430<\/p>\n<\/li>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0430 \u0432\u0432\u043e\u0434\u0430 e-mail \u0430\u0434\u0440\u0435\u0441\u0430<\/p>\n<\/li>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0430 \u0432\u0432\u043e\u0434\u0430 OTP \u0434\u043b\u044f \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f e-mail \u0430\u0434\u0440\u0435\u0441\u0430<\/p>\n<\/li>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f e-mail \u0430\u0434\u0440\u0435\u0441\u0430<\/p>\n<\/li>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0430 \u0432\u0432\u043e\u0434\u0430 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0430\u0440\u043e\u043b\u044f<\/p>\n<\/li>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u044e\u0449\u0430\u044f \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0441\u043c\u0435\u043d\u0435 \u043f\u0430\u0440\u043e\u043b\u044f<\/p>\n<\/li>\n<\/ol>\n<p>\u0418\u0442\u0430\u043a, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430. \u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0444\u043e\u0440\u043c\u044b. \u0422\u0443\u0442 \u043a\u0430\u043a \u0440\u0430\u0437 \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u043c, \u0447\u0442\u043e \u043f\u0440\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043c\u044b \u0437\u0430\u043b\u043e\u0436\u0438\u043b\u0438\u0441\u044c \u043d\u0430 \u0431\u0443\u0434\u0443\u0449\u0435\u0435 \u0438 \u0447\u0430\u0441\u0442\u044c \u0444\u043e\u0440\u043c \u0432\u044b\u043d\u0435\u0441\u043b\u0438 \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b <code>sign-view<\/code>. \u041d\u0430\u043f\u043e\u043c\u043d\u044e, \u044d\u0442\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0444\u043e\u0440\u043c\u044b:<\/p>\n<ol>\n<li>\n<p><code>password-form.vue<\/code> &#8212; \u0432\u0432\u043e\u0434\u0430 \u043f\u0430\u0440\u043e\u043b\u044f \u0438 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u043f\u0430\u0440\u043e\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/p>\n<\/li>\n<li>\n<p><code>confirm-form.vue<\/code> &#8212; \u0432\u0432\u043e\u0434\u0430 OTP<\/p>\n<\/li>\n<li>\n<p><code>success-form.vue<\/code> &#8212; \u0444\u043e\u0440\u043c\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u044e\u0449\u0430\u044f \u043e\u0431 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u0435\u0440\u0432\u044b\u0435 \u0434\u0432\u0435 \u0444\u043e\u0440\u043c\u044b \u043c\u044b \u043a\u0430\u043a \u0440\u0430\u0437 \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 1-3 \u0448\u0430\u0433\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 \u0441\u043c\u0435\u043d\u044b \u043f\u0430\u0440\u043e\u043b\u044f. \u0410 \u0442\u0440\u0435\u0442\u044c\u044e \u0444\u043e\u0440\u043c\u0443 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u0438\u043b\u0438 \u043d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c!<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>reset-password<\/code> \u0432 <code>views\/sign-view<\/code>. \u0412 \u043d\u0435\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u0432\u0441\u0451, \u0447\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 \u0441\u043c\u0435\u043d\u044b \u043f\u0430\u0440\u043e\u043b\u044f. \u0414\u0430\u043b\u0435\u0435 \u043f\u043e \u0442\u043e\u043c\u0443 \u0436\u0435 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0443, \u0447\u0442\u043e \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0444\u043e\u0440\u043c \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438, \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u043e\u0440\u043c\u044b \u0441\u043c\u0435\u043d\u044b \u043f\u0430\u0440\u043e\u043b\u044f. <code>reset-password.vue<\/code> &#8212; \u0430\u0433\u0440\u0435\u0433\u0438\u0440\u0443\u044e\u0449\u0430\u044f \u0444\u043e\u0440\u043c\u0430. \u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>forms<\/code> \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0444\u043e\u0440\u043c\u044b \u043f\u043e\u0434 \u043a\u0430\u0436\u0434\u044b\u0439 \u0448\u0430\u0433.<\/p>\n<ol>\n<li>\n<p><code>init-form-pr.vue<\/code> &#8212; \u0444\u043e\u0440\u043c\u0430 \u0432\u0432\u043e\u0434\u0430 email \u0430\u0434\u0440\u0435\u0441\u0430<\/p>\n<\/li>\n<li>\n<p><code>confirm-step-pr.vue<\/code> &#8212; \u0444\u043e\u0440\u043c\u0430 \u0432\u0432\u043e\u0434\u0430 \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043f\u0430\u0440\u043e\u043b\u044f<\/p>\n<\/li>\n<li>\n<p><code>success-step-pr.vue<\/code> &#8212; \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u044e\u0449\u0430\u044f \u0444\u043e\u0440\u043c\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f email \u0430\u0434\u0440\u0435\u0441\u0430<\/p>\n<\/li>\n<li>\n<p><code>password-step-pr.vue<\/code> &#8212; \u0444\u043e\u0440\u043c\u0430 \u0432\u0432\u043e\u0434\u0430 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0430\u0440\u043e\u043b\u044f. \u0418\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u0430 \u0444\u043e\u0440\u043c\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u0438\u0437 email \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f<\/p>\n<\/li>\n<li>\n<p><code>success-step-change-password.vue<\/code> &#8212; \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u044e\u0449\u0430\u044f \u0444\u043e\u0440\u043c\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0441\u043c\u0435\u043d\u044b \u043f\u0430\u0440\u043e\u043b\u044f. \u0415\u0441\u043b\u0438 \u0441\u043c\u0435\u043d\u0430 \u043f\u0440\u043e\u0448\u043b\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e.<\/p>\n<\/li>\n<li>\n<p><code>error-step-change-password.vue<\/code> &#8212; \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u044e\u0449\u0430\u044f \u0444\u043e\u0440\u043c\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0441\u043c\u0435\u043d\u044b \u043f\u0430\u0440\u043e\u043b\u044f. \u0415\u0441\u043b\u0438 \u0441\u043c\u0435\u043d\u0430 \u043f\u0440\u043e\u0448\u043b\u0430 \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439.<\/p>\n<\/li>\n<\/ol>\n<p>\u0412\u043d\u0443\u0442\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u0439 \u0444\u043e\u0440\u043c\u044b \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 \u0435\u0451 \u043d\u0435 \u0431\u0443\u0434\u0435\u043c. \u041a\u043e\u0434 \u0434\u0430\u043d\u043d\u044b\u0445 \u0444\u043e\u0440\u043c \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u0432 <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/tree\/chapter-4.3\/j-sso\/client\/src\/views\/sign-view\/reset-password\/forms\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/a>.<\/p>\n<p>\u0421\u0442\u043e\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 <code>onMounted()<\/code> \u0445\u0443\u043a \u0432 <code>reset-password.vue<\/code>. \u0417\u0434\u0435\u0441\u044c \u0437\u0430\u0440\u044b\u0442\u0430 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u043d\u0438\u0436\u0435.<\/p>\n<p><code><strong>reset-password.vue<\/strong><\/code><\/p>\n<pre><code>\/\/ ....  onMounted(() => {     \/\/ \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0438\u0437 \u0441\u0442\u0440\u043e\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u043e \u0438\u043c\u0435\u043d\u0438 resetSessionId     const urlParams = new URLSearchParams(window.location.search);     const resetSessionId = urlParams.get('resetSessionId');      \/\/ \u0435\u0441\u043b\u0438 \u043c\u044b \u0441\u043c\u043e\u0433\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 resetSessionId     if (!!resetSessionId) {          \/\/ \u0441\u0440\u0430\u0437\u0443 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a \u0448\u0430\u0433\u0443 \u0441\u043c\u0435\u043d\u044b \u043f\u0430\u0440\u043e\u043b\u044f         setStep(STEPS.PASSWORD);         store.dispatch('setResetData', {             resetSessionId: resetSessionId         });         router.replace({name: \"reset-password\"})     } });  \/\/ .... <\/code><\/pre>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0433\u043e\u0440\u043e\u0434\u0438\u0442\u044c \u0433\u043e\u0440\u043e\u0434\u0443\u0448\u0435\u043a \u0441 \u0440\u043e\u0443\u0442\u0430\u043c\u0438, \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u0444\u043e\u0440\u043c\u044b \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0437 \u0441\u0442\u0440\u043e\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u043f\u043e \u0438\u043c\u0435\u043d\u0438 <code>resetSessionId<\/code>. \u0415\u0441\u043b\u0438 \u043c\u044b \u0435\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c, \u0442\u043e \u0441\u0440\u0430\u0437\u0443 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a \u0448\u0430\u0433\u0443 \u0441\u043c\u0435\u043d\u044b \u043f\u0430\u0440\u043e\u043b\u044f. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, URL \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u044b \u0441\u043c\u0435\u043d\u044b \u043f\u0430\u0440\u043e\u043b\u044f \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c: <code>http:\/\/localhost:7777\/client\/auth\/reset-password?resetSessionId=asda.....<\/code>.<\/p>\n<p>\u041d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043e \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435, \u043a\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f:<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/f87\/97b\/538\/f8797b5385fb7bf7b87b36a99a4dc8d3.png\" alt=\"E-mail \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0441\u0431\u0440\u043e\u0441\u0430 \u043f\u0430\u0440\u043e\u043b\u044f\" title=\"E-mail \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0441\u0431\u0440\u043e\u0441\u0430 \u043f\u0430\u0440\u043e\u043b\u044f\" width=\"1200\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/f87\/97b\/538\/f8797b5385fb7bf7b87b36a99a4dc8d3.png\"\/><\/p>\n<div><figcaption>E-mail \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0441\u0431\u0440\u043e\u0441\u0430 \u043f\u0430\u0440\u043e\u043b\u044f<\/figcaption><\/div>\n<\/figure>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0432\u0441\u0451 \u0431\u0430\u043d\u0430\u043b\u044c\u043d\u043e. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u0432\u043e\u0434\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0444\u043e\u0440\u043c\u0435 \u0441\u043c\u0435\u043d\u044b \u043f\u0430\u0440\u043e\u043b\u044f, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0431\u044d\u043a, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u043c\u0443 <code>resetSessionId<\/code> \u0432 Redis \u0438\u0449\u0435\u0442\u0441\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u0445\u043e\u0442\u0435\u043b \u0441\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0430\u0440\u043e\u043b\u044c. \u0415\u0441\u043b\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043d\u0430\u0439\u0434\u0435\u043d\u0430, \u0442\u043e \u043c\u0435\u043d\u044f\u0435\u043c \u043f\u0430\u0440\u043e\u043b\u044c, \u0435\u0441\u043b\u0438 \u043d\u0435\u0442, \u0442\u043e \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u043c \u043e\u0448\u0438\u0431\u043a\u0443.<\/p>\n<p>\u041d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0438 \u043e\u0431\u044a\u044f\u0432\u0438\u0442\u044c \u0442\u0430\u043c \u0442\u0440\u0438 endpoint-\u0430.<\/p>\n<p><code><strong>ResetPasswordController.java<\/strong><\/code><\/p>\n<pre><code class=\"java\"> @RestController @RequiredArgsConstructor @RequestMapping(\"\/reset-password\") public class ResetPasswordController {      private final ResetPasswordService resetPasswordService;      \/**      * \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u043c\u0435\u043d\u044b \u043f\u0430\u0440\u043e\u043b\u044f. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0434\u043b\u044f \u043a\u0430\u043a\u043e\u0433\u043e email \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0430\u0440\u043e\u043b\u044c.      * \u0415\u0441\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d, \u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0431\u0440\u043e\u0448\u0435\u043d\u043e \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435.      * \u0415\u0441\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u043d\u0430\u0439\u0434\u0435\u043d, \u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 OTP      *\/     @PostMapping(\"\/init\")     public void initResetPassword(@RequestPart(\"email\") String email, HttpServletResponse response) {         resetPasswordService.initial(email, response);     }      \/**      * \u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 email. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u0440\u0438\u0441\u044b\u043b\u0430\u0435\u0442 OTP \u043a\u043e\u0434 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u0435\u043c\u0443 \u043d\u0430 email \u0432 \u043f\u0435\u0440\u0432\u043e\u043c endpoint-\u0435.      * \u0415\u0441\u043b\u0438 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043f\u0440\u043e\u0448\u043b\u043e, \u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0432\u044b\u0441\u044b\u043b\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441\u043e \u0441\u0441\u044b\u043b\u043a\u043e\u0439 \u043d\u0430 \u0444\u043e\u0440\u043c\u0443 \u0441\u043c\u0435\u043d\u044b \u043f\u0430\u0440\u043e\u043b\u044f.      *\/     @PostMapping(\"\/confirm\")     public void confirm(@RequestPart(\"otp\") String otp, HttpServletRequest request) {         resetPasswordService.confirmEmail(otp, request);     }      \/**      * \u0421\u043c\u0435\u043d\u0430 \u043f\u0430\u0440\u043e\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0412 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u0445 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0443\u043a\u0430\u0437\u0430\u043d 'reset-password-session'      *\/     @PostMapping(\"\/set\")     public void setPassword(@RequestPart(\"password\") String password, HttpServletRequest request) {         resetPasswordService.setNewPassword(password, request);     } } <\/code><\/pre>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u0438 \u0432\u0442\u043e\u0440\u043e\u0439 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430\u043c \u0443\u0436\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b \u043f\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0443 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438. \u0412 <code>\/init<\/code>, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <code>OTPStore<\/code> (\u0435\u0433\u043e \u043c\u044b \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b\u0438 \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u043f\u0440\u043e \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044e), \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 Cookie \u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441\u0430\u043c \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c. \u041f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e Cookie \u0432\u044b\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432 <code>HttpServletResponse<\/code> \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0443. \u0410 \u043a\u043e\u0434 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430 email, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043a\u0430\u0437\u0430\u043b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c. \u0414\u0430\u043b\u0435\u0435 <code>\/confirm<\/code> &#8212; endpoint \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f \u0438 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 OTP \u043a\u043e\u0434\u0430. \u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e, \u043a\u0430\u043a \u0438 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438.<\/p>\n<p><code><strong>DefaultResetPasswordService.java<\/strong><\/code><\/p>\n<pre><code class=\"java\"> @Service @RequiredArgsConstructor public class DefaultResetPasswordService implements ResetPasswordService {      \/\/ .....      @Override     public void confirmEmail(String otp, HttpServletRequest request) {         otp = otp.trim();         if (!otpStore.validate(otp, request)) {             throw new ResetPasswordException(\"$opt.incorrect\");         }          \/\/ \u043f\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0443 \u043f\u043e OTPStore \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 resetPasswordStore. \u0422\u0430\u043c \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f email \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.         \/\/ \u041e\u043d \u0431\u044b\u043b \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d \u043d\u0430 \u043f\u0435\u0440\u0432\u043e\u043c \u0448\u0430\u0433\u0435.         String sessionId = otpStore.getSessionId(request);         ResetPasswordStore.StoreItem storeItem;         try {             storeItem = resetPasswordStore.take(sessionId);         } catch (Exception e) {             throw InformationException.builder(\"$happened.unexpected.error\").build();         }          \/\/ \u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0441\u0435\u0441\u0441\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043a\u0430\u0436\u0435\u043c \u0432 email \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0438.         String resetPasswordSessionId = CryptoUtils.hash(sessionId + \"-\" + otp);         try {             resetPasswordStore.save(storeItem, resetPasswordSessionId);         } catch (Exception e) {             throw InformationException.builder(\"$happened.unexpected.error\").build();         }          \/\/ \u041d\u0430\u0445\u043e\u0434\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u043e email \u0432 \u0411\u0414. \u041e\u043d \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d, \u0434\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0438\u043c\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.         UserEntity user = userService.findByEmail(storeItem.email());          \/\/ \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c email \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435.         emailSender.sendHtmlTemplated(                 storeItem.email(),                 messageService.getMessage(\"email.subject.reset.password\"),                 \"classpath:mail-templates\/reset-password.html\",                 ImmutableMap.&lt;String, Object>builder()                         .put(\"firstName\", user.getFirstName())                         .put(\"resetPasswordUrl\", this.getResetPasswordUrl(resetPasswordSessionId))                         .build()         );     }      \/**      * \u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f URL \u043d\u0430 \u0444\u043e\u0440\u043c\u0443 \u0441\u0431\u0440\u043e\u0441\u0430 \u043f\u0430\u0440\u043e\u043b\u044f      * @param sessionId \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0441\u0435\u0441\u0441\u0438\u0438      *\/     private String getResetPasswordUrl(String sessionId) {         String httpUrl = authorizationServerProperties.getIssuerUrl()                 + authorizationServerProperties.getResetPasswordEndpoint();         UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(httpUrl);         builder.queryParam(\"resetSessionId\", sessionId);         return builder.build().toUriString();     }      \/\/ ..... } <\/code><\/pre>\n<p>\u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043f\u0440\u0438 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 OTP \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 (\u0442\u043e\u0442 \u0441\u0430\u043c\u044b\u0439 <code>resetSessionId<\/code>). \u041f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e, \u043e\u043d \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043e\u0431 email \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 Redis. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0435\u0449\u0451 \u043e\u0434\u043d\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0444\u043e\u0440\u043c\u0443 \u0441\u0431\u0440\u043e\u0441\u0430 \u043f\u0430\u0440\u043e\u043b\u044f (\u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0434\u0430\u043d\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440). \u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0441\u0431\u0440\u043e\u0441 \u043f\u0430\u0440\u043e\u043b\u044f \u0431\u044b\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u043d\u043e\u0432\u0430\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0432 <code>application.yml<\/code> &#8212; <code>spring.security.oauth2.authorizationserver.reset-password-endpoint<\/code>. \u0421\u0430\u043c URL \u043d\u0430 \u0444\u043e\u0440\u043c\u0443 \u0441\u0431\u0440\u043e\u0441\u0430 \u043f\u0430\u0440\u043e\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u043f\u043e \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c \u043a\u043e\u043d\u043a\u0430\u0442\u0435\u043d\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u043e\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438 <code>authorizationserver.issuer-url<\/code>, \u0430 \u0434\u0430\u043b\u0435\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>resetSessionId<\/code>, \u043a\u0430\u043a \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u0442 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435, \u0432\u0432\u0435\u0434\u0451\u0442 \u043d\u043e\u0432\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c \u0438 \u043d\u0430\u0436\u043c\u0451\u0442 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 &#171;\u0414\u0430\u043b\u0435\u0435&#187;, \u043f\u043e\u043b\u0435\u0442\u0438\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 <code>\/set<\/code>. \u041b\u043e\u0433\u0438\u043a\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u044d\u0442\u043e\u0433\u043e endpoint-\u0430 \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u043d\u0438\u0436\u0435.<\/p>\n<p><code><strong>DefaultResetPasswordService.java<\/strong><\/code><\/p>\n<pre><code class=\"java\"> @Service @RequiredArgsConstructor public class DefaultResetPasswordService implements ResetPasswordService {      private static final String SESSION_ID_HEADER = \"reset-password-session\";      \/\/ .....      @Override     public void setNewPassword(String newPassword, HttpServletRequest request) {         \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a         if (request.getHeader(SESSION_ID_HEADER) == null) {             throw new ResetPasswordException(\"$reset.password.broke\");         }          \/\/ \u041f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430.         String resetPasswordSessionId = request.getHeader(SESSION_ID_HEADER);          \/\/ \u041f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 resetPasswordStore \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u0438\u0437 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430         ResetPasswordStore.StoreItem storeItem;         try {             storeItem = resetPasswordStore.take(resetPasswordSessionId);         } catch (Exception e) {             throw InformationException.builder(\"$happened.unexpected.error\").build();         }          \/\/ \u0415\u0441\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0435\u0442, \u0442\u043e \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u043c \u043e\u0448\u0438\u0431\u043a\u0443         if (storeItem == null) {             throw new ResetPasswordException(\"$reset.password.broke\");         }          \/\/ \u0415\u0441\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0435\u0441\u0442\u044c, \u0442\u043e \u043c\u0435\u043d\u044f\u0435\u043c \u043f\u0430\u0440\u043e\u043b\u044c \u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. Email \u0431\u0435\u0440\u0451\u043c \u0442\u043e\u0442 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0438\u0437 resetPasswordStore         userService.changePassword(storeItem.email(), newPassword);     } }  <\/code><\/pre>\n<p>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0441\u0435\u0441\u0441\u0438\u0438 \u0438\u0437 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430. \u0418\u0437 <code>ResetPasswordStore<\/code> \u0434\u043e\u0441\u0442\u0430\u0451\u043c email \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u043c\u0443 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0443. \u0415\u0441\u043b\u0438 \u043e\u0448\u0438\u0431\u043e\u043a \u043d\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u043e, \u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043c\u0435\u043d\u044f\u0435\u043c \u043f\u0430\u0440\u043e\u043b\u044c \u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<p>\u0414\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 \u0431\u044b\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u044b \u0434\u0432\u0430 \u0448\u0430\u0431\u043b\u043e\u043d\u0430 email \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0418\u0445 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432 <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/tree\/chapter-4.3\/j-sso\/src\/main\/resources\/mail-templates\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/a>.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0444\u043e\u0440\u043c\u043e\u0439 \u0432\u0445\u043e\u0434\u0430 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0430\u0440\u043e\u043b\u044f. \u041d\u0438\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/b58\/cde\/236\/b58cde236a1981fa8d7ec1ba1ee26d10.gif\" alt=\"\u041c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0441\u0431\u0440\u043e\u0441\u0430 \u043f\u0430\u0440\u043e\u043b\u044f\" title=\"\u041c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0441\u0431\u0440\u043e\u0441\u0430 \u043f\u0430\u0440\u043e\u043b\u044f\" width=\"1200\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/b58\/cde\/236\/b58cde236a1981fa8d7ec1ba1ee26d10.gif\"\/><\/p>\n<div><figcaption>\u041c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0441\u0431\u0440\u043e\u0441\u0430 \u043f\u0430\u0440\u043e\u043b\u044f<\/figcaption><\/div>\n<\/figure>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0440\u0430\u0437\u0431\u043e\u0440 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 &#171;\u0437\u0430\u0431\u044b\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c&#187; \u043c\u044b \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u043c \u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a \u0438\u0442\u043e\u0433\u0430\u043c \u043d\u0430\u0448\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0438.<\/p>\n<blockquote>\n<p>\u0418\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/tree\/chapter-4.3\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<\/blockquote>\n<h3>\u0420\u0435\u0437\u044e\u043c\u0435<\/h3>\n<p>\u0418\u0442\u0430\u043a, \u043c\u044b \u043f\u0440\u043e\u0434\u0435\u043b\u0430\u043b\u0438 \u043e\u0433\u0440\u043e\u043c\u043d\u0443\u044e \u0440\u0430\u0431\u043e\u0442\u0443 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043b\u0438 \u0432\u0441\u0435 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0438 \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u0435\u0440\u043d\u0451\u043c\u0441\u044f \u043a \u043f\u0435\u0440\u0432\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0438 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0438\u043c \u043d\u0438\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f:<\/p>\n<p><strong>\u0422\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f<\/strong><\/p>\n<ol>\n<li>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0435\u043f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u044b\u0445 \u0442\u043e\u043a\u0435\u043d\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445 \u0432\u0435\u0440\u0441\u0438\u0439 Spring Boot \u0438 Spring Authorization Server<\/p>\n<\/li>\n<li>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 Java 17<\/p>\n<\/li>\n<li>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 SPA Vue.JS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0444\u0440\u043e\u043d\u0442\u0430 SSO<\/p>\n<\/li>\n<li>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 Redis \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043a\u044d\u0448 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 (\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u043e\u0432 \u0438 \u0442.\u0434.)<\/p>\n<\/li>\n<li>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 PostgreSQL \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c Swagger \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0442\u0430\u043c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e<\/p>\n<\/li>\n<\/ol>\n<p><strong>\u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f:<\/strong><\/p>\n<ol>\n<li>\n<p>\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043d\u0430 SSO \u0447\u0435\u0440\u0435\u0437 \u0444\u043e\u0440\u043c\u0443 \u043b\u043e\u0433\u0438\u043d\u0430\/\u043f\u0430\u0440\u043e\u043b\u044f<\/p>\n<\/li>\n<li>\n<p>\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043d\u0430 SSO \u0447\u0435\u0440\u0435\u0437 Google, Github \u0438 Yandex<\/p>\n<\/li>\n<li>\n<p>\u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0443 OAuth2.1 \u0434\u043b\u044f \u043c\u043e\u0438\u0445 pet-\u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435 \u043f\u043e \u0442\u043e\u043a\u0435\u043d\u0443 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0438\u0437 SSO<\/p>\n<\/li>\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\u0435\u0439 \u0447\u0435\u0440\u0435\u0437 Google, Github \u0438 Yandex<\/p>\n<\/li>\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\u0435\u0439 \u0447\u0435\u0440\u0435\u0437 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0444\u043e\u0440\u043c\u0443 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043d\u0430 SSO<\/p>\n<\/li>\n<li>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438 &#171;\u0417\u0430\u0431\u044b\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c&#187;<\/p>\n<\/li>\n<\/ol>\n<p>\u0423 \u043d\u0430\u0441 \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u043e \u043d\u0435\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u043e\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0435.<\/p>\n<ul>\n<li>\n<p>\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u044b\u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0442\u043e\u043a\u0435\u043d\u0430\u043c\u0438 (\u043e\u0442\u0437\u044b\u0432 \u0442\u043e\u043a\u0435\u043d\u0430, \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0441\u0435\u0441\u0441\u0438\u0439 \u0438 \u0442.\u0434.)<\/p>\n<\/li>\n<\/ul>\n<p>\u0415\u0433\u043e \u043c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0437\u0430\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435. \u0422\u0430\u043a\u0436\u0435 \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u043c \u043d\u0430\u0448 <code>j-sso<\/code> \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c\u0438 \u0444\u043e\u0440\u043c\u0430\u043c\u0438. \u0418 \u0432 \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043a\u043e \u0432\u0441\u0435\u043c\u0443 \u0441\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u043c\u0443 \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c, \u043a\u0430\u043a \u0438 \u043a\u0430\u043a\u0438\u0435 Security Headers \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c.<\/p>\n<h3>\u041f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0441\u0441\u044b\u043b\u043a\u0438<\/h3>\n<p>\u0418\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a><\/p>\n<p><strong>Frontend<\/strong><\/p>\n<ol>\n<li>\n<p><a href=\"https:\/\/docs.npmjs.com\/cli\/v10\/configuring-npm\/package-json\" rel=\"noopener noreferrer nofollow\">\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043f\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 package.json<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.npmjs.com\/\" rel=\"noopener noreferrer nofollow\">\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 NPM<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/github.com\/browserslist\/browserslist\" rel=\"noopener noreferrer nofollow\">\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043f\u043e browserslist<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/cli.vuejs.org\/config\/#vue-config-js\" rel=\"noopener noreferrer nofollow\">\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043f\u043e vue.config.js<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/vuetifyjs.com\/en\/getting-started\/installation\/#installation\" rel=\"noopener noreferrer nofollow\">\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043f\u043e Vuetify<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/babeljs.io\/docs\" rel=\"noopener noreferrer nofollow\">\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043f\u043e Babel<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/router.vuejs.org\/guide\/\" rel=\"noopener noreferrer nofollow\">\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043f\u043e vue-router<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/vuex.vuejs.org\/guide\/modules.html\" rel=\"noopener noreferrer nofollow\">\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043f\u043e vuex<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/v3.ru.vuejs.org\/ru\/api\/application-api.html\" rel=\"noopener noreferrer nofollow\">\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043f\u043e Vue 3<\/a><\/p>\n<\/li>\n<li>\n<p>\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 d-dto. <a href=\"https:\/\/www.npmjs.com\/package\/@dlabs71\/d-dto\" rel=\"noopener noreferrer nofollow\">Npmjs<\/a>. <a href=\"https:\/\/github.com\/dlabs71\/d-dto#readme\" rel=\"noopener noreferrer nofollow\">Github<\/a><\/p>\n<\/li>\n<\/ol>\n<p><strong>Backend<\/strong><\/p>\n<ol>\n<li>\n<p><a href=\"https:\/\/jakarta.ee\/specifications\/mail\/2.0\/jakarta-mail-spec-2.0\" rel=\"noopener noreferrer nofollow\">\u041f\u0440\u043e\u0435\u043a\u0442 Jakarta Mail<\/a><\/p>\n<\/li>\n<li>\n<p>\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 D-email. <a href=\"https:\/\/mvnrepository.com\/artifact\/ru.dlabs71.library\/d-email\" rel=\"noopener noreferrer nofollow\">Maven Central<\/a>. <a href=\"https:\/\/github.com\/dlabs71\/d-email#readme\" rel=\"noopener noreferrer nofollow\">Github<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/17\/docs\/api\/java.base\/java\/util\/ResourceBundle.html\" rel=\"noopener noreferrer nofollow\">\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043f\u043e Class ResourceBundle<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/docs.spring.io\/spring-framework\/docs\/current\/javadoc-api\/org\/springframework\/context\/support\/ResourceBundleMessageSource.html\" rel=\"noopener noreferrer nofollow\">\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043f\u043e Class ResourceBundleMessageSource<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/docs.spring.io\/spring-framework\/docs\/current\/javadoc-api\/org\/springframework\/web\/bind\/annotation\/RestControllerAdvice.html\" rel=\"noopener noreferrer nofollow\">\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043f\u043e Annotation Interface RestControllerAdvice<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/docs.spring.io\/spring-boot\/docs\/1.5.6.RELEASE\/reference\/html\/boot-features-external-config.html\" rel=\"noopener noreferrer nofollow\">\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043f\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c Spring Boot \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/a><\/p>\n<\/li>\n<\/ol>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><\/p>\n<div class=\"tm-article-poll-container\"><!--[--><\/p>\n<div class=\"tm-article-poll tm-article-poll_variant-bordered\">\n<div class=\"tm-notice tm-notice_positive tm-article-poll__notice\"><!----><\/p>\n<div class=\"tm-notice__inner\"><!----><\/p>\n<div class=\"tm-notice__content\" data-test-id=\"notice-content\"><!--[--><span>\u0422\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043c\u043e\u0433\u0443\u0442 \u0443\u0447\u0430\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0432 \u043e\u043f\u0440\u043e\u0441\u0435. <a rel=\"nofollow\" href=\"\/kek\/v1\/auth\/habrahabr\/?back=\/ru\/articles\/784552\/&#038;hl=ru\">\u0412\u043e\u0439\u0434\u0438\u0442\u0435<\/a>, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430.<\/span><!--]--><\/div>\n<\/div>\n<\/div>\n<p><!--[--><\/p>\n<div class=\"tm-article-poll__header\">\u041d\u0440\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043b\u0438 \u0412\u0430\u043c \u0444\u043e\u0440\u043c\u0430\u0442 \u0441\u0442\u0430\u0442\u0435\u0439?<\/div>\n<div class=\"tm-article-poll__answers\"><!--[--><\/p>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent tm-article-poll__answer-percent_winning\">64.71% <\/span><span class=\"tm-article-poll__answer-label\">\u0414\u0430<\/span><span class=\"tm-article-poll__answer-votes\">11<\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress tm-article-poll__answer-progress_winning\" style=\"width: 64.71%\"><\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent\">17.65% <\/span><span class=\"tm-article-poll__answer-label\">\u041d\u043e\u0440\u043c, \u043d\u043e \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u043a\u043e\u0440\u043e\u0447\u0435<\/span><span class=\"tm-article-poll__answer-votes\">3<\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress\" style=\"width: 17.65%\"><\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent\">17.65% <\/span><span class=\"tm-article-poll__answer-label\">\u041d\u0435\u0442<\/span><span class=\"tm-article-poll__answer-votes\">3<\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress\" style=\"width: 17.65%\"><\/div>\n<\/div>\n<\/div>\n<p><!--]--><\/div>\n<div class=\"tm-article-poll__stats\"> \u041f\u0440\u043e\u0433\u043e\u043b\u043e\u0441\u043e\u0432\u0430\u043b\u0438 17 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.   \u0412\u043e\u0437\u0434\u0435\u0440\u0436\u0430\u043b\u0438\u0441\u044c 3 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. <\/div>\n<p><!--]--><\/div>\n<div class=\"tm-article-poll tm-article-poll_variant-bordered\">\n<div class=\"tm-notice tm-notice_positive tm-article-poll__notice\"><!----><\/p>\n<div class=\"tm-notice__inner\"><!----><\/p>\n<div class=\"tm-notice__content\" data-test-id=\"notice-content\"><!--[--><span>\u0422\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043c\u043e\u0433\u0443\u0442 \u0443\u0447\u0430\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0432 \u043e\u043f\u0440\u043e\u0441\u0435. <a rel=\"nofollow\" href=\"\/kek\/v1\/auth\/habrahabr\/?back=\/ru\/articles\/784552\/&#038;hl=ru\">\u0412\u043e\u0439\u0434\u0438\u0442\u0435<\/a>, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430.<\/span><!--]--><\/div>\n<\/div>\n<\/div>\n<p><!--[--><\/p>\n<div class=\"tm-article-poll__header\">\u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0435 \u0412\u044b \u044d\u0442\u0438 \u0437\u043d\u0430\u043d\u0438\u044f \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435?<\/div>\n<div class=\"tm-article-poll__answers\"><!--[--><\/p>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent tm-article-poll__answer-percent_winning\">60% <\/span><span class=\"tm-article-poll__answer-label\">\u0414\u0430<\/span><span class=\"tm-article-poll__answer-votes\">6<\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress tm-article-poll__answer-progress_winning\" style=\"width: 60%\"><\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent\">40% <\/span><span class=\"tm-article-poll__answer-label\">\u041d\u0435\u0442<\/span><span class=\"tm-article-poll__answer-votes\">4<\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress\" style=\"width: 40%\"><\/div>\n<\/div>\n<\/div>\n<p><!--]--><\/div>\n<div class=\"tm-article-poll__stats\"> \u041f\u0440\u043e\u0433\u043e\u043b\u043e\u0441\u043e\u0432\u0430\u043b\u0438 10 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.   \u0412\u043e\u0437\u0434\u0435\u0440\u0436\u0430\u043b\u0438\u0441\u044c 4 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. <\/div>\n<p><!--]--><\/div>\n<p><!--]--><\/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\/784552\/\"> https:\/\/habr.com\/ru\/articles\/784552\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h3>\u0421\u043f\u0438\u0441\u043e\u043a \u0441\u0442\u0430\u0442\u0435\u0439 \u044d\u0442\u043e\u0439 \u0441\u0435\u0440\u0438\u0438<\/h3>\n<ul>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/737548\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 1: \u0421\u0442\u0440\u043e\u0438\u043c \u0441\u0432\u043e\u0439 SSO \u0441\u0435\u0440\u0432\u0435\u0440, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f Spring Authorization Server<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/746698\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 2: \u0421\u0442\u0440\u043e\u0438\u043c \u0441\u0432\u043e\u0439 SSO. PostgreSQL \u0438 \u0440\u043e\u043b\u0435\u0432\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/748584\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 3: \u0421\u0442\u0440\u043e\u0438\u043c \u0441\u0432\u043e\u0439 SSO. Redis, Swagger, Vue.js<\/a><\/p>\n<\/li>\n<li>\n<p>\u0427\u0430\u0441\u0442\u044c 4: \u0421\u0442\u0440\u043e\u0438\u043c \u0441\u0432\u043e\u0439 SSO. Vue.js, \u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f, \u0421\u0431\u0440\u043e\u0441 \u043f\u0430\u0440\u043e\u043b\u044f<\/p>\n<\/li>\n<\/ul>\n<h3>\u0412\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435<\/h3>\n<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442, \u043c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 SSO Server. \u041d\u043e \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u043c, \u0447\u0442\u043e \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u0432 <a href=\"https:\/\/habr.com\/ru\/articles\/748584\/\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435<\/a>:<\/p>\n<ul>\n<li>\n<p>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043b\u0438 Redis<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u043b\u0438 Swagger<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043b\u0438 \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f <code>j-sso<\/code> \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <code>Vue.js<\/code><\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u0440\u0438 \u0440\u0430\u0437\u0431\u043e\u0440\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 Redis \u0431\u044b\u043b \u0443\u043f\u0443\u0449\u0435\u043d \u043e\u0447\u0435\u043d\u044c \u0432\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442. \u041a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u044f <code>OAuth2AuthorizationService oAuth2AuthorizationService()<\/code> \u0431\u0438\u043d\u0430, \u043f\u0435\u0440\u0435\u0432\u043e\u0434 \u0435\u0433\u043e \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 Redis. \u041d\u0435\u0434\u0430\u0432\u043d\u043e \u043e\u043d \u0431\u044b\u043b \u043e\u0431\u043d\u043e\u0432\u043b\u0451\u043d, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0441\u043b\u0438 \u0412\u044b \u0435\u0449\u0451 \u043d\u0435 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043b\u0438 \u0435\u0433\u043e, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430 \u0432\u0435\u0440\u043d\u0438\u0442\u0435\u0441\u044c \u043a \u0440\u0430\u0437\u0434\u0435\u043b\u0443 <a href=\"https:\/\/habr.com\/ru\/articles\/748584\/\" rel=\"noopener noreferrer nofollow\"><strong>\u0420\u0430\u0437\u0434\u0435\u043b 3.1: \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c Redis<\/strong><\/a> \u0438 \u043f\u0440\u043e\u0447\u0442\u0438\u0442\u0435 \u0435\u0433\u043e \u0435\u0449\u0451 \u0440\u0430\u0437.<\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u0443\u043d\u043a\u0442\u044b:<\/p>\n<ul>\n<li>\n<p>\u0414\u0435\u0442\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c frontend \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0447\u0435\u0440\u0435\u0437 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0444\u043e\u0440\u043c\u0443 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043d\u0430 SSO<\/p>\n<\/li>\n<li>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e &#171;\u0417\u0430\u0431\u044b\u043b\u0438 \u043f\u0430\u0440\u043e\u043b\u044c&#187;<\/p>\n<\/li>\n<\/ul>\n<p>\u0418\u0442\u0430\u043a, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c!<\/p>\n<h3>\u0420\u0430\u0437\u0434\u0435\u043b 4.1: \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 frontend \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h3>\n<p>\u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0443\u0436\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b\u0438 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <code>vue-cli<\/code>. \u0410 \u0442\u0430\u043a\u0436\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438, \u0447\u0442\u043e \u0438\u0437 \u0441\u0435\u0431\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u0431\u043e\u0440\u043a\u0430 frontend \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u0435\u0435 \u043f\u043e\u0433\u0440\u0443\u0437\u0438\u0442\u044c\u0441\u044f \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0435 \u0435\u0433\u043e \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0435.<\/p>\n<p>\u0421\u0440\u0430\u0437\u0443 \u0441\u043a\u0430\u0436\u0443, \u044f \u0443\u043b\u0443\u0447\u0448\u0438\u043b \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043f\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044e \u0441 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435\u0439. \u0422\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u0440\u044f\u0434 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u043f\u0440\u0438 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412\u0441\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/tree\/chapter-4.1\/j-sso\/client\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a><\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u0437\u0433\u043b\u044f\u043d\u0435\u043c \u043d\u0430 \u043d\u0430\u0448 <code>package.json<\/code> \u0444\u0430\u0439\u043b. \u0412 \u043d\u0451\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0422\u0430\u043a\u0436\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u044b \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0438 \u0441\u0431\u043e\u0440\u043a\u0438. \u0418 \u0435\u0449\u0451 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043c\u0435\u0442\u0430\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0434\u043b\u044f \u0441\u0438\u0441\u0442\u0435\u043c \u0441\u0431\u043e\u0440\u043a\u0438 frontend \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p><code><strong>package.json<\/strong><\/code><\/p>\n<pre><code class=\"json\">{     \"name\": \"client\",     \"version\": \"0.1.0\",     \"private\": true,     \"scripts\": {         \"serve\": \"vue-cli-service serve --mode=development\",         \"build\": \"vue-cli-service build --mode=development\",         \"build-prod\": \"vue-cli-service build --mode=production\",         \"build-test\": \"vue-cli-service build --mode=testing\",         \"build-dev-java\": \"vue-cli-service build --mode=dev-java\"     },     \"dependencies\": {         \"@dlabs71\/d-dto\": \"^1.1.0\",         \"@kyvg\/vue3-notification\": \"^2.9.1\",         \"@mdi\/font\": \"^7.2.96\",         \"@vee-validate\/i18n\": \"^4.9.5\",         \"@vee-validate\/rules\": \"^4.9.5\",         \"@vuepic\/vue-datepicker\": \"^5.1.2\",         \"axios\": \"^1.4.0\",         \"core-js\": \"^3.30.2\",         \"moment\": \"^2.29.4\",         \"roboto-fontface\": \"*\",         \"uuid\": \"^9.0.0\",         \"vee-validate\": \"^4.9.5\",         \"vue\": \"^3.3.4\",         \"vue-router\": \"^4.2.2\",         \"vuetify\": \"^3.3.1\",         \"vuex\": \"^4.1.0\",         \"vuex-persist\": \"^3.1.3\",         \"webfontloader\": \"^1.6.28\"     },     \"devDependencies\": {         \"@babel\/core\": \"^7.22.1\",         \"@babel\/preset-env\": \"^7.22.2\",         \"@vue\/cli-plugin-babel\": \"~5.0.8\",         \"@vue\/cli-plugin-router\": \"~5.0.8\",         \"@vue\/cli-plugin-vuex\": \"~5.0.8\",         \"@vue\/cli-service\": \"~5.0.8\",         \"sass\": \"^1.62.1\",         \"sass-loader\": \"^13.3.1\",         \"vue-cli-plugin-vuetify\": \"~2.5.8\",         \"webpack-plugin-vuetify\": \"^2.0.1\"     },     \"engines\": {         \"npm\": \">=8.0.0\",         \"node\": \">=16.0.0\"     },     \"browserslist\": [         \"> 1%\",         \"last 2 versions\",         \"not dead\",         \"not ie 11\"     ] } <\/code><\/pre>\n<p>\u0414\u0435\u0442\u0430\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431\u043e \u0432\u0441\u0435\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u044d\u0442\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 <a href=\"https:\/\/docs.npmjs.com\/cli\/v10\/configuring-npm\/package-json\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>. \u041a\u043e\u043c\u0430\u043d\u0434\u044b \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u0432 \u0441\u0435\u043a\u0446\u0438\u0438 <code>\"scripts\"<\/code> \u0443\u0436\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b\u0438\u0441\u044c \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430 \u043d\u0438\u0445 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u0431\u0443\u0434\u0435\u043c. \u0421\u0440\u0430\u0437\u0443 \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c \u0432 \u0441\u0435\u043a\u0446\u0438\u0438 <code>\"dependencies\"<\/code>. \u041d\u0438\u0436\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<ul>\n<li>\n<p><code>@dlabs71\/d-dto<\/code> &#8212; \u044d\u0442\u043e \u043c\u043d\u043e\u044e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u043b\u0430\u0441\u0441\u043e\u0432 DTO, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0430\u0446\u0438\u0438 \u0438\u0437 json \u0432 dto \u043a\u043b\u0430\u0441\u0441 \u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e. \u041e\u043d\u0430 \u043d\u0430\u043c \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0440\u0430\u0437\u0434\u0435\u043b\u0430\u0445 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u043f\u0440\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 API.<\/p>\n<\/li>\n<li>\n<p><code>@kyvg\/vue3-notification<\/code> &#8212; \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0438\u0445 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p><code>@vuepic\/vue-datepicker<\/code> &#8212; \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u043e\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 \u0434\u0430\u0442\u044b.<\/p>\n<\/li>\n<li>\n<p><code>axios<\/code> &#8212; \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f HTTP \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p><code>vee-validate<\/code> &#8212; \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u043e\u0432 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0444\u043e\u0440\u043c.<\/p>\n<\/li>\n<li>\n<p><code>vue<\/code> &#8212; \u0441\u0430\u043c VUE \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u043f\u0435\u0440\u0441\u043e\u043d\u043e\u0439<\/p>\n<\/li>\n<li>\n<p><code>vue-router<\/code> &#8212; \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u043e\u0432 \u0440\u043e\u0443\u0442\u0438\u043d\u0433\u0430 (\u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438).<\/p>\n<\/li>\n<li>\n<p><code>vuetify<\/code> &#8212; \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0432\u0441\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u0438 \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0444\u043e\u0440\u043c.<\/p>\n<\/li>\n<li>\n<p><code>vuex<\/code> &#8212; \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u0441\u0435\u043a\u0446\u0438\u0438 <code>devDependencies<\/code> \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0422\u0443\u0442 \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u043f\u043b\u0430\u0433\u0438\u043d\u044b <code>vue<\/code>, <code>vuetify<\/code>, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043f\u0440\u0435\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 <code>sass<\/code>.<\/p>\n<p>\u0412\u0441\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u043d\u0430 \u0441\u0430\u0439\u0442\u0435 <a href=\"https:\/\/www.npmjs.com\/\" rel=\"noopener noreferrer nofollow\">npmjs<\/a>.<\/p>\n<p>\u0421\u0442\u043e\u0438\u0442 \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043b\u043e\u0432 \u043f\u0440\u043e \u0441\u0435\u043a\u0446\u0438\u044e <code>\"browserslist\"<\/code>. \u0412 \u043d\u0435\u0439 \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u0432 \u0434\u043b\u044f \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041f\u043e\u043b\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043d\u0451\u043c \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 <a href=\"https:\/\/github.com\/browserslist\/browserslist\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0434\u043b\u044f \u043d\u0430\u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u043c \u0444\u0430\u0439\u043b\u043e\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <code>vue.config.js<\/code>. \u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0432\u0441\u044e \u043e\u0441\u043d\u043e\u0432\u043d\u0443\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u043d\u0430\u0448\u0435\u0433\u043e Vue \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0418\u0437\u0443\u0447\u0438\u0442\u044c \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e \u0435\u0451 \u043c\u043e\u0436\u043d\u043e <a href=\"https:\/\/cli.vuejs.org\/config\/#vue-config-js\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>. \u041d\u0443 \u0430 \u043c\u044b \u043f\u0440\u043e\u0439\u0434\u0451\u043c\u0441\u044f \u043f\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u043c \u043d\u0430\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c:<\/p>\n<p><code><strong>vue.config.js<\/strong><\/code><\/p>\n<pre><code>const {defineConfig} = require('@vue\/cli-service');  module.exports = defineConfig({     transpileDependencies: [\"vuetify\"],     publicPath: process.env.VUE_APP_NODE_ENV !== \"development\" ? \"\/static\" : \"\/\",      devServer: {         port: 8080     },      pluginOptions: {         vuetify: {             styles: {                 configFile: \"src\/assets\/scss\/settings.scss\"             }         }     } }); <\/code><\/pre>\n<ul>\n<li>\n<p><code>transpileDependencies<\/code> &#8212; \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043a\u0430\u043a\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043d\u0443\u0436\u043d\u043e \u0442\u0440\u0430\u043d\u0441\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0442\u0430\u043a \u043a\u0430\u043a \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e <code>babel-loader<\/code> \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0435\u0442 \u0432\u0441\u0435 \u0444\u0430\u0439\u043b\u044b \u0438\u0437 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>node_modules<\/code><\/p>\n<\/li>\n<li>\n<p><code>publicPath<\/code> &#8212; \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b\u0438 \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435. \u041d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043f\u0443\u0442\u0438 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043f\u0440\u0438 \u0441\u0431\u043e\u0440\u043a\u0435.<\/p>\n<\/li>\n<li>\n<p><code>devServer<\/code> &#8212; \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043b\u044f <code>nodejs<\/code> \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 \u0435\u0433\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u0423\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043f\u043e\u0440\u0442 <code>8080<\/code>.<\/p>\n<\/li>\n<li>\n<p><code>pluginOptions<\/code> &#8212; \u0437\u0434\u0435\u0441\u044c \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u0445 \u043f\u043b\u0430\u0433\u0438\u043d\u043e\u0432, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a <code>vuetify<\/code>. \u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0434\u043b\u044f \u043f\u043b\u0430\u0433\u0438\u043d\u0430 <code>vue-cli-plugin-vuetify<\/code> \u0444\u0430\u0439\u043b \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0441\u0442\u0438\u043b\u0435\u0439. \u0423\u0437\u043d\u0430\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0441\u0442\u0438\u043b\u0435\u0439 <code>vuetify<\/code> \u043c\u043e\u0436\u043d\u043e <a href=\"https:\/\/vuetifyjs.com\/en\/features\/sass-variables\/#installation\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a>.<\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u0442\u043e\u0438\u0442 \u0441\u0440\u0430\u0437\u0443 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0433\u0434\u0435 \u0443 \u043d\u0430\u0441 \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u044e\u0442\u0441\u044f <code>css<\/code> \u0441\u0442\u0438\u043b\u0438 (\u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043f\u0440\u0435\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 <code>sass<\/code> \u0441\u043e \u0441\u0442\u0438\u043b\u0435\u043c <code>scss<\/code>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0443 \u043d\u0430\u0441 <code>.scss<\/code> \u0444\u0430\u0439\u043b\u044b). \u041e\u043d\u0438 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>src\/assets\/css<\/code>. \u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <code>src\/assets<\/code> \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u0442\u0438\u043b\u0435\u0439, \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439, \u0448\u0440\u0438\u0444\u0442\u043e\u0432 \u0438 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0443 \u043d\u0430\u0441 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438 \u0441\u0442\u0438\u043b\u0438.<\/p>\n<p>\u0412\u0441\u0435 <code>.env<\/code> \u0444\u0430\u0439\u043b\u044b \u043c\u044b \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b\u0438 \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435. \u041e\u043d\u0438 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u044b \u0433\u043b\u0430\u0432\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0441\u0440\u0435\u0434\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0437\u0433\u043b\u044f\u043d\u0435\u043c \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0444\u0430\u0439\u043b\u044b:<\/p>\n<ul>\n<li>\n<p><code>babel.config.js<\/code> &#8212; \u0445\u0440\u0430\u043d\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e babel (\u043f\u043e\u043f\u0440\u043e\u0441\u0442\u0443 \u0433\u043e\u0432\u043e\u0440\u044f js \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440). \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043d\u0451\u043c \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 <a href=\"https:\/\/babeljs.io\/docs\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<\/li>\n<li>\n<p><code>jsconfig.json<\/code> &#8212; \u044d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u0445\u0440\u0430\u043d\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u043c\u043e\u0433\u0430\u044e\u0442 \u0432\u0430\u0448\u0435\u043c\u0443 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0443 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u0442\u044c \u043f\u0443\u0442\u0438 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0421\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <code>vue-cli<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <code>public<\/code> &#8212; \u0445\u0440\u0430\u043d\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 html \u0444\u0430\u0439\u043b \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0430 \u0442\u0430\u043a\u0436\u0435 <code>favicon.ico<\/code> \u0438\u043a\u043e\u043d\u043a\u0443, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0443\u044e \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u0445 \u044d\u0442\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u0418\u0442\u0430\u043a, \u0432\u0441\u0435 \u0441\u043e\u043f\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0444\u0430\u0439\u043b\u044b \u0438 \u0444\u0430\u0439\u043b\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043c\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438. \u041d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u0441\u0430\u043c\u043e\u043c\u0443 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u043c\u0443 &#8212; \u044d\u0442\u043e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <code>src<\/code>. \u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432\u0441\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u043d\u0430\u0448\u0435\u0433\u043e frontend \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041a\u0430\u043a \u0443\u0436\u0435 \u0433\u043e\u0432\u043e\u0440\u0438\u043b\u043e\u0441\u044c \u0432\u044b\u0448\u0435, \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <code>assets<\/code> \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u043d\u043e\u0433\u043e \u0440\u043e\u0434\u0430 \u0441\u0442\u0430\u0442\u0438\u043a\u0438 \u0438 \u0441\u0442\u0438\u043b\u0435\u0439, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0435\u0451 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b\u0430. \u0418\u0442\u0430\u043a, \u0441 \u043d\u0435\u0439 \u0432\u0441\u0451 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e. \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u043e\u0431\u0440\u0430\u0437\u0443\u044e\u0442 \u0432\u0441\u0435 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u043e\u0439\u0434\u0451\u043c\u0441\u044f \u043f\u043e \u043d\u0438\u043c.<\/p>\n<p>\u0422\u043e\u0447\u043a\u043e\u0439 \u0432\u0445\u043e\u0434\u0430 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0444\u0430\u0439\u043b <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/blob\/chapter-4.1\/j-sso\/client\/src\/main.js\" rel=\"noopener noreferrer nofollow\"><code>main.js<\/code><\/a>. \u0412 \u043d\u0451\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 <code>vue plugins<\/code>, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0445 \u0432 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f\u0445, \u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u0430\u043c\u043e\u0433\u043e <code>vue<\/code> \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/blob\/chapter-4.1\/j-sso\/client\/src\/App.vue\" rel=\"noopener noreferrer nofollow\"><code>App.vue<\/code><\/a> &#8212; \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043d\u0430\u0448\u0435\u0433\u043e SPA \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0432 <code>main.js<\/code>. \u0412 \u043d\u0451\u043c \u0443\u043a\u0430\u0437\u0430\u043d \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0448\u0430\u0431\u043b\u043e\u043d \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b:<\/p>\n<ul>\n<li>\n<p><code>&lt;j-exception\/><\/code> &#8212; \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043d\u0430\u0448 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 (\u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u043e 500-\u044b\u0445 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430).<\/p>\n<\/li>\n<li>\n<p><code>&lt;notifications group=\"main\"\/><\/code> &#8212; \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043c\u0435\u0441\u0442\u043e\u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u0430 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u044e\u0449\u0438\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p><code>&lt;router-view\/><\/code> &#8212; \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0437 <code>vue-router<\/code>.<\/p>\n<\/li>\n<\/ul>\n<p>\u041c\u043e\u0436\u043d\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 <code>App.vue<\/code> \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u0448\u0430\u0431\u043b\u043e\u043d wrapper \u0434\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438, \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u0443\u044e\u0449\u0438\u0435 \u0432 \u0441\u0435\u0431\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0440\u043e\u0443\u0442\u0438\u043d\u0433\u0430 \u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430. \u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <code>router<\/code> &#8212; \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u043e\u0434\u0438\u043d \u0444\u0430\u0439\u043b <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/blob\/chapter-4.1\/j-sso\/client\/src\/router\/index.js\" rel=\"noopener noreferrer nofollow\"><code>index.js<\/code><\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <code>vue-router<\/code>. \u0422\u0430\u043a\u0436\u0435 \u0432 \u043d\u0435\u0439 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 <code>Router<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u0444\u0430\u0439\u043b\u0435 <code>main.js<\/code>. \u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 <code>vue-router<\/code> \u043c\u043e\u0436\u043d\u043e \u043d\u0430 \u0438\u0445 <a href=\"https:\/\/router.vuejs.org\/guide\/\" rel=\"noopener noreferrer nofollow\">\u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u043c \u0441\u0430\u0439\u0442\u0435<\/a>.<\/p>\n<p>\u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <code>store<\/code> &#8212; \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u0444\u0430\u0439\u043b <a href=\"https:\/\/github.com\/dlabs71\/spring-authorization-server-example\/blob\/chapter-4.1\/j-sso\/client\/src\/store\/index.js\" rel=\"noopener noreferrer nofollow\"><code>index.js<\/code><\/a>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 <code>vuex<\/code>. \u0414\u0430\u043d\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043e \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043c\u0435\u0436\u0434\u0443 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430\u043c\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446. \u0412\u043d\u0443\u0442\u0440\u0438 \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>sessionStorage<\/code> \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0439 \u0432 \u043b\u044e\u0431\u043e\u043c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435. \u0422\u0430\u043a\u0436\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u043c\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u043f\u043b\u0430\u0433\u0438\u043d <code>VuexPersistence<\/code>&#8212; \u043e\u043d \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 (\u0442\u0430\u043a \u043a\u0430\u043a <code>sessionStorage<\/code> \u0431\u0443\u0434\u0435\u0442 \u043e\u0447\u0438\u0449\u0435\u043d \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043e\u043c). \u041e\u0431\u044b\u0447\u043d\u043e \u0442\u0430\u043a\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435: \u0435\u0433\u043e \u0442\u043e\u043a\u0435\u043d\u044b \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0438 \u0442.\u0434. \u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u043c\u043e\u0436\u043d\u043e \u0438 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u044d\u0442\u0443 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 <code>localStorage<\/code> \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430, \u0438\u043b\u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c <code>vuex<\/code>, \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0441\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 <code>localStorage<\/code>. \u041d\u043e \u043d\u0430\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0441\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e <code>sessionStorage<\/code>. \u0410 \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0438\u0437\u043e\u0431\u0440\u0435\u0442\u0430\u0442\u044c &#171;\u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434\u043e\u0432&#187;, \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u043b\u0430\u0433\u0438\u043d \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u0442\u0440\u043e\u0433\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043c\u0435\u0436\u0434\u0443 \u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430\u043c\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b.<\/p>\n<p>\u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <code>modules<\/code> \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c\u044b\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e <code>vuex<\/code>. \u042d\u0442\u0438 \u043c\u043e\u0434\u0443\u043b\u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0441\u043e\u0431\u043e\u0439 js \u0444\u0430\u0439\u043b\u044b, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u043f\u0438\u0441\u0430\u043d <\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-364567","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/364567","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=364567"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/364567\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=364567"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=364567"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=364567"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}