{"id":467509,"date":"2025-07-18T22:11:14","date_gmt":"2025-07-18T22:11:14","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=467509"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=467509","title":{"rendered":"<span>\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c \u0447\u0435\u0440\u0435\u0437 Keycloak: SSO \u0438 JWT \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438<\/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<h2>1. \u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435: \u041f\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u0434\u0430\u0447\u0438 \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435<\/h2>\n<p>\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u044c\u0442\u0435,\u00a0\u0447\u0442\u043e \u0432\u044b\u00a0\u2014\u00a0\u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0432 \u043a\u0440\u0443\u043f\u043d\u043e\u0439 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438,\u00a0\u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0435\u0439 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043c\u0430\u0433\u0430\u0437\u0438\u043d\u043e\u043c.\u00a0\u0423 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c:\u00a0\u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430\u00a0(\u0432\u0435\u0431-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430,\u00a0\u0433\u0434\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u044b \u043f\u0440\u043e\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u044e\u0442 \u0442\u043e\u0432\u0430\u0440\u044b \u0438 \u043e\u0444\u043e\u0440\u043c\u043b\u044f\u044e\u0442 \u0437\u0430\u043a\u0430\u0437\u044b),\u00a0\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043a\u0430\u0437\u043e\u0432\u00a0(backend,\u00a0\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u043a\u0430\u0437\u0430\u043c\u0438 \u0438 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u043e\u0439)\u00a0\u0438 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0434\u043b\u044f \u043e\u0442\u0447\u0451\u0442\u043e\u0432.\u00a0\u041f\u0440\u0438\u043b\u0435\u0442\u0430\u0435\u0442 \u0437\u0430\u0434\u0430\u0447\u0430:\u00a0\u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u0438\u0437 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430 \u043a \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 \u043e\u0431\u0449\u0435\u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 Keycloak\u00a0\u2014\u00a0\u0435\u0434\u0438\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438\u00a0(Identity Provider,\u00a0IdP).\u00a0\u0426\u0435\u043b\u044c\u00a0\u2014\u00a0\u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u044b \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430)\u00a0\u043c\u043e\u0433\u043b\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u00a0(\u0441\u043a\u0430\u0436\u0435\u043c,\u00a0\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u0442\u044c \u0437\u0430\u043a\u0430\u0437\u044b),\u00a0\u0430 JWT-\u0442\u043e\u043a\u0435\u043d,\u00a0\u0432\u044b\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u0439 Keycloak,\u00a0\u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b \u043d\u0443\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435,\u00a0\u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u0440\u043e\u043b\u044c\u00a0<code>order_manager<\/code>\u00a0\u0438\u043b\u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442 \u043e\u0442\u0434\u0435\u043b\u0430.<\/p>\n<p>\u042d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0441 \u043d\u0443\u043b\u044f,\u00a0\u0430 \u0442\u0438\u043f\u0438\u0447\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430:\u00a0\u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0432 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435,\u00a0\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c,\u00a0\u043a\u0430\u043a\u0438\u0435 \u0440\u043e\u043b\u0438 \u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u043d\u0443\u0436\u043d\u044b,\u00a0\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e.\u00a0\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0442\u043e\u043c,\u00a0\u0447\u0442\u043e \u0431\u0435\u0437 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f,\u00a0\u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 Keycloak \u0438 OIDC,\u00a0\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043c\u043e\u0436\u0435\u0442\u00a0&#171;\u0437\u0430\u043b\u0438\u043f\u043d\u0443\u0442\u044c&#187;.\u00a0\u0421 \u043a\u0435\u043c \u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f?\u00a0\u0421 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b,\u00a0\u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0442\u043e\u043a\u0435\u043d\u043e\u0432?\u00a0\u0421 \u0430\u0434\u043c\u0438\u043d\u0430\u043c\u0438 Keycloak,\u00a0\u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b\u0438 realm?\u00a0\u0421 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430\u043c\u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0437\u0430\u043a\u0430\u0437\u043e\u0432,\u00a0\u0447\u0442\u043e\u0431\u044b \u0443\u0442\u043e\u0447\u043d\u0438\u0442\u044c \u0440\u043e\u043b\u0438?\u00a0\u0418 \u0447\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u0442\u044c:\u00a0\u043a\u0430\u043a\u0438\u0435 scopes,\u00a0\u043a\u0430\u043a \u043c\u0430\u043f\u043f\u0438\u0442\u044c \u0440\u043e\u043b\u0438,\u00a0\u043a\u0430\u043a \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043a\u0435\u043d\u044b?\u00a0\u041d\u0435\u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0430\u043c,\u00a0\u043e\u0448\u0438\u0431\u043a\u0430\u043c \u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0430\u0445\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u0432\u0438\u0434\u0438\u0442 \u0447\u0443\u0436\u0438\u0435 \u0437\u0430\u043a\u0430\u0437\u044b)\u00a0\u0438\u043b\u0438 \u0434\u0430\u0436\u0435 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u044f\u043c.<\/p>\n<p>\u0426\u0435\u043b\u044c \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438\u00a0\u2014\u00a0\u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c,\u00a0\u043a\u0430\u043a \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u043c\u0443 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0443 \u043f\u043e\u0434\u043e\u0439\u0442\u0438 \u043a \u0442\u0430\u043a\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0435.\u00a0\u041c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u044b Single Sign-On\u00a0(SSO)\u00a0\u0438 OpenID Connect\u00a0(OIDC),\u00a0\u0438\u0437\u0443\u0447\u0438\u043c Keycloak \u043a\u0430\u043a \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0438\u0445 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438,\u00a0\u0438 \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u00a0(React-frontend,\u00a0Node.js-backend,\u00a0Docker)\u00a0\u043f\u043e\u043a\u0430\u0436\u0435\u043c,\u00a0\u043a\u0430\u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f.\u00a0\u0412 \u043a\u043e\u043d\u0446\u0435 \u0432\u0435\u0440\u043d\u0451\u043c\u0441\u044f \u043a \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0435 \u0438 \u043e\u0431\u044a\u044f\u0441\u043d\u0438\u043c,\u00a0\u043a\u0430\u043a \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c,\u00a0\u0447\u0442\u043e\u0431\u044b JWT \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b \u043d\u0443\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435,\u00a0\u0438 \u0447\u0442\u043e \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a.\u00a0\u042d\u0442\u043e \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u0448\u0438\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0443,\u00a0\u043d\u043e \u0438 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u0442\u0438\u043f\u0438\u0447\u043d\u044b\u0445 \u043e\u0448\u0438\u0431\u043e\u043a \u0432 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445.<\/p>\n<p>\u0414\u043b\u044f <strong>\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432<\/strong> \u0441\u0442\u0430\u0442\u044c\u044f \u0434\u0430\u0451\u0442 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 OIDC \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c PKCE \u0438 \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 JWT. \u042d\u0442\u043e \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0441\u0442\u0440\u043e \u0432\u043d\u0435\u0434\u0440\u0438\u0442\u044c SSO \u0431\u0435\u0437 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438. \u0414\u043b\u044f <strong>\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u043e\u0440\u043e\u0432<\/strong> \u0441\u0442\u0430\u0442\u044c\u044f \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442, \u043a\u0430\u043a Keycloak \u0432\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043d\u0443\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u044c (\u0447\u0435\u0440\u0435\u0437 PostgreSQL \u0438\u043b\u0438 Active Directory) \u0438 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c (PKCE, HTTPS). <\/p>\n<h2>2. \u041f\u0440\u0438\u043d\u0446\u0438\u043f\u044b SSO \u0438 OIDC<\/h2>\n<p>Single Sign-On\u00a0(SSO)\u00a0\u0438 OpenID Connect\u00a0(OIDC)\u00a0\u2014\u00a0\u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0438:\u00a0\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u0438\u0437 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b\u00a0(<code>reports-frontend<\/code>)\u00a0\u043a API \u043e\u0442\u0447\u0451\u0442\u043e\u0432\u00a0(<code>reports-api<\/code>)\u00a0\u0447\u0435\u0440\u0435\u0437 \u043e\u0431\u0449\u0435\u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 Keycloak,\u00a0\u0447\u0442\u043e\u0431\u044b JWT-\u0442\u043e\u043a\u0435\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b \u0440\u043e\u043b\u044c\u00a0<code>report_user<\/code>.\u00a0\u0412 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 e-commerce \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043a\u0430\u043a \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430,\u00a0\u0433\u0434\u0435 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u044b \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u044e\u0442 \u043e\u0442\u0447\u0451\u0442\u044b \u043e \u043f\u0440\u043e\u0434\u0430\u0436\u0430\u0445,\u00a0\u0430 Keycloak \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0435\u0439.\u00a0\u0414\u043b\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 SSO \u0438 OIDC \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u043e,\u00a0\u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0441\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0437\u0430\u044f\u0432\u043a\u0443 \u043d\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0438 \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u0442\u044c \u0441 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u043c\u0438\u00a0(\u0430\u0434\u043c\u0438\u043d\u044b Keycloak,\u00a0\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438,\u00a0\u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u044b API),\u00a0\u043a\u0430\u043a\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0432 \u0442\u043e\u043a\u0435\u043d\u0435.\u00a0\u0411\u0435\u0437 \u044d\u0442\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0437\u043d\u0430\u0442\u044c,\u00a0\u0447\u0442\u043e \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u0442\u044c\u00a0(\u0440\u043e\u043b\u0438,\u00a0\u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b)\u00a0\u0438 \u0441 \u043a\u0435\u043c,\u00a0\u0447\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u0442 \u043a \u043e\u0448\u0438\u0431\u043a\u0430\u043c,\u00a0\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u044e \u0440\u043e\u043b\u0438 \u0432 JWT.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u043d\u0430\u0447\u043d\u0451\u043c \u0441 \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u044b,\u00a0\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0435\u0439 \u043f\u043e\u0442\u043e\u043a OIDC:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6eb\/fe8\/d3f\/6ebfe8d3fa0d63acf28a7b776fdf9f82.png\" alt=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043b\u043e\u0433\u0438\u043d\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 Keycloak,\u00a0\u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0report_user,\u00a0\u0430 API \u043e\u0442\u0447\u0451\u0442\u043e\u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d,\u00a0\u0447\u0442\u043e\u0431\u044b \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0447\u0451\u0442\u0430.\" title=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043b\u043e\u0433\u0438\u043d\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 Keycloak,\u00a0\u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0report_user,\u00a0\u0430 API \u043e\u0442\u0447\u0451\u0442\u043e\u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d,\u00a0\u0447\u0442\u043e\u0431\u044b \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0447\u0451\u0442\u0430.\" width=\"1602\" height=\"855\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/6eb\/fe8\/d3f\/6ebfe8d3fa0d63acf28a7b776fdf9f82.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6eb\/fe8\/d3f\/6ebfe8d3fa0d63acf28a7b776fdf9f82.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043b\u043e\u0433\u0438\u043d\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 Keycloak,\u00a0\u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0<code>report_user<\/code>,\u00a0\u0430 API \u043e\u0442\u0447\u0451\u0442\u043e\u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d,\u00a0\u0447\u0442\u043e\u0431\u044b \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0447\u0451\u0442\u0430.<\/figcaption><\/div>\n<\/figure>\n<h4>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 SSO<\/h4>\n<p>SSO\u00a0(Single Sign-On)\u00a0\u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0432\u043e\u0439\u0442\u0438 \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a\u043e \u0432\u0441\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0451\u043d\u043d\u044b\u043c \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u043c \u0431\u0435\u0437 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0433\u043e \u0432\u0432\u043e\u0434\u0430 \u043b\u043e\u0433\u0438\u043d\u0430 \u0438 \u043f\u0430\u0440\u043e\u043b\u044f.\u00a0\u0412 \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0435 \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442,\u00a0\u0447\u0442\u043e \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u0432\u0445\u043e\u0434\u0438\u0442 \u0432\u00a0<code>reports-frontend<\/code>\u00a0\u0438 \u0441\u0440\u0430\u0437\u0443 \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0438\u0442\u044c \u043e\u0442\u0447\u0451\u0442\u044b \u0447\u0435\u0440\u0435\u0437\u00a0<code>reports-api<\/code>.\u00a0SSO:<\/p>\n<ul>\n<li>\n<p><strong>\u0423\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u043e\u043f\u044b\u0442<\/strong>: \u041e\u0434\u0438\u043d \u043b\u043e\u0433\u0438\u043d \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0441\u0438\u0441\u0442\u0435\u043c.<\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u043e\u0432\u044b\u0448\u0430\u0435\u0442 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c<\/strong>: \u0426\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 Keycloak.<\/p>\n<\/li>\n<li>\n<p><strong>\u0421\u043d\u0438\u0436\u0430\u0435\u0442 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443<\/strong>: \u041c\u0435\u043d\u044c\u0448\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 IT-\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443.<\/p>\n<\/li>\n<\/ul>\n<p>SSO \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 Identity Provider\u00a0(IdP),\u00a0\u0442\u0430\u043a\u043e\u0439 \u043a\u0430\u043a Keycloak,\u00a0\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u0432\u044b\u0434\u0430\u0451\u0442 \u0442\u043e\u043a\u0435\u043d\u044b.\u00a0\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043d\u044f\u0442\u044c,\u00a0\u043a\u0430\u043a\u0438\u0435 \u0440\u043e\u043b\u0438\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>report_user<\/code>)\u00a0\u043d\u0443\u0436\u043d\u044b \u0432 \u0442\u043e\u043a\u0435\u043d\u0435 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a API.<\/p>\n<h4>OpenID Connect (OIDC) \u0438 \u0435\u0433\u043e \u0440\u043e\u043b\u044c<\/h4>\n<p>OIDC\u00a0\u2014\u00a0\u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438,\u00a0\u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u043f\u043e\u0432\u0435\u0440\u0445 OAuth 2.0,\u00a0\u0440\u0435\u0448\u0430\u044e\u0449\u0438\u0439 \u0434\u0432\u0435 \u0437\u0430\u0434\u0430\u0447\u0438:<\/p>\n<ul>\n<li>\n<p><strong>\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/strong>: \u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u0435\u0442, \u043a\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>access1<\/code>).<\/p>\n<\/li>\n<li>\n<p><strong>\u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f<\/strong>: \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442, \u0447\u0442\u043e \u043e\u043d \u043c\u043e\u0436\u0435\u0442 \u0434\u0435\u043b\u0430\u0442\u044c (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043e\u0442\u0447\u0451\u0442\u0430\u043c \u0447\u0435\u0440\u0435\u0437\u00a0<code>report_user<\/code>).<\/p>\n<\/li>\n<\/ul>\n<p>OIDC \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 Authorization Code Flow:<\/p>\n<ol>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0437\u0430\u0445\u043e\u0434\u0438\u0442 \u0432\u00a0<code>reports-frontend<\/code>\u00a0\u0438 \u043a\u043b\u0438\u043a\u0430\u0435\u0442 &#171;\u0412\u043e\u0439\u0442\u0438&#187;.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u0430 Keycloak \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u043d\u0430.<\/p>\n<\/li>\n<li>\n<p>Keycloak \u0432\u044b\u0434\u0430\u0451\u0442 authorization code, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u043c\u0435\u043d\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 JWT-\u0442\u043e\u043a\u0435\u043d\u044b (ID Token \u0434\u043b\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438, Access Token \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430).<\/p>\n<\/li>\n<li>\n<p><code>reports-frontend<\/code>\u00a0\u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 Access Token \u043d\u0430\u00a0<code>\/reports<\/code>, \u0433\u0434\u0435 API \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0440\u043e\u043b\u044c\u00a0<code>report_user<\/code>.<\/p>\n<\/li>\n<\/ol>\n<p>\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u0442\u044c,\u00a0\u0447\u0442\u043e\u0431\u044b JWT \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b\u00a0<code>report_user<\/code>,\u00a0\u0438 \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c \u044d\u0442\u043e \u0441 \u0430\u0434\u043c\u0438\u043d\u0430\u043c\u0438 Keycloak \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 API.<\/p>\n<h4>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 JWT<\/h4>\n<p>JWT\u00a0(JSON Web Token)\u00a0\u2014\u00a0\u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u044b\u0439 \u0442\u043e\u043a\u0435\u043d \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON,\u00a0\u0432\u044b\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u0439 Keycloak.\u00a0\u041e\u043d \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0442\u0440\u0451\u0445 \u0447\u0430\u0441\u0442\u0435\u0439:\u00a0Header,\u00a0Payload,\u00a0Signature\u00a0(\u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u044b \u0442\u043e\u0447\u043a\u0430\u043c\u0438,\u00a0\u0437\u0430\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0432 base64).\u00a0Payload \u0432\u0430\u0436\u0435\u043d \u0434\u043b\u044f \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430,\u00a0\u0442\u0430\u043a \u043a\u0430\u043a \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442:<\/p>\n<ul>\n<li>\n<p><code>sub<\/code>: ID \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>access1<\/code>).<\/p>\n<\/li>\n<li>\n<p><code>name<\/code>,\u00a0<code>email<\/code>: \u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>access1@example.com<\/code>).<\/p>\n<\/li>\n<li>\n<p><code>realm_access.roles<\/code>: \u0420\u043e\u043b\u0438 \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 realm (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>[\"report_user\"]<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b: \u0415\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>department<\/code>), \u0438\u0445 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442 \u0447\u0435\u0440\u0435\u0437 \u043c\u0430\u043f\u043f\u0435\u0440\u044b \u0432 Keycloak.<\/p>\n<\/li>\n<\/ul>\n<p>\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0443\u0442\u043e\u0447\u043d\u0438\u0442\u044c \u0443 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0435\u0432 API,\u00a0\u043a\u0430\u043a\u0438\u0435 \u0440\u043e\u043b\u0438\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>report_user<\/code>)\u00a0\u043d\u0443\u0436\u043d\u044b \u0432 \u0442\u043e\u043a\u0435\u043d\u0435,\u00a0\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u044d\u0442\u043e \u0432 \u0437\u0430\u044f\u0432\u043a\u0435.<\/p>\n<h4>\u0421\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u0441 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430\u043c\u0438<\/h4>\n<p>OIDC\u00a0\u2014\u00a0\u043b\u0443\u0447\u0448\u0438\u0439 \u0432\u044b\u0431\u043e\u0440 \u0434\u043b\u044f \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439,\u00a0\u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a\u00a0<code>reports-frontend<\/code>:<\/p>\n<ul>\n<li>\n<p><strong>SAML<\/strong>: \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 XML, \u0441\u043b\u043e\u0436\u043d\u0435\u0435 \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435, \u0434\u043b\u044f \u0441\u0442\u0430\u0440\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c.<\/p>\n<\/li>\n<li>\n<p><strong>OAuth 2.0<\/strong>: \u0422\u043e\u043b\u044c\u043a\u043e \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f, \u0431\u0435\u0437 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>Kerberos<\/strong>: \u0414\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u0435\u0442\u0435\u0439, \u043d\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0432\u0435\u0431\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>OIDC \u043f\u0440\u043e\u0441\u0442 \u0432 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f JSON \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0435 Keycloak.<\/p>\n<h4>\u0420\u0438\u0441\u043a\u0438 \u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430<\/h4>\n<p>OIDC \u0443\u044f\u0437\u0432\u0438\u043c \u0431\u0435\u0437 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438:<\/p>\n<ul>\n<li>\n<p><strong>CSRF-\u0430\u0442\u0430\u043a\u0438<\/strong>: \u0417\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u043f\u043e\u0434\u0434\u0435\u043b\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441. \u0417\u0430\u0449\u0438\u0449\u0430\u0435\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u00a0<code>state<\/code>\u00a0(\u0441\u043b\u0443\u0447\u0430\u0439\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c\u0430\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c).<\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u0435\u0440\u0435\u0445\u0432\u0430\u0442 \u0442\u043e\u043a\u0435\u043d\u043e\u0432<\/strong>: \u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f HTTPS.<\/p>\n<\/li>\n<li>\n<p><strong>\u041e\u0448\u0438\u0431\u043a\u0438 \u0432 \u0442\u043e\u043a\u0435\u043d\u0435<\/strong>: \u0415\u0441\u043b\u0438\u00a0<code>report_user<\/code>\u00a0\u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442, \u0434\u043e\u0441\u0442\u0443\u043f \u043d\u0435 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/p>\n<\/li>\n<\/ul>\n<p>\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c:<\/p>\n<ul>\n<li>\n<p>\u0412\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u00a0<code>state<\/code>\u00a0\u0434\u043b\u044f \u0437\u0430\u0449\u0438\u0442\u044b.<\/p>\n<\/li>\n<li>\n<p>\u0420\u043e\u043b\u0438 \u0432 JWT (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>report_user<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u043e\u0432 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430 <a href=\"http:\/\/jwt.io\" rel=\"noopener noreferrer nofollow\">jwt.io<\/a>).<\/p>\n<\/li>\n<\/ul>\n<p>\u0411\u0435\u0437 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f OIDC \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0437\u043d\u0430\u0442\u044c,\u00a0\u0447\u0442\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0432 \u0437\u0430\u044f\u0432\u043a\u0443 \u0438\u043b\u0438 \u0441 \u043a\u0435\u043c \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c,\u00a0\u0447\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u0442 \u043a \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0430\u043c.<\/p>\n<h2>3. Keycloak \u043a\u0430\u043a \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 OIDC<\/h2>\n<p>Keycloak\u00a0\u2014\u00a0\u044d\u0442\u043e \u043c\u043e\u0449\u043d\u044b\u0439 open-source \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0435\u0439 \u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c\u00a0(Identity and Access Management,\u00a0IAM),\u00a0\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 Single Sign-On\u00a0(SSO)\u00a0\u0447\u0435\u0440\u0435\u0437 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b OpenID Connect\u00a0(OIDC).\u00a0\u0412 \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0435 Keycloak \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u043a\u0430\u043a \u043e\u0431\u0449\u0435\u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 Identity Provider\u00a0(IdP),\u00a0\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u044f \u0434\u043e\u0441\u0442\u0443\u043f \u0438\u0437 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u0432\u0435\u0431-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0434\u043b\u044f \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u043e\u0432)\u00a0\u043a \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043a\u0430\u0437\u043e\u0432.\u00a0Keycloak \u0431\u0435\u0440\u0451\u0442 \u043d\u0430 \u0441\u0435\u0431\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0432\u044b\u0434\u0430\u0447\u0443 JWT-\u0442\u043e\u043a\u0435\u043d\u043e\u0432 \u0441 \u0440\u043e\u043b\u044f\u043c\u0438\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>order_manager<\/code>)\u00a0\u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430\u043c\u0438\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>department: sales<\/code>).\u00a0\u0414\u043b\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430 \u044d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 Keycloak \u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438,\u00a0\u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u0438 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430\u043c\u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b,\u00a0\u0447\u0442\u043e\u0431\u044b \u0442\u043e\u043a\u0435\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b \u043d\u0443\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435,\u00a0\u0430 \u0434\u043e\u0441\u0442\u0443\u043f \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u043d\u0430\u0447\u043d\u0451\u043c \u0441 \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u044b,\u00a0\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0435\u0439,\u00a0\u043a\u0430\u043a Keycloak \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443 \u0437\u0430\u043a\u0430\u0437\u043e\u0432:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/00e\/7da\/cd8\/00e7dacd8f7fdd69e7413b4719d25fce.png\" alt=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0Keycloak \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 realm\u00a0(store-realm),\u00a0\u0433\u0434\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0438 \u0440\u043e\u043b\u0438.\u00a0\u0424\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430\u00a0(store-frontend)\u00a0\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u043f\u043e\u0441\u043b\u0435 \u043b\u043e\u0433\u0438\u043d\u0430,\u00a0\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0437\u0430\u043a\u0430\u0437\u043e\u0432\u00a0(orders-api)\u00a0\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d,\u00a0\u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f.\" title=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0Keycloak \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 realm\u00a0(store-realm),\u00a0\u0433\u0434\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0438 \u0440\u043e\u043b\u0438.\u00a0\u0424\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430\u00a0(store-frontend)\u00a0\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u043f\u043e\u0441\u043b\u0435 \u043b\u043e\u0433\u0438\u043d\u0430,\u00a0\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0437\u0430\u043a\u0430\u0437\u043e\u0432\u00a0(orders-api)\u00a0\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d,\u00a0\u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f.\" width=\"1092\" height=\"680\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/00e\/7da\/cd8\/00e7dacd8f7fdd69e7413b4719d25fce.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/00e\/7da\/cd8\/00e7dacd8f7fdd69e7413b4719d25fce.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0Keycloak \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 realm\u00a0(<code>store-realm<\/code>),\u00a0\u0433\u0434\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0438 \u0440\u043e\u043b\u0438.\u00a0\u0424\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430\u00a0(<code>store-frontend<\/code>)\u00a0\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u043f\u043e\u0441\u043b\u0435 \u043b\u043e\u0433\u0438\u043d\u0430,\u00a0\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0437\u0430\u043a\u0430\u0437\u043e\u0432\u00a0(<code>orders-api<\/code>)\u00a0\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d,\u00a0\u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f.<\/figcaption><\/div>\n<\/figure>\n<h4>\u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 Keycloak<\/h4>\n<p>Keycloak \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0437\u0430\u0434\u0430\u0447\u0443 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430 \u0432 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445,\u00a0\u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a \u043d\u0430\u0448 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043c\u0430\u0433\u0430\u0437\u0438\u043d:<\/p>\n<ul>\n<li>\n<p><strong>\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f<\/strong>: \u041f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 OIDC \u0434\u043b\u044f \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u044f JSON-\u0442\u043e\u043a\u0435\u043d\u044b (JWT) \u0441 \u0440\u043e\u043b\u044f\u043c\u0438 \u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>\u0413\u0438\u0431\u043a\u043e\u0441\u0442\u044c<\/strong>: \u041f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c SSO \u043c\u0435\u0436\u0434\u0443 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439 \u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u043e\u0439 \u0437\u0430\u043a\u0430\u0437\u043e\u0432, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441 Active Directory \u0438\u043b\u0438 Google.<\/p>\n<\/li>\n<li>\n<p><strong>\u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c<\/strong>: \u0412\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u044b, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0430\u0440\u043e\u043b\u0435\u0439, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 MFA \u0438 \u0437\u0430\u0449\u0438\u0442\u0430 \u043e\u0442 \u0430\u0442\u0430\u043a (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0435\u0440\u0435\u0437 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u00a0<code>state<\/code>).<\/p>\n<\/li>\n<li>\n<p><strong>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441<\/strong>: \u0412\u0435\u0431-\u0430\u0434\u043c\u0438\u043d\u043a\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0443 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u0440\u043e\u043b\u0438 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u0431\u0435\u0437 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p><strong>Open-source<\/strong>: \u0411\u0435\u0441\u043f\u043b\u0430\u0442\u0435\u043d, \u0441 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u043e\u043c \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c \u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b,\u00a0\u043a\u0430\u043a \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u0442\u043e\u043a\u0435\u043d\u044b,\u00a0\u0441 \u0430\u0434\u043c\u0438\u043d\u0430\u043c\u0438 Keycloak\u00a0\u2014\u00a0\u043a\u0430\u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0440\u043e\u043b\u0438 \u0432 realm,\u00a0\u0438 \u0441 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430\u043c\u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0437\u0430\u043a\u0430\u0437\u043e\u0432\u00a0\u2014\u00a0\u043a\u0430\u043a\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0443\u0436\u043d\u044b \u0432 JWT.<\/p>\n<h4>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b Keycloak<\/h4>\n<p>Keycloak \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432,\u00a0\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c,\u00a0\u0447\u0442\u043e\u0431\u044b \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438:<\/p>\n<ul>\n<li>\n<p><strong>Realms<\/strong>: \u0418\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 &#171;\u0434\u043e\u043c\u0435\u043d\u044b&#187; \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u0440\u043e\u043b\u0435\u0439 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>store-realm<\/code>\u00a0\u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430 \u0438 \u0438\u0445 \u0440\u043e\u043b\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>Clients<\/strong>: \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u044e\u0449\u0438\u0435\u0441\u044f \u043a Keycloak. \u0412 \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0435 \u044d\u0442\u043e\u00a0<code>store-frontend<\/code>\u00a0(\u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430) \u0438\u00a0<code>orders-api<\/code>\u00a0(\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0437\u0430\u043a\u0430\u0437\u043e\u0432). Clients \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442 redirect URI \u0438 scopes (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u0430\u043a\u0438\u0435 \u0440\u043e\u043b\u0438 \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0432 JWT).<\/p>\n<\/li>\n<li>\n<p><strong>Users \u0438 Roles<\/strong>: \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>access1<\/code>) \u0438 \u0438\u0445 \u0440\u043e\u043b\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>order_manager<\/code>). \u0420\u043e\u043b\u0438 \u0431\u044b\u0432\u0430\u044e\u0442 \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 realm \u0438\u043b\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p><strong>Flows<\/strong>: \u041d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438 \u043b\u043e\u0433\u0438\u043d\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0430\u0440\u043e\u043b\u044f \u0438\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 MFA.<\/p>\n<\/li>\n<\/ul>\n<p>\u042d\u0442\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0432\u043c\u0435\u0441\u0442\u0435:\u00a0realm \u0438\u0437\u043e\u043b\u0438\u0440\u0443\u0435\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438,\u00a0client \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442 \u0442\u043e\u043a\u0435\u043d\u044b,\u00a0\u0430 \u0440\u043e\u043b\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442 \u0434\u043e\u0441\u0442\u0443\u043f.\u00a0\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c,\u00a0\u0447\u0442\u043e\u0431\u044b\u00a0<code>order_manager<\/code>\u00a0\u043f\u043e\u043f\u0430\u043b\u0430 \u0432 JWT \u0434\u043b\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0437\u0430\u043a\u0430\u0437\u043e\u0432.<\/p>\n<h4>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0438 \u0431\u0430\u0437\u043e\u0432\u0430\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430<\/h4>\n<p>\u0414\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438\u043b\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 Keycloak \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 Docker \u0441 PostgreSQL \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445.\u00a0\u042d\u0442\u043e \u043d\u0435 \u0437\u0430\u0434\u0430\u0447\u0430 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430,\u00a0\u043d\u043e \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441,\u00a0\u0447\u0442\u043e\u0431\u044b \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c \u0435\u0433\u043e \u0441 DevOps \u0438\u043b\u0438 \u0430\u0434\u043c\u0438\u043d\u0430\u043c\u0438.\u00a0\u0412\u043e\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u00a0<code>docker-compose.yml<\/code>:<\/p>\n<pre><code class=\"yaml\">services:   keycloak_db:     image: postgres:14     environment:       POSTGRES_DB: keycloak_db       POSTGRES_USER: keycloak_user       POSTGRES_PASSWORD: keycloak_password     volumes:       - .\/postgres-keycloak-data:\/var\/lib\/postgresql\/data     ports:       - \"5433:5432\"     healthcheck:       test: [\"CMD-SHELL\", \"pg_isready -U keycloak_user -d keycloak_db\"]       interval: 5s       timeout: 5s       retries: 5    keycloak:     image: quay.io\/keycloak\/keycloak:21.1     environment:       KEYCLOAK_ADMIN: admin       KEYCLOAK_ADMIN_PASSWORD: admin       KC_DB: postgres       KC_DB_URL: jdbc:postgresql:\/\/keycloak_db:5432\/keycloak_db       KC_DB_USERNAME: keycloak_user       KC_DB_PASSWORD: keycloak_password     command:        - start-dev     ports:       - \"8080:8080\"     depends_on:       keycloak_db:         condition: service_healthy<\/code><\/pre>\n<p>\u0420\u0430\u0437\u0432\u0435\u0440\u043d\u0438\u0442\u0435 Keycloak \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439:<\/p>\n<pre><code class=\"bash\">docker compose up -d<\/code><\/pre>\n<ul>\n<li>\n<p><code>-d<\/code>\u00a0\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0432 \u0444\u043e\u043d\u043e\u0432\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435. \u0415\u0441\u043b\u0438 \u043f\u043e\u0440\u0442 8080 \u0437\u0430\u043d\u044f\u0442, \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e\u00a0<code>netstat -tuln<\/code>\u00a0(Linux) \u0438\u043b\u0438\u00a0<code>netstat -aon<\/code>\u00a0(Windows) \u0438 \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430\u00a0<code>8081:8080<\/code>.<\/p>\n<\/li>\n<li>\n<p>Keycloak \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043f\u043e\u00a0<a href=\"http:\/\/localhost:8080\" rel=\"noopener noreferrer nofollow\">http:\/\/localhost:8080<\/a>, \u043b\u043e\u0433\u0438\u043d\/\u043f\u0430\u0440\u043e\u043b\u044c:\u00a0<code>admin\/admin<\/code>.<\/p>\n<\/li>\n<\/ul>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d91\/6da\/89f\/d916da89fa04de1b8206454215f597fc.png\" width=\"1701\" height=\"974\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/d91\/6da\/89f\/d916da89fa04de1b8206454215f597fc.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d91\/6da\/89f\/d916da89fa04de1b8206454215f597fc.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u0414\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043c\u043e\u0436\u0435\u0442:<\/p>\n<ol>\n<li>\n<p>\u0412 \u0430\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u0438 \u0432\u044b\u0431\u0440\u0430\u0442\u044c &#171;Add realm&#187; \u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c\u00a0<code>store-realm<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0440\u043e\u043b\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>access1<\/code>\u00a0\u0441 \u0440\u043e\u043b\u044c\u044e\u00a0<code>order_manager<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u0442\u044c clients (<code>store-frontend<\/code>,\u00a0<code>orders-api<\/code>) \u0441 \u043d\u0443\u0436\u043d\u044b\u043c\u0438 redirect URI.<\/p>\n<\/li>\n<\/ol>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6c7\/ae7\/561\/6c7ae7561ed76f4b04bdc91f626dd2a2.png\" alt=\"\u0424\u043e\u0440\u043c\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e realm \u0432 \u0430\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u0438 Keycloak\" title=\"\u0424\u043e\u0440\u043c\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e realm \u0432 \u0430\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u0438 Keycloak\" width=\"1472\" height=\"936\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/6c7\/ae7\/561\/6c7ae7561ed76f4b04bdc91f626dd2a2.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6c7\/ae7\/561\/6c7ae7561ed76f4b04bdc91f626dd2a2.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0424\u043e\u0440\u043c\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e realm \u0432 \u0430\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u0438 Keycloak<\/figcaption><\/div>\n<\/figure>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d69\/06f\/5d8\/d6906f5d86e7f27169b45aa3c7735e69.png\" alt=\"\u0424\u043e\u0440\u043c\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e realm \u0432 \u0430\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u0438 Keycloakstore-realm\" title=\"\u0424\u043e\u0440\u043c\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e realm \u0432 \u0430\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u0438 Keycloakstore-realm\" width=\"1490\" height=\"853\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/d69\/06f\/5d8\/d6906f5d86e7f27169b45aa3c7735e69.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d69\/06f\/5d8\/d6906f5d86e7f27169b45aa3c7735e69.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0424\u043e\u0440\u043c\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e realm \u0432 \u0430\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u0438 Keycloak<code>store-realm<\/code><\/figcaption><\/div>\n<\/figure>\n<p>\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c \u0441 \u0430\u0434\u043c\u0438\u043d\u0430\u043c\u0438 Keycloak,\u00a0\u0447\u0442\u043e\u0431\u044b \u0440\u043e\u043b\u0438 \u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <code>department: sales<\/code>) \u0431\u044b\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u0432 JWT,\u00a0\u0438 \u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438\u00a0\u2014\u00a0\u0447\u0442\u043e\u0431\u044b \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u043b\u0430 \u0442\u043e\u043a\u0435\u043d\u044b.<\/p>\n<h2>4. \u041f\u043e\u0433\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0432 realms Keycloak<\/h2>\n<p>Realms\u00a0(\u0434\u043e\u043c\u0435\u043d\u044b)\u00a0\u0432 Keycloak\u00a0\u2014\u00a0\u044d\u0442\u043e \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438,\u00a0\u0440\u043e\u043b\u044f\u043c\u0438 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c\u0438.\u00a0\u041e\u043d\u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c,\u00a0\u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430 \u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u0432 \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0435.\u00a0\u041a\u0430\u0436\u0434\u044b\u0439 realm \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u0432\u043e\u0438\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>access1<\/code>),\u00a0\u0440\u043e\u043b\u0438\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>order_manager<\/code>)\u00a0\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>store-frontend<\/code>,\u00a0<code>orders-api<\/code>),\u00a0\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c \u0438 \u043f\u043e\u0440\u044f\u0434\u043e\u043a.\u00a0\u0414\u043b\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430 realms\u00a0\u2014\u00a0\u043a\u043b\u044e\u0447 \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0430:\u00a0\u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c,\u00a0\u043a\u0430\u043a\u0438\u0435 \u0440\u043e\u043b\u0438 \u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u043f\u043e\u043f\u0430\u0434\u0443\u0442 \u0432 JWT-\u0442\u043e\u043a\u0435\u043d,\u00a0\u0438 \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e \u0441 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430\u043c\u0438 Keycloak \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u043d\u0430\u0447\u043d\u0451\u043c \u0441 \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u044b,\u00a0\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0435\u0439,\u00a0\u043a\u0430\u043a realms \u0438\u0437\u043e\u043b\u0438\u0440\u0443\u044e\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u044e\u0442 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/800\/5c8\/4d8\/8005c84d839c453c28b35d388e59d2a5.png\" alt=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0Keycloak \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u0432\u0443\u043c\u044f realms\u00a0(store-realm\u00a0\u0434\u043b\u044f \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430,\u00a0orders-realm\u00a0\u0434\u043b\u044f \u0437\u0430\u043a\u0430\u0437\u043e\u0432).\u00a0\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u00a0access1\u00a0\u0438\u0437\u00a0store-realm\u00a0\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0order_manager,\u00a0\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 \u043a\u043b\u0438\u0435\u043d\u0442\u00a0orders-api.\u00a0\u0424\u0435\u0434\u0435\u0440\u0430\u0446\u0438\u044f \u043c\u0435\u0436\u0434\u0443 realms \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c SSO.  \" title=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0Keycloak \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u0432\u0443\u043c\u044f realms\u00a0(store-realm\u00a0\u0434\u043b\u044f \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430,\u00a0orders-realm\u00a0\u0434\u043b\u044f \u0437\u0430\u043a\u0430\u0437\u043e\u0432).\u00a0\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u00a0access1\u00a0\u0438\u0437\u00a0store-realm\u00a0\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0order_manager,\u00a0\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 \u043a\u043b\u0438\u0435\u043d\u0442\u00a0orders-api.\u00a0\u0424\u0435\u0434\u0435\u0440\u0430\u0446\u0438\u044f \u043c\u0435\u0436\u0434\u0443 realms \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c SSO.  \" width=\"1486\" height=\"731\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/800\/5c8\/4d8\/8005c84d839c453c28b35d388e59d2a5.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/800\/5c8\/4d8\/8005c84d839c453c28b35d388e59d2a5.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0Keycloak \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u0432\u0443\u043c\u044f realms\u00a0(<code>store-realm<\/code>\u00a0\u0434\u043b\u044f \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430,\u00a0<code>orders-realm<\/code>\u00a0\u0434\u043b\u044f \u0437\u0430\u043a\u0430\u0437\u043e\u0432).\u00a0\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u00a0<code>access1<\/code>\u00a0\u0438\u0437\u00a0<code>store-realm<\/code>\u00a0\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0<code>order_manager<\/code>,\u00a0\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 \u043a\u043b\u0438\u0435\u043d\u0442\u00a0<code>orders-api<\/code>.\u00a0\u0424\u0435\u0434\u0435\u0440\u0430\u0446\u0438\u044f \u043c\u0435\u0436\u0434\u0443 realms \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c SSO.  <\/figcaption><\/div>\n<\/figure>\n<h4>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 realms \u0438 \u0437\u0430\u0447\u0435\u043c \u043e\u043d\u0438 \u043d\u0443\u0436\u043d\u044b<\/h4>\n<p>Realm\u00a0\u2014\u00a0\u044d\u0442\u043e\u00a0&#171;\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440&#187;\u00a0\u0432 Keycloak,\u00a0\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0437\u043e\u043b\u0438\u0440\u0443\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438.\u00a0\u0411\u0435\u0437 realms \u0432\u0441\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u044b \u0441\u043c\u0435\u0448\u0438\u0432\u0430\u043b\u0438\u0441\u044c \u0431\u044b,\u00a0\u0447\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u043b\u043e \u0431\u044b \u043a \u0445\u0430\u043e\u0441\u0443 \u0438 \u0440\u0438\u0441\u043a\u0430\u043c\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430 \u043c\u043e\u0433 \u0431\u044b \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0435).\u00a0\u0412 \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0435 realms \u0440\u0435\u0448\u0430\u044e\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b:<\/p>\n<ul>\n<li>\n<p><strong>\u0418\u0437\u043e\u043b\u044f\u0446\u0438\u044f<\/strong>: \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0438 \u0440\u043e\u043b\u0438\u00a0<code>store-realm<\/code>\u00a0\u043d\u0435 \u043f\u0435\u0440\u0435\u0441\u0435\u043a\u0430\u044e\u0442\u0441\u044f \u0441\u00a0<code>orders-realm<\/code>, \u0447\u0442\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e.<\/p>\n<\/li>\n<li>\n<p><strong>\u0413\u0438\u0431\u043a\u043e\u0441\u0442\u044c<\/strong>: \u041a\u0430\u0436\u0434\u044b\u0439 realm \u043c\u043e\u0436\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0441\u0432\u043e\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043b\u043e\u0433\u0438\u043d\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, MFA \u0434\u043b\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0437\u0430\u043a\u0430\u0437\u043e\u0432).<\/p>\n<\/li>\n<li>\n<p><strong>\u0424\u0435\u0434\u0435\u0440\u0430\u0446\u0438\u044f<\/strong>: Realms \u043c\u043e\u0433\u0443\u0442 \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f SSO, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044f \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0443 \u0438\u0437\u00a0<code>store-realm<\/code>\u00a0\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0437\u0430\u043a\u0430\u0437\u0430\u043c\u0438 \u0432\u00a0<code>orders-realm<\/code>.<\/p>\n<\/li>\n<li>\n<p><strong>\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435<\/strong>: \u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0440\u043e\u043b\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>order_manager<\/code>) \u0432 \u043e\u0434\u043d\u043e\u043c realm \u0438 \u043c\u0430\u043f\u043f\u0438\u0442\u044c \u0438\u0445 \u0432 \u0434\u0440\u0443\u0433\u043e\u043c.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u043b\u044f \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430 realms\u00a0\u2014\u00a0\u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430.\u00a0\u041e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c \u0441 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430\u043c\u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b,\u00a0\u043a\u0430\u043a\u0438\u0435 \u0440\u043e\u043b\u0438 \u043d\u0443\u0436\u043d\u044b\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>edit_orders<\/code>\u00a0\u0434\u043b\u044f \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f \u0437\u0430\u043a\u0430\u0437\u043e\u0432),\u00a0\u0438 \u0441 \u0430\u0434\u043c\u0438\u043d\u0430\u043c\u0438 Keycloak\u00a0\u2014\u00a0\u043a\u0430\u043a \u0438\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c.<\/p>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 realms<\/h4>\n<p>Realms \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0434\u0432\u0443\u043c\u044f \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438:\u00a0\u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0447\u0435\u0440\u0435\u0437 \u0430\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u044c Keycloak \u0438\u043b\u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 \u0438\u043c\u043f\u043e\u0440\u0442 JSON-\u0444\u0430\u0439\u043b\u0430.\u00a0\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0447\u0430\u0449\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u0430\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u044c\u044e,\u00a0\u0442\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<h3>\u0420\u0443\u0447\u043d\u0430\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430<\/h3>\n<ol>\n<li>\n<p>\u0417\u0430\u0439\u0434\u0438\u0442\u0435 \u0432 \u0430\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u044c Keycloak (<a href=\"http:\/\/localhost:8080\" rel=\"noopener noreferrer nofollow\">http:\/\/localhost:8080<\/a>, \u043b\u043e\u0433\u0438\u043d\/\u043f\u0430\u0440\u043e\u043b\u044c:\u00a0<code>admin\/admin<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0436\u043c\u0438\u0442\u0435 &#171;Add realm&#187; (\u0438\u043b\u0438 &#171;Create Realm&#187;) \u0432 \u043b\u0435\u0432\u043e\u043c \u043c\u0435\u043d\u044e.<\/p>\n<\/li>\n<li>\n<p>\u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u0438\u043c\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>store-realm<\/code>) \u0438 \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u0435 (Enabled: true).<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/aa4\/fd4\/cfa\/aa4fd4cfadb3a7c7b2974c8634304c6c.png\" width=\"2094\" height=\"827\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/aa4\/fd4\/cfa\/aa4fd4cfadb3a7c7b2974c8634304c6c.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/aa4\/fd4\/cfa\/aa4fd4cfadb3a7c7b2974c8634304c6c.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u0412 \u043d\u043e\u0432\u043e\u043c realm \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435:<\/p>\n<ul>\n<li>\n<p><strong>Users<\/strong>: \u0412 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 &#171;Users&#187; \u2192 &#171;Add user&#187; \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>access1<\/code>, email:\u00a0<code>access1@example.com<\/code>). \u0412 &#171;Credentials&#187; \u0437\u0430\u0434\u0430\u0439\u0442\u0435 \u043f\u0430\u0440\u043e\u043b\u044c (<code>accesspass1<\/code>, temporary: false).<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/99f\/00e\/d27\/99f00ed27ba32630ba5deb0a4455ab14.png\" width=\"2163\" height=\"908\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/99f\/00e\/d27\/99f00ed27ba32630ba5deb0a4455ab14.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/99f\/00e\/d27\/99f00ed27ba32630ba5deb0a4455ab14.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c8c\/0f8\/58d\/c8c0f858dbe25dc8d18d26ff9c16b6d6.png\" width=\"1651\" height=\"713\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/c8c\/0f8\/58d\/c8c0f858dbe25dc8d18d26ff9c16b6d6.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c8c\/0f8\/58d\/c8c0f858dbe25dc8d18d26ff9c16b6d6.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<\/li>\n<li>\n<p><strong>Roles<\/strong>: \u0412 &#171;Realm Roles&#187; \u2192 &#171;Create role&#187; \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0440\u043e\u043b\u044c\u00a0<code>order_manager<\/code>\u00a0\u0441 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c &#171;Manager for order operations&#187;.<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/1e1\/a3c\/62c\/1e1a3c62c1eb6199be0c237acb3be8e8.png\" width=\"2053\" height=\"806\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/1e1\/a3c\/62c\/1e1a3c62c1eb6199be0c237acb3be8e8.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/1e1\/a3c\/62c\/1e1a3c62c1eb6199be0c237acb3be8e8.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/125\/98f\/770\/12598f770b0d8cdfa61a2aa6e1dea724.png\" width=\"1937\" height=\"680\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/125\/98f\/770\/12598f770b0d8cdfa61a2aa6e1dea724.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/125\/98f\/770\/12598f770b0d8cdfa61a2aa6e1dea724.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<\/li>\n<li>\n<p><strong>Clients<\/strong>: \u0412 &#171;Clients&#187; \u2192 &#171;Create client&#187; \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u00a0<code>store-frontend<\/code>\u00a0(publicClient: true, redirectUris:\u00a0<a href=\"http:\/\/localhost:3000\/*\" rel=\"noopener noreferrer nofollow\"><code>http:\/\/localhost:3000\/*<\/code><\/a>) \u0438\u00a0<code>orders-api<\/code>\u00a0(bearerOnly: true).<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/518\/fca\/660\/518fca6607fd3e748782e91b5db32942.png\" width=\"1950\" height=\"1004\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/518\/fca\/660\/518fca6607fd3e748782e91b5db32942.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/518\/fca\/660\/518fca6607fd3e748782e91b5db32942.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/e61\/9ae\/516\/e619ae516a0994eb2b56a94654c66954.png\" width=\"2107\" height=\"941\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/e61\/9ae\/516\/e619ae516a0994eb2b56a94654c66954.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/e61\/9ae\/516\/e619ae516a0994eb2b56a94654c66954.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<\/li>\n<li>\n<p><strong>Role Mappings<\/strong>: \u0412 &#171;Users&#187; \u2192\u00a0<code>access1<\/code>\u00a0\u2192 &#171;Role Mappings&#187; \u043f\u0440\u0438\u0441\u0432\u043e\u0439\u0442\u0435 \u0440\u043e\u043b\u044c\u00a0<code>order_manager<\/code>.<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/57d\/548\/b52\/57d548b524fd0b61c9dfee56bcbd3756.png\" width=\"1923\" height=\"811\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/57d\/548\/b52\/57d548b524fd0b61c9dfee56bcbd3756.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/57d\/548\/b52\/57d548b524fd0b61c9dfee56bcbd3756.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/524\/c76\/82a\/524c7682a29697c4bcf26782916da708.png\" width=\"2123\" height=\"928\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/524\/c76\/82a\/524c7682a29697c4bcf26782916da708.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/524\/c76\/82a\/524c7682a29697c4bcf26782916da708.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/410\/ab0\/f8b\/410ab0f8b3cc724ae45d3e240ca7e6f5.png\" width=\"1960\" height=\"860\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/410\/ab0\/f8b\/410ab0f8b3cc724ae45d3e240ca7e6f5.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/410\/ab0\/f8b\/410ab0f8b3cc724ae45d3e240ca7e6f5.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 \u0438\u043c\u043f\u043e\u0440\u0442 JSON<\/h4>\n<p>\u0414\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u0432 CI\/CD)\u00a0\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c JSON-\u0444\u0430\u0439\u043b \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439 realm \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0435\u0433\u043e \u0430\u0434\u043c\u0438\u043d\u0430\u043c Keycloak.\u00a0\u041f\u0440\u0438\u043c\u0435\u0440 \u0434\u043b\u044f\u00a0<code>store-realm<\/code>:<\/p>\n<pre><code class=\"json\">{   \"realm\": \"store-realm\",   \"enabled\": true,   \"roles\": {     \"realm\": [       {         \"name\": \"order_manager\",         \"description\": \"Manager for order operations\"       }     ]   },   \"users\": [     {       \"username\": \"access1\",       \"enabled\": true,       \"email\": \"access1@example.com\",       \"credentials\": [         {           \"type\": \"password\",           \"value\": \"accesspass1\",           \"temporary\": false         }       ],       \"realmRoles\": [\"order_manager\"]     }   ],   \"clients\": [     {       \"clientId\": \"store-frontend\",       \"enabled\": true,       \"publicClient\": true,       \"redirectUris\": [\"http:\/\/localhost:3000\/*\"]     },     {       \"clientId\": \"orders-api\",       \"enabled\": true,       \"clientAuthenticatorType\": \"client-secret\",       \"secret\": \"oNwoLQdvJAvRcL89SydqCWCe5ry1jMgq\",       \"bearerOnly\": true     }   ] } <\/code><\/pre>\n<p>\u0418\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0439\u0442\u0435 \u0444\u0430\u0439\u043b:\u00a0\u0432 \u0430\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u0438 \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435\u00a0&#171;Import&#187;\u00a0\u2192\u00a0\u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u0435 JSON\u00a0\u2192\u00a0\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0435.<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/7e5\/99a\/253\/7e599a25305b7bd35b5bf290bc5ed4b4.png\" alt=\"\u0420\u0430\u0437\u0434\u0435\u043b &quot;Import&quot; \u0432 \u0430\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u0438 Keycloak\" title=\"\u0420\u0430\u0437\u0434\u0435\u043b &quot;Import&quot; \u0432 \u0430\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u0438 Keycloak\" width=\"2249\" height=\"1025\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/7e5\/99a\/253\/7e599a25305b7bd35b5bf290bc5ed4b4.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/7e5\/99a\/253\/7e599a25305b7bd35b5bf290bc5ed4b4.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0420\u0430\u0437\u0434\u0435\u043b &#171;Import&#187; \u0432 \u0430\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u0438 Keycloak<\/figcaption><\/div>\n<\/figure>\n<h4>\u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u043b\u043e\u0433\u0438\u043d\u043e\u0432 \u0438 \u043f\u0430\u0440\u043e\u043b\u0435\u0439 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 \u0436\u0438\u0437\u043d\u0438<\/h4>\n<p>\u0412 production-\u0441\u0440\u0435\u0434\u0430\u0445 \u043b\u043e\u0433\u0438\u043d\u044b \u0438 \u043f\u0430\u0440\u043e\u043b\u0438 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e:<\/p>\n<ul>\n<li>\n<p><strong>\u0425\u0440\u0430\u043d\u0435\u043d\u0438\u0435<\/strong>: \u041f\u0430\u0440\u043e\u043b\u0438 \u0445\u044d\u0448\u0438\u0440\u0443\u044e\u0442\u0441\u044f (PBKDF2 \u0438\u043b\u0438 Argon2). \u0412 JSON-\u0444\u0430\u0439\u043b\u0435 \u043e\u043d\u0438 \u0432 plain-text \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0438\u043c\u043f\u043e\u0440\u0442\u0430; \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u2014 \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u044b.<\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0430<\/strong>: \u041b\u043e\u0433\u0438\u043d\u044b\/\u043f\u0430\u0440\u043e\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u043f\u043e HTTPS. \u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e Keycloak \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d \u043d\u0430 SSL (\u0432 production \u044d\u0442\u043e \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e).<\/p>\n<\/li>\n<li>\n<p><strong>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f<\/strong>: \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043c\u043e\u0433\u0443\u0442 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 Keycloak (\u0441 email-\u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0435\u0439) \u0438\u043b\u0438 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0438\u0437 Active Directory (\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435). \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u044b \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0438\u0437 AD, \u0430 \u0438\u0445 \u0440\u043e\u043b\u0438 \u043c\u0430\u043f\u043f\u044f\u0442\u0441\u044f \u0432\u00a0<code>store-realm<\/code>.<\/p>\n<\/li>\n<li>\n<p><strong>\u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c<\/strong>: \u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0438 \u043f\u0430\u0440\u043e\u043b\u0435\u0439 (\u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043b\u0438\u043d\u0430, expiration) \u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 MFA \u0434\u043b\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0437\u0430\u043a\u0430\u0437\u043e\u0432. \u041f\u0430\u0440\u043e\u043b\u0438 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 secrets (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>KEYCLOAK_ADMIN_PASSWORD<\/code>\u00a0\u0432 Docker) \u0438\u043b\u0438 HashiCorp Vault.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u043b\u044f \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c,\u00a0\u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u00a0<code>access1<\/code>\u00a0\u043f\u043e\u043b\u0443\u0447\u0438\u043b \u0440\u043e\u043b\u044c\u00a0<code>order_manager<\/code>\u00a0\u0432\u00a0<code>store-realm<\/code>,\u00a0\u0430 JWT-\u0442\u043e\u043a\u0435\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b \u044d\u0442\u0443 \u0440\u043e\u043b\u044c \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a\u00a0<code>orders-api<\/code>.<\/p>\n<h4>\u0421\u0445\u0435\u043c\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0440\u043e\u043b\u0435\u0439 \u0432 realm<\/h4>\n<p>\u0412\u043e\u0442 \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430,\u00a0\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0430\u044f,\u00a0\u043a\u0430\u043a \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 \u0440\u043e\u043b\u0438 \u0432 realm:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ea4\/8ef\/c67\/ea48efc673898fdb8fb8f7d54388d0d6.png\" alt=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441:\u00a0\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 realm,\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0440\u043e\u043b\u0438,\u00a0\u0430 \u0437\u0430\u0442\u0435\u043c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0438\u0440\u0443\u0435\u0442 \u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438,\u00a0\u0447\u0442\u043e\u0431\u044b JWT \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b \u043d\u0443\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.  \" title=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441:\u00a0\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 realm,\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0440\u043e\u043b\u0438,\u00a0\u0430 \u0437\u0430\u0442\u0435\u043c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0438\u0440\u0443\u0435\u0442 \u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438,\u00a0\u0447\u0442\u043e\u0431\u044b JWT \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b \u043d\u0443\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.  \" width=\"1393\" height=\"799\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/ea4\/8ef\/c67\/ea48efc673898fdb8fb8f7d54388d0d6.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ea4\/8ef\/c67\/ea48efc673898fdb8fb8f7d54388d0d6.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441:\u00a0\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 realm,\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0440\u043e\u043b\u0438,\u00a0\u0430 \u0437\u0430\u0442\u0435\u043c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0438\u0440\u0443\u0435\u0442 \u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438,\u00a0\u0447\u0442\u043e\u0431\u044b JWT \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b \u043d\u0443\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.  <\/figcaption><\/div>\n<\/figure>\n<h2>5. \u0425\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0432 Keycloak<\/h2>\n<p>Keycloak \u0445\u0440\u0430\u043d\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439\u00a0(\u043b\u043e\u0433\u0438\u043d\u044b,\u00a0\u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u0430\u0440\u043e\u043b\u0438,\u00a0\u0440\u043e\u043b\u0438,\u00a0email)\u00a0\u0432 \u0440\u0430\u043c\u043a\u0430\u0445 realms,\u00a0\u0447\u0442\u043e\u0431\u044b \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e.\u00a0\u0412 \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0435\u00a0\u2014\u00a0\u0434\u043e\u0441\u0442\u0443\u043f \u0438\u0437 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b\u00a0(<code>reports-frontend<\/code>)\u00a0\u043a API \u043e\u0442\u0447\u0451\u0442\u043e\u0432\u00a0(<code>reports-api<\/code>)\u00a0\u0441 JWT,\u00a0\u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u043c \u0440\u043e\u043b\u044c\u00a0<code>report_user<\/code>\u00a0\u2014\u00a0\u0432\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u044c,\u00a0\u0433\u0434\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>access1<\/code>)\u00a0\u0438 \u043a\u0430\u043a \u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0435\u00a0(\u0440\u043e\u043b\u044c\u00a0<code>report_user<\/code>)\u00a0\u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442 \u0432 \u0442\u043e\u043a\u0435\u043d.\u00a0\u0412 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 e-commerce \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043a\u0430\u043a \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u043e\u0432 \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430,\u00a0\u0447\u044c\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u043e.\u00a0Keycloak \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0434\u0432\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043f\u043e\u0434\u0445\u043e\u0434\u0430:\u00a0\u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0432 PostgreSQL\u00a0(\u0442\u0438\u043f\u0438\u0447\u043d\u044b\u0439 \u0432\u044b\u0431\u043e\u0440 \u0434\u043b\u044f \u043c\u043d\u043e\u0433\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432)\u00a0\u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e \u0441 Active Directory\u00a0(AD)\u00a0\u0438\u043b\u0438 LDAP \u0434\u043b\u044f \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c.\u00a0\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0432 \u0437\u0430\u044f\u0432\u043a\u0435,\u00a0\u043e\u0442\u043a\u0443\u0434\u0430 \u0431\u0440\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u043a\u0430\u043a\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0432 JWT,\u00a0\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0438\u0440\u0443\u044f \u0441 \u0430\u0434\u043c\u0438\u043d\u0430\u043c\u0438 Keycloak,\u00a0\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u0438 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430\u043c\u0438 API.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u043d\u0430\u0447\u043d\u0451\u043c \u0441 \u043e\u0431\u0449\u0435\u0439 \u0441\u0445\u0435\u043c\u044b,\u00a0\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0435\u0439,\u00a0\u043a\u0430\u043a \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0441\u0432\u044f\u0437\u0430\u043d\u044b \u0441 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430\u043c\u0438:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f50\/6e5\/a97\/f506e5a97d20311296a3ab5b780b2cf0.png\" alt=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0Keycloak \u0445\u0440\u0430\u043d\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u00a0reports-realm,\u00a0\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f PostgreSQL \u0438\u043b\u0438 AD.\u00a0\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u00a0access1\u00a0\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0report_user,\u00a0\u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f\u00a0reports-api.\" title=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0Keycloak \u0445\u0440\u0430\u043d\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u00a0reports-realm,\u00a0\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f PostgreSQL \u0438\u043b\u0438 AD.\u00a0\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u00a0access1\u00a0\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0report_user,\u00a0\u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f\u00a0reports-api.\" width=\"1788\" height=\"543\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/f50\/6e5\/a97\/f506e5a97d20311296a3ab5b780b2cf0.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f50\/6e5\/a97\/f506e5a97d20311296a3ab5b780b2cf0.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0Keycloak \u0445\u0440\u0430\u043d\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u00a0<code>reports-realm<\/code>,\u00a0\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f PostgreSQL \u0438\u043b\u0438 AD.\u00a0\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u00a0<code>access1<\/code>\u00a0\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0<code>report_user<\/code>,\u00a0\u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f\u00a0<code>reports-api<\/code>.<\/figcaption><\/div>\n<\/figure>\n<h4>1. \u041b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0432 PostgreSQL<\/h4>\n<p>Keycloak \u0447\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 PostgreSQL \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439,\u00a0\u0440\u043e\u043b\u0435\u0439 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432.\u00a0\u0414\u0430\u043d\u043d\u044b\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u0445:<\/p>\n<ul>\n<li>\n<p><strong>Users<\/strong>: \u041b\u043e\u0433\u0438\u043d\u044b, email (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>access1<\/code>,\u00a0<code>access1@example.com<\/code>).<\/p>\n<\/li>\n<li>\n<p><strong>Credentials<\/strong>: \u0425\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u0430\u0440\u043e\u043b\u0438 (\u0441 PBKDF2 \u0438\u043b\u0438 Argon2 \u0434\u043b\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438).<\/p>\n<\/li>\n<li>\n<p><strong>Roles<\/strong>: \u0420\u043e\u043b\u0438 \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 realm (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>report_user<\/code>).<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u041f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e \u0432\u0430\u0436\u043d\u043e<\/strong>:\u00a0PostgreSQL\u00a0\u2014\u00a0\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0432\u044b\u0431\u043e\u0440 \u0434\u043b\u044f \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u043e\u0432 \u0438\u043b\u0438 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438.\u00a0\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0438 \u0440\u043e\u043b\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <code>access1<\/code> \u0441 <code>report_user<\/code>) \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u0431\u0430\u0437\u0435 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f JWT.<\/p>\n<p><strong>\u041f\u0440\u0438\u043c\u0435\u0440 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438<\/strong>:\u00a0\u0412 Keycloak \u0437\u0430\u0434\u0430\u0451\u0442\u0441\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a PostgreSQL \u0447\u0435\u0440\u0435\u0437 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0432\u0440\u043e\u0434\u0435\u00a0<code>KC_DB_URL<\/code>.\u00a0\u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441 Docker \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u0430 \u0432 \u0447\u0430\u0441\u0442\u0438 8.<\/p>\n<p><strong>\u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430<\/strong>:\u00a0\u041f\u0440\u043e\u0441\u0442\u043e\u0442\u0430,\u00a0\u0432\u0441\u0451 \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435.\u00a0<strong>\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438<\/strong>:\u00a0\u041d\u0435 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0442\u044b\u0441\u044f\u0447 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439,\u00a0\u0435\u0434\u0438\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u043e\u0442\u043a\u0430\u0437\u0430.<\/p>\n<p><strong>\u0421\u0445\u0435\u043c\u0430 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0432 PostgreSQL<\/strong>:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c20\/299\/895\/c20299895d602dc67f4782a212943a9e.png\" width=\"916\" height=\"380\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/c20\/299\/895\/c20299895d602dc67f4782a212943a9e.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c20\/299\/895\/c20299895d602dc67f4782a212943a9e.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<h4>2. \u0420\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435<\/h4>\n<p>\u0414\u043b\u044f \u043a\u0440\u0443\u043f\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c \u0441 \u0442\u044b\u0441\u044f\u0447\u0430\u043c\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 Keycloak \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u0441 PostgreSQL \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u0431\u0430\u0437\u0430\u043c\u0438\u00a0(MySQL,\u00a0Oracle)\u00a0\u0447\u0435\u0440\u0435\u0437 Infinispan\u00a0(\u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u043a\u044d\u0448 Keycloak):<\/p>\n<ul>\n<li>\n<p><strong>Infinispan<\/strong>: \u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043c\u0435\u0436\u0434\u0443 \u043d\u043e\u0434\u0430\u043c\u0438 Keycloak.<\/p>\n<\/li>\n<li>\n<p><strong>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430<\/strong>: \u0422\u0440\u0435\u0431\u0443\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043d\u043e\u0434 Keycloak \u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a\u044d\u0448\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>KC_CACHE=ispn<\/code>).<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u041f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e \u0432\u0430\u0436\u043d\u043e<\/strong>:\u00a0\u041e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u044c \u0434\u043b\u044f \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u043e\u0432 \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430).<\/p>\n<p><strong>\u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430<\/strong>:\u00a0\u0412\u044b\u0441\u043e\u043a\u0430\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u044c.\u00a0<strong>\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438<\/strong>:\u00a0\u0421\u043b\u043e\u0436\u043d\u0430\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430,\u00a0\u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0Kubernetes).<\/p>\n<p><strong>\u0421\u0445\u0435\u043c\u0430 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0438<\/strong>:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2e6\/9d9\/167\/2e69d9167da17a7578c4de2be998b8df.png\" width=\"634\" height=\"643\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/2e6\/9d9\/167\/2e69d9167da17a7578c4de2be998b8df.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2e6\/9d9\/167\/2e69d9167da17a7578c4de2be998b8df.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<h4>3. \u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441 Active Directory \u0438\u043b\u0438 LDAP<\/h4>\n<p>\u0412 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445,\u00a0\u043a\u0430\u043a \u043d\u0430\u0448 e-commerce \u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0447\u0430\u0441\u0442\u043e \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 Active Directory\u00a0(AD)\u00a0\u0438\u043b\u0438 LDAP.\u00a0Keycloak \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0443\u0435\u0442 \u0438\u0445 \u0447\u0435\u0440\u0435\u0437 User Federation:<\/p>\n<ul>\n<li>\n<p><strong>\u041a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442<\/strong>: Keycloak \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043a AD, \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0433\u0440\u0443\u043f\u043f\u044b. \u0413\u0440\u0443\u043f\u043f\u0430 AD\u00a0<code>ReportUsers<\/code>\u00a0\u043c\u0430\u043f\u043f\u0438\u0442\u0441\u044f \u043d\u0430 \u0440\u043e\u043b\u044c\u00a0<code>report_user<\/code>\u00a0\u0432\u00a0<code>reports-realm<\/code>.<\/p>\n<\/li>\n<li>\n<p><strong>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430<\/strong>:<\/p>\n<ol>\n<li>\n<p>\u0412 \u0430\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u0438: &#171;User Federation&#187; \u2192 &#171;Add provider&#187; \u2192 &#171;ldap&#187;.<\/p>\n<\/li>\n<li>\n<p>\u0423\u043a\u0430\u0436\u0438\u0442\u0435 URL (<code>ldap:\/\/<\/code><a href=\"http:\/\/ad.example.com\" rel=\"noopener noreferrer nofollow\"><code>ad.example.com<\/code><\/a>), bind DN, \u0444\u0438\u043b\u044c\u0442\u0440\u044b (<code>(objectClass=user)<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u041c\u0430\u043f\u043f\u0438\u043d\u0433: \u0433\u0440\u0443\u043f\u043f\u0430\u00a0<code>ReportUsers<\/code>\u00a0\u2192 \u0440\u043e\u043b\u044c\u00a0<code>report_user<\/code>.<\/p>\n<\/li>\n<\/ol>\n<\/li>\n<\/ul>\n<p><strong>\u041f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e \u0432\u0430\u0436\u043d\u043e<\/strong>:\u00a0\u041f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0443\u0447\u0451\u0442\u043d\u044b\u0435 \u0437\u0430\u043f\u0438\u0441\u0438,\u00a0\u043a\u0430\u043a \u0434\u043b\u044f \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u043e\u0432 \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430.<\/p>\n<p><strong>\u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430<\/strong>:\u00a0\u0426\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435.\u00a0<strong>\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438<\/strong>:\u00a0\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0443\u043f \u043a AD,\u00a0\u0441\u043b\u043e\u0436\u043d\u0435\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430.<\/p>\n<p><strong>\u0421\u0445\u0435\u043c\u0430 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 AD<\/strong>:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/540\/5e6\/815\/5405e6815ff41eabb1cb0866b1ab4b8a.png\" width=\"1335\" height=\"673\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/540\/5e6\/815\/5405e6815ff41eabb1cb0866b1ab4b8a.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/540\/5e6\/815\/5405e6815ff41eabb1cb0866b1ab4b8a.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<h4>4. \u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u043b\u043e\u0433\u0438\u043d\u043e\u0432 \u0438 \u043f\u0430\u0440\u043e\u043b\u0435\u0439<\/h4>\n<p>\u0412 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e:<\/p>\n<ul>\n<li>\n<p><strong>\u0425\u0440\u0430\u043d\u0435\u043d\u0438\u0435<\/strong>: \u041f\u0430\u0440\u043e\u043b\u0438 \u0445\u044d\u0448\u0438\u0440\u0443\u044e\u0442\u0441\u044f (PBKDF2\/Argon2). \u0412 JSON-\u0438\u043c\u043f\u043e\u0440\u0442\u0435 (\u043a\u0430\u043a \u0432 \u0447\u0430\u0441\u0442\u0438 8) \u043e\u043d\u0438 \u0432 plain-text \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0430<\/strong>: \u041b\u043e\u0433\u0438\u043d\u044b\/\u043f\u0430\u0440\u043e\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u043f\u043e HTTPS. Keycloak \u0442\u0440\u0435\u0431\u0443\u0435\u0442 SSL \u0432 \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0435.<\/p>\n<\/li>\n<li>\n<p><strong>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f<\/strong>: \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 Keycloak (\u0441 email-\u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0435\u0439) \u0438\u043b\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0438\u0437 AD.<\/p>\n<\/li>\n<li>\n<p><strong>\u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c<\/strong>: \u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0432 \u0437\u0430\u044f\u0432\u043a\u0435 \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0438 \u043f\u0430\u0440\u043e\u043b\u0435\u0439 (\u0434\u043b\u0438\u043d\u0430, expiration) \u0438 MFA. \u041f\u0430\u0440\u043e\u043b\u0438 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u0432 secrets (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f).<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u0421\u0445\u0435\u043c\u0430 \u043f\u043e\u0442\u043e\u043a\u0430 \u043b\u043e\u0433\u0438\u043d\u0430<\/strong>:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/8e1\/195\/e86\/8e1195e861d6e5a18df7476e4dabf060.png\" width=\"1659\" height=\"630\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/8e1\/195\/e86\/8e1195e861d6e5a18df7476e4dabf060.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/8e1\/195\/e86\/8e1195e861d6e5a18df7476e4dabf060.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<h2>6. PKCE \u0434\u043b\u044f \u0437\u0430\u0449\u0438\u0442\u044b \u043e\u0442 \u0430\u0442\u0430\u043a \u0432 OIDC<\/h2>\n<p>PKCE\u00a0(Proof Key for Code Exchange)\u00a0\u2014\u00a0\u044d\u0442\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 OpenID Connect (OIDC), \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u0432\u044b\u0448\u0430\u0435\u0442 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c \u0434\u043b\u044f public clients,\u00a0\u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430\u00a0(<code>store-frontend<\/code>)\u00a0\u0432 \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0435.\u00a0Public clients\u00a0\u2014\u00a0\u044d\u0442\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f,\u00a0\u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0435 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0React-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435),\u00a0\u0433\u0434\u0435 \u043d\u0435\u043b\u044c\u0437\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0441\u0435\u043a\u0440\u0435\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430.\u00a0PKCE \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0430\u0442\u0430\u043a\u0438,\u00a0\u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u043e\u043c authorization code,\u00a0\u043a\u043e\u0433\u0434\u0430 \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u043c\u043e\u0436\u0435\u0442 \u0443\u043a\u0440\u0430\u0441\u0442\u044c \u043a\u043e\u0434 \u0438 \u043e\u0431\u043c\u0435\u043d\u044f\u0442\u044c \u0435\u0433\u043e \u043d\u0430 JWT-\u0442\u043e\u043a\u0435\u043d,\u00a0\u043f\u043e\u043b\u0443\u0447\u0438\u0432 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 \u0437\u0430\u043a\u0430\u0437\u043e\u0432\u00a0(<code>orders-api<\/code>).\u00a0\u0414\u043b\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430 PKCE \u0432\u0430\u0436\u043d\u043e,\u00a0\u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u0442\u044c \u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u0437\u0430\u0449\u0438\u0442\u044b \u0438 \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f,\u00a0\u0447\u0442\u043e \u0442\u043e\u043a\u0435\u043d\u044b\u00a0(\u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0435,\u00a0\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u0440\u043e\u043b\u044c\u00a0<code>order_manager<\/code>)\u00a0\u0432\u044b\u0434\u0430\u044e\u0442\u0441\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e.<\/p>\n<h4>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0431\u0435\u0437 PKCE: \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u044c \u0432 Authorization Code Flow<\/h4>\n<p>\u0412 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u043c Authorization Code Flow OIDC \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043d\u0430 Keycloak \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u043d\u0430,\u00a0\u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 authorization code \u0447\u0435\u0440\u0435\u0437 redirect URI\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<a href=\"http:\/\/localhost:3000\/*\" rel=\"noopener noreferrer nofollow\"><code>http:\/\/localhost:3000\/*<\/code><\/a>).\u00a0\u042d\u0442\u043e\u0442 \u043a\u043e\u0434 \u043e\u0431\u043c\u0435\u043d\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 JWT-\u0442\u043e\u043a\u0435\u043d\u044b\u00a0(ID Token \u0438 Access Token)\u00a0\u0447\u0435\u0440\u0435\u0437 Token Endpoint.\u00a0\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0442\u043e\u043c,\u00a0\u0447\u0442\u043e \u043a\u043e\u0434 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0447\u0435\u043d \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a\u043e\u043c,\u00a0\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<ul>\n<li>\n<p><strong>\u041f\u043e\u0434\u043c\u0435\u043d\u0430 redirect URI<\/strong>: \u0417\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043a\u043e\u0434 \u043d\u0430 \u0441\u0432\u043e\u0439 \u0441\u0435\u0440\u0432\u0435\u0440.<\/p>\n<\/li>\n<li>\n<p><strong>\u0412\u0440\u0435\u0434\u043e\u043d\u043e\u0441\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/strong>: \u0414\u0440\u0443\u0433\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u0442\u0435\u043c \u0436\u0435 redirect URI \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0443\u043a\u0440\u0430\u0434\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u0434.<\/p>\n<\/li>\n<\/ul>\n<p>\u0411\u0435\u0437 \u0437\u0430\u0449\u0438\u0442\u044b Keycloak \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c,\u00a0\u0447\u0442\u043e \u043a\u043e\u0434 \u0437\u0430\u043f\u0440\u043e\u0448\u0435\u043d \u0438\u043c\u0435\u043d\u043d\u043e \u043b\u0435\u0433\u0438\u0442\u0438\u043c\u043d\u044b\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c\u00a0(<code>store-frontend<\/code>),\u00a0\u0438 \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u043e\u043a\u0435\u043d \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0<code>order_manager<\/code>.<\/p>\n<p>\u0412\u043e\u0442 \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430,\u00a0\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0430\u044f \u0430\u0442\u0430\u043a\u0443 \u0431\u0435\u0437 PKCE:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/bb6\/4c4\/421\/bb64c4421073d49eb2a3286845299fe3.png\" alt=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442,\u00a0\u043a\u0430\u043a \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043a\u043e\u0434 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0442\u043e\u043a\u0435\u043d,\u00a0\u043e\u0431\u0445\u043e\u0434\u044f \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0443.  \" title=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442,\u00a0\u043a\u0430\u043a \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043a\u043e\u0434 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0442\u043e\u043a\u0435\u043d,\u00a0\u043e\u0431\u0445\u043e\u0434\u044f \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0443.  \" width=\"1821\" height=\"846\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/bb6\/4c4\/421\/bb64c4421073d49eb2a3286845299fe3.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/bb6\/4c4\/421\/bb64c4421073d49eb2a3286845299fe3.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442,\u00a0\u043a\u0430\u043a \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043a\u043e\u0434 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0442\u043e\u043a\u0435\u043d,\u00a0\u043e\u0431\u0445\u043e\u0434\u044f \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0443.  <\/figcaption><\/div>\n<\/figure>\n<h4>\u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u0441 PKCE: \u0437\u0430\u0449\u0438\u0449\u0451\u043d\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a<\/h4>\n<p>PKCE \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u0442 \u043e\u0442 \u0442\u0430\u043a\u0438\u0445 \u0430\u0442\u0430\u043a,\u00a0\u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044f \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u0439 \u0441\u0435\u043a\u0440\u0435\u0442,\u00a0\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u0435\u0442,\u00a0\u0447\u0442\u043e \u0437\u0430\u043f\u0440\u043e\u0441 \u0442\u043e\u043a\u0435\u043d\u043e\u0432 \u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0442 \u043b\u0435\u0433\u0438\u0442\u0438\u043c\u043d\u043e\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430.\u00a0\u0412\u043e\u0442 \u043a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442:<\/p>\n<ul>\n<li>\n<p>\u0424\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u2014\u00a0<strong>code_verifier<\/strong>\u00a0(\u0441\u0435\u043a\u0440\u0435\u0442, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <code>E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u0418\u0437\u00a0<code>code_verifier<\/code>\u00a0\u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f\u00a0<strong>code_challenge<\/strong>\u00a0\u2014 \u0435\u0433\u043e SHA-256 \u0445\u0435\u0448, \u0437\u0430\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0432 base64-URL (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk<\/code>).<\/p>\n<\/li>\n<li>\n<p><code>code_challenge<\/code>\u00a0\u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043d\u0430 \u043b\u043e\u0433\u0438\u043d, \u0430\u00a0<code>code_verifier<\/code>\u00a0\u2014 \u043f\u0440\u0438 \u043e\u0431\u043c\u0435\u043d\u0435 \u043a\u043e\u0434\u0430 \u043d\u0430 \u0442\u043e\u043a\u0435\u043d\u044b. Keycloak \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0447\u0442\u043e \u0445\u0435\u0448 verifier \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0435\u0442 \u0441 challenge.<\/p>\n<\/li>\n<\/ul>\n<p>\u0415\u0441\u043b\u0438 \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0438\u0442 \u043a\u043e\u0434,\u00a0\u043e\u043d \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u043e\u0431\u043c\u0435\u043d\u044f\u0442\u044c \u0435\u0433\u043e \u043d\u0430 \u0442\u043e\u043a\u0435\u043d\u044b \u0431\u0435\u0437 <code>code_verifier<\/code>,\u00a0\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e\u0433\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0435.<\/p>\n<p>\u0412\u043e\u0442 \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u0434\u043b\u044f \u0437\u0430\u0449\u0438\u0449\u0451\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0441 PKCE:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/7ac\/126\/107\/7ac126107a4fbfc44300a2b424468f3a.png\" alt=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442,\u00a0\u043a\u0430\u043a PKCE \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u0442 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0443,\u00a0\u0434\u0435\u043b\u0430\u044f \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442 \u043a\u043e\u0434\u0430 \u0431\u0435\u0441\u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c.\" title=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442,\u00a0\u043a\u0430\u043a PKCE \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u0442 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0443,\u00a0\u0434\u0435\u043b\u0430\u044f \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442 \u043a\u043e\u0434\u0430 \u0431\u0435\u0441\u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c.\" width=\"1842\" height=\"1062\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/7ac\/126\/107\/7ac126107a4fbfc44300a2b424468f3a.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/7ac\/126\/107\/7ac126107a4fbfc44300a2b424468f3a.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442,\u00a0\u043a\u0430\u043a PKCE \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u0442 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0443,\u00a0\u0434\u0435\u043b\u0430\u044f \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442 \u043a\u043e\u0434\u0430 \u0431\u0435\u0441\u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c.<\/figcaption><\/div>\n<\/figure>\n<h4>\u041a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 PKCE \u0432 \u0434\u0435\u0442\u0430\u043b\u044f\u0445<\/h4>\n<p>PKCE\u00a0\u2014\u00a0\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442,\u00a0\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043d\u043d\u044b\u0439 RFC 7636,\u00a0\u0438 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u0435\u043d \u0434\u043b\u044f public clients,\u00a0\u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a \u043d\u0430\u0448\u00a0<code>store-frontend<\/code>.\u00a0\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0448\u0430\u0433\u0438:<\/p>\n<ol>\n<li>\n<p><strong>\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f<\/strong>: \u0424\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u00a0<code>code_verifier<\/code>\u00a0\u2014 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 (43\u2013128 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432, base64-URL \u0431\u0435\u0437\u00a0<code>=<\/code>,\u00a0<code>+<\/code>,\u00a0<code>\/<\/code>). \u0417\u0430\u0442\u0435\u043c \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442\u00a0<code>code_challenge<\/code>\u00a0\u2014 SHA-256 \u0445\u0435\u0448 verifier, \u0442\u043e\u0436\u0435 \u0432 base64-URL.<\/p>\n<\/li>\n<li>\n<p><strong>\u0417\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u043b\u043e\u0433\u0438\u043d<\/strong>: \u0412 Authorization Endpoint \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f\u00a0<code>code_challenge<\/code>\u00a0\u0438\u00a0<code>code_challenge_method=S256<\/code>\u00a0(\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u043c\u044b\u0439 \u043c\u0435\u0442\u043e\u0434;\u00a0<code>plain<\/code>\u00a0\u043c\u0435\u043d\u0435\u0435 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u0435\u043d).<\/p>\n<\/li>\n<li>\n<p><strong>\u041e\u0431\u043c\u0435\u043d \u043d\u0430 \u0442\u043e\u043a\u0435\u043d\u044b<\/strong>: \u0424\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u00a0<code>code_verifier<\/code>\u00a0\u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043a\u043e\u0434\u043e\u043c. Keycloak \u0445\u044d\u0448\u0438\u0440\u0443\u0435\u0442 verifier \u0438 \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u0442 \u0441 challenge.<\/p>\n<\/li>\n<li>\n<p><strong>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0432 Keycloak<\/strong>: \u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043f\u0440\u043e\u0441\u0438\u0442\u044c \u0430\u0434\u043c\u0438\u043d\u043e\u0432 \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c PKCE \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u00a0<code>store-frontend<\/code>\u00a0\u0432 \u0430\u0434\u043c\u0438\u043d-\u043f\u0430\u043d\u0435\u043b\u0438 (\u0440\u0430\u0437\u0434\u0435\u043b &#171;Clients&#187; \u2192\u00a0<code>store-frontend<\/code>\u00a0\u2192 &#171;Advanced Settings&#187; \u2192 &#171;Proof Key for Code Exchange Policy&#187; = Enforced). \u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 PKCE \u0432 \u043a\u043e\u0434\u0435 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 React \u0441\u00a0<code>@react-keycloak\/web<\/code>).<\/p>\n<\/li>\n<\/ol>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a1a\/af8\/490\/a1aaf8490a55335e2da92d24b240c9d3.png\" width=\"1865\" height=\"1168\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/a1a\/af8\/490\/a1aaf8490a55335e2da92d24b240c9d3.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a1a\/af8\/490\/a1aaf8490a55335e2da92d24b240c9d3.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d:<\/p>\n<ul>\n<li>\n<p>\u0421\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u0442\u044c \u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 PKCE.<\/p>\n<\/li>\n<li>\n<p>\u0423\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f \u0441 \u0430\u0434\u043c\u0438\u043d\u0430\u043c\u0438 Keycloak, \u0447\u0442\u043e \u043a\u043b\u0438\u0435\u043d\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d \u043d\u0430\u00a0<code>S256<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u0447\u0442\u043e JWT \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043d\u0443\u0436\u043d\u044b\u0435 \u0440\u043e\u043b\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>order_manager<\/code>) \u043f\u043e\u0441\u043b\u0435 \u043b\u043e\u0433\u0438\u043d\u0430.<\/p>\n<\/li>\n<\/ul>\n<h4>\u0420\u043e\u043b\u044c \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430<\/h4>\n<p>\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0438\u0440\u0443\u0435\u0442 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b:<\/p>\n<ul>\n<li>\n<p><strong>\u041e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u0435 \u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438<\/strong>: \u0423\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u00a0<code>code_challenge<\/code>\u00a0\u0438 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u00a0<code>code_verifier<\/code>.<\/p>\n<\/li>\n<li>\n<p><strong>\u041e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u0435 \u0441 \u0430\u0434\u043c\u0438\u043d\u0430\u043c\u0438 Keycloak<\/strong>: \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 PKCE \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u00a0<code>store-frontend<\/code>.<\/p>\n<\/li>\n<li>\n<p><strong>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/strong>: \u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u0447\u0442\u043e \u0442\u043e\u043a\u0435\u043d\u044b \u0432\u044b\u0434\u0430\u044e\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043b\u0435\u0433\u0438\u0442\u0438\u043c\u043d\u044b\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c, \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u0443\u044f JWT (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 <a href=\"http:\/\/jwt.io\" rel=\"noopener noreferrer nofollow\">jwt.io<\/a>).<\/p>\n<\/li>\n<\/ul>\n<p>\u0411\u0435\u0437 PKCE \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0443\u044f\u0437\u0432\u0438\u043c\u0430,\u00a0\u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u043d\u0435\u0441\u0430\u043d\u043a\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u043c\u0443 \u0434\u043e\u0441\u0442\u0443\u043f\u0443 \u043a \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 \u0437\u0430\u043a\u0430\u0437\u043e\u0432.\u00a0PKCE\u00a0\u2014\u00a0\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043c\u0435\u0440\u0430 \u0434\u043b\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0433\u043e SSO \u0432 \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0435.<\/p>\n<h2>7. \u0421\u0445\u0435\u043c\u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0440\u043e\u043b\u044c Keycloak \u0432 \u043d\u0451\u043c<\/h2>\n<p>Keycloak \u0432 \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0435 \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u043a\u0430\u043a \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438\u00a0(Identity Provider,\u00a0IdP),\u00a0\u0441\u0432\u044f\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430\u00a0(<code>store-frontend<\/code>)\u00a0\u0441 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043a\u0430\u0437\u043e\u0432\u00a0(<code>orders-api<\/code>).\u00a0\u0414\u043b\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430 \u0432\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u044c,\u00a0\u043a\u0430\u043a \u044d\u0442\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0442 \u0447\u0435\u0440\u0435\u0437 Keycloak,\u00a0\u0447\u0442\u043e\u0431\u044b \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u0434\u043b\u044f \u0440\u043e\u043b\u0438\u00a0<code>order_manager<\/code>)\u00a0\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 JWT-\u0442\u043e\u043a\u0435\u043d\u0430\u00a0(\u0440\u043e\u043b\u0438,\u00a0\u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b).\u00a0\u0412 \u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u0442\u0438\u043f\u0438\u0447\u043d\u043e\u0433\u043e \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f,\u00a0\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0435\u0433\u043e Keycloak,\u00a0\u0438 \u043f\u043e\u043a\u0430\u0436\u0435\u043c,\u00a0\u043a\u0430\u043a \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0438\u0440\u0443\u0435\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443,\u00a0\u0447\u0442\u043e\u0431\u044b \u0442\u043e\u043a\u0435\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b \u043d\u0443\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u043d\u0430\u0447\u043d\u0451\u043c \u0441 \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u044b,\u00a0\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0435\u0439,\u00a0\u043a\u0430\u043a Keycloak \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/31c\/33f\/263\/31c33f263ef59ad01622c1188f5baf79.png\" alt=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043b\u043e\u0433\u0438\u043d\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0443,\u00a0Keycloak \u0432\u044b\u0434\u0430\u0451\u0442 JWT \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0order_manager,\u00a0\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d,\u00a0\u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u0437\u0430\u043a\u0430\u0437\u043e\u0432).\u00a0PostgreSQL \u0445\u0440\u0430\u043d\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0440\u043e\u043b\u0438.\" title=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043b\u043e\u0433\u0438\u043d\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0443,\u00a0Keycloak \u0432\u044b\u0434\u0430\u0451\u0442 JWT \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0order_manager,\u00a0\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d,\u00a0\u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u0437\u0430\u043a\u0430\u0437\u043e\u0432).\u00a0PostgreSQL \u0445\u0440\u0430\u043d\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0440\u043e\u043b\u0438.\" width=\"1086\" height=\"632\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/31c\/33f\/263\/31c33f263ef59ad01622c1188f5baf79.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/31c\/33f\/263\/31c33f263ef59ad01622c1188f5baf79.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043b\u043e\u0433\u0438\u043d\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0443,\u00a0Keycloak \u0432\u044b\u0434\u0430\u0451\u0442 JWT \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0<code>order_manager<\/code>,\u00a0\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d,\u00a0\u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u0437\u0430\u043a\u0430\u0437\u043e\u0432).\u00a0PostgreSQL \u0445\u0440\u0430\u043d\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0440\u043e\u043b\u0438.<\/figcaption><\/div>\n<\/figure>\n<h4>\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h4>\n<p>\u0422\u0438\u043f\u0438\u0447\u043d\u043e\u0435 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0442\u0440\u0451\u0445 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432:<\/p>\n<ul>\n<li>\n<p><strong>\u0424\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 (Frontend)<\/strong>: \u0412\u0435\u0431-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u0433\u0434\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u044b \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430) \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0442 \u0441 \u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439. \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u2014 React-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 (<code>store-frontend<\/code>), \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u0430 Keycloak \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u043d\u0430.<\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0437\u0430\u043a\u0430\u0437\u043e\u0432 (Backend)<\/strong>: \u0421\u0435\u0440\u0432\u0435\u0440, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u0437\u0430\u043a\u0430\u0437\u043e\u0432. \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u2014 Node.js-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 (<code>orders-api<\/code>), \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0435\u0440\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u0442 JWT-\u0442\u043e\u043a\u0435\u043d\u044b.<\/p>\n<\/li>\n<li>\n<p><strong>Keycloak<\/strong>: IdP, \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0435\u0439 \u0438 \u0432\u044b\u0434\u0430\u044e\u0449\u0438\u0439 \u0442\u043e\u043a\u0435\u043d\u044b \u0441 \u0440\u043e\u043b\u044f\u043c\u0438 \u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430\u043c\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d:<\/p>\n<ul>\n<li>\n<p>\u0421\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u0442\u044c \u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u043a\u0430\u043a \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u0442\u043e\u043a\u0435\u043d\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0435\u0440\u0435\u0437 OIDC Authorization Code Flow).<\/p>\n<\/li>\n<li>\n<p>\u0423\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f \u0441 \u0430\u0434\u043c\u0438\u043d\u0430\u043c\u0438 Keycloak, \u0447\u0442\u043e \u0440\u043e\u043b\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>order_manager<\/code>) \u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>department: sales<\/code>) \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u0432 JWT.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043f\u0440\u043e\u0441\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e \u0442\u043e\u043a\u0435\u043d\u043e\u0432.<\/p>\n<\/li>\n<\/ul>\n<h4>\u0420\u043e\u043b\u044c Keycloak \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438<\/h4>\n<p>Keycloak \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u043a\u0430\u043a\u00a0&#171;\u043f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a&#187;\u00a0\u043c\u0435\u0436\u0434\u0443 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439 \u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u043e\u0439 \u0437\u0430\u043a\u0430\u0437\u043e\u0432:<\/p>\n<ol>\n<li>\n<p><strong>\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/strong>: \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0437\u0430\u0445\u043e\u0434\u0438\u0442 \u0432 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0438 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430 Keycloak \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u043d\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u0432\u043e\u0434\u0438\u0442\u00a0<code>access1<\/code>\/<code>accesspass1<\/code>).<\/p>\n<\/li>\n<li>\n<p><strong>\u0412\u044b\u0434\u0430\u0447\u0430 \u0442\u043e\u043a\u0435\u043d\u043e\u0432<\/strong>: Keycloak \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 JWT (ID Token \u0434\u043b\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438, Access Token \u0441 \u0440\u043e\u043b\u044f\u043c\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>order_manager<\/code>).<\/p>\n<\/li>\n<li>\n<p><strong>\u0412\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/strong>: \u0424\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 Access Token \u043d\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443 \u0437\u0430\u043a\u0430\u0437\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0435\u0433\u043e (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0435\u0440\u0435\u0437 JWKS \u2014 JSON Web Key Set).<\/p>\n<\/li>\n<li>\n<p><strong>\u0414\u043e\u0441\u0442\u0443\u043f<\/strong>: \u0415\u0441\u043b\u0438 \u0442\u043e\u043a\u0435\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043d\u0443\u0436\u043d\u0443\u044e \u0440\u043e\u043b\u044c, \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u0437\u0430\u043a\u0430\u0437\u0430).<\/p>\n<\/li>\n<\/ol>\n<p>\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c \u0441 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u043c\u0438:<\/p>\n<ul>\n<li>\n<p>\u041a\u0430\u043a\u0438\u0435 \u0440\u043e\u043b\u0438 \u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0432 JWT (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>order_manager<\/code>,\u00a0<code>department<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c clients \u0432 Keycloak (<code>store-frontend<\/code>,\u00a0<code>orders-api<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u043a \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043a\u0435\u043d\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 <a href=\"http:\/\/jwt.io\" rel=\"noopener noreferrer nofollow\">jwt.io<\/a>).<\/p>\n<\/li>\n<\/ul>\n<h4>\u041f\u043e\u0442\u043e\u043a \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f<\/h4>\n<p>\u0412\u043e\u0442 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a,\u00a0\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439,\u00a0\u043a\u0430\u043a Keycloak \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/352\/744\/7b2\/3527447b2bdef144ddf1027462e7d483.png\" alt=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0Keycloak \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f,\u00a0\u0432\u044b\u0434\u0430\u0451\u0442 JWT,\u00a0\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d,\u00a0\u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f.\u00a0\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f,\u00a0\u0447\u0442\u043e JWT \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043d\u0443\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.\" title=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0Keycloak \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f,\u00a0\u0432\u044b\u0434\u0430\u0451\u0442 JWT,\u00a0\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d,\u00a0\u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f.\u00a0\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f,\u00a0\u0447\u0442\u043e JWT \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043d\u0443\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.\" width=\"1788\" height=\"947\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/352\/744\/7b2\/3527447b2bdef144ddf1027462e7d483.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/352\/744\/7b2\/3527447b2bdef144ddf1027462e7d483.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0Keycloak \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f,\u00a0\u0432\u044b\u0434\u0430\u0451\u0442 JWT,\u00a0\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d,\u00a0\u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f.\u00a0\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f,\u00a0\u0447\u0442\u043e JWT \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043d\u0443\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.<\/figcaption><\/div>\n<\/figure>\n<h4>\u0420\u043e\u043b\u044c \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430<\/h4>\n<p>\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0438\u0440\u0443\u0435\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443:<\/p>\n<ul>\n<li>\n<p><strong>\u0421 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b<\/strong>: \u0423\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043a\u043b\u0438\u0435\u043d\u0442 (<code>store-frontend<\/code>) \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 OIDC \u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435 redirect URI.<\/p>\n<\/li>\n<li>\n<p><strong>\u0421 \u0430\u0434\u043c\u0438\u043d\u0430\u043c\u0438 Keycloak<\/strong>: \u041d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c realm (<code>store-realm<\/code>) \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438 (<code>access1<\/code>) \u0438 \u0440\u043e\u043b\u044f\u043c\u0438 (<code>order_manager<\/code>).<\/p>\n<\/li>\n<li>\n<p><strong>\u0421 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0437\u0430\u043a\u0430\u0437\u043e\u0432<\/strong>: \u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u0447\u0442\u043e backend \u0432\u0435\u0440\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u0442 JWT \u0438 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442 \u0440\u043e\u043b\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/strong>: \u0414\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c JWT (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 <a href=\"http:\/\/jwt.io\" rel=\"noopener noreferrer nofollow\">jwt.io<\/a>) \u0438 \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043e\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u00a0<code>order_manager<\/code>\u00a0\u0438\u00a0<code>department: sales<\/code>.<\/p>\n<\/li>\n<\/ul>\n<h4>\u0421\u0432\u044f\u0437\u044c \u0441 \u0437\u0430\u0434\u0430\u0447\u0435\u0439<\/h4>\n<p>\u0412 \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0435 Keycloak \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u0442 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443 \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 SSO.\u00a0\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d:<\/p>\n<ul>\n<li>\n<p>\u0421\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u0440\u043e\u043b\u0438 \u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u043d\u0443\u0436\u043d\u044b \u0432 JWT \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0437\u0430\u043a\u0430\u0437\u0430\u043c.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 clients (<code>store-frontend<\/code>,\u00a0<code>orders-api<\/code>) \u0432 Keycloak.<\/p>\n<\/li>\n<li>\n<p>\u0423\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 HTTPS).<\/p>\n<\/li>\n<\/ul>\n<p>\u042d\u0442\u0430 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u0430:\u00a0\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0443)\u00a0\u0432 \u0442\u043e\u0442 \u0436\u0435 realm \u0438\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439,\u00a0\u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0432 SSO.<\/p>\n<h2>8. \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430: \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440<\/h2>\n<p>\u042d\u0442\u0430 \u0447\u0430\u0441\u0442\u044c \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442,\u00a0\u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435,\u00a0\u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0449\u0435\u0435 \u0434\u043e\u0441\u0442\u0443\u043f \u0438\u0437 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b\u00a0(<code>reports-frontend<\/code>)\u00a0\u043a API \u043e\u0442\u0447\u0451\u0442\u043e\u0432\u00a0(<code>reports-api<\/code>)\u00a0\u0447\u0435\u0440\u0435\u0437 Keycloak,\u00a0\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b OpenID Connect\u00a0(OIDC).\u00a0\u041c\u044b \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u044d\u0442\u043e \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 e-commerce,\u00a0\u0433\u0434\u0435 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430,\u00a0\u0430 API \u043e\u0442\u0447\u0451\u0442\u043e\u0432\u00a0\u2014\u00a0\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u043e\u0439 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445.\u00a0\u041f\u0440\u0438\u043c\u0435\u0440 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 React-frontend,\u00a0Node.js-backend \u0438 Keycloak,\u00a0\u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0435 \u0447\u0435\u0440\u0435\u0437 Docker Compose.\u00a0\u041c\u044b \u043f\u0440\u043e\u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c,\u00a0\u043a\u0430\u043a \u043a\u043e\u0434 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 Keycloak,\u00a0\u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u0443\u0435\u0442 \u0444\u0440\u043e\u043d\u0442-\u00a0\u0438 \u0431\u044d\u043a\u0435\u043d\u0434-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f,\u00a0\u0438 \u043a\u0430\u043a JWT-\u0442\u043e\u043a\u0435\u043d \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0<code>report_user<\/code>\u00a0\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043e\u0442\u0447\u0451\u0442\u0430\u043c.\u00a0\u042d\u0442\u043e \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043d\u044f\u0442\u044c,\u00a0\u043a\u0430\u043a \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f Single Sign-On\u00a0(SSO). \u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 <a href=\"https:\/\/github.com\/vasilokb\/keycloak\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/vasilokb\/keycloak<\/a>, \u0433\u0434\u0435 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0438 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u043d\u0430\u0447\u043d\u0451\u043c \u0441 \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u044b,\u00a0\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0435\u0439 \u043f\u043e\u0442\u043e\u043a \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f84\/513\/5da\/f845135dad87ce93d107d620015ed0a1.png\" alt=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043b\u043e\u0433\u0438\u043d\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 Keycloak,\u00a0\u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0report_user,\u00a0\u0430 API \u043e\u0442\u0447\u0451\u0442\u043e\u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u043e\u0442\u0447\u0451\u0442\u00a0{ id: 123, title: &quot;Usage Report 45&quot; }).\" title=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043b\u043e\u0433\u0438\u043d\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 Keycloak,\u00a0\u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0report_user,\u00a0\u0430 API \u043e\u0442\u0447\u0451\u0442\u043e\u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u043e\u0442\u0447\u0451\u0442\u00a0{ id: 123, title: &quot;Usage Report 45&quot; }).\" width=\"1637\" height=\"954\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/f84\/513\/5da\/f845135dad87ce93d107d620015ed0a1.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f84\/513\/5da\/f845135dad87ce93d107d620015ed0a1.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043b\u043e\u0433\u0438\u043d\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 Keycloak,\u00a0\u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0<code>report_user<\/code>,\u00a0\u0430 API \u043e\u0442\u0447\u0451\u0442\u043e\u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u043e\u0442\u0447\u0451\u0442\u00a0<code>{ id: 123, title: \"Usage Report 45\" }<\/code>).<\/figcaption><\/div>\n<\/figure>\n<h4>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h4>\n<p>\u041f\u0440\u043e\u0435\u043a\u0442 \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u043d \u043a\u0430\u043a \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430,\u00a0\u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u00a0(\u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430,\u00a0\u0431\u044d\u043a\u0435\u043d\u0434,\u00a0Keycloak,\u00a0\u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445)\u00a0\u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435.\u00a0\u042d\u0442\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442:<\/p>\n<ul>\n<li>\n<p><strong>\u041c\u043e\u0434\u0443\u043b\u044c\u043d\u043e\u0441\u0442\u044c<\/strong>: \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b, \u0447\u0442\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435.<\/p>\n<\/li>\n<li>\n<p><strong>\u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u044c<\/strong>: \u0421\u0435\u0440\u0432\u0438\u0441\u044b \u043c\u043e\u0436\u043d\u043e \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0434\u044b Keycloak).<\/p>\n<\/li>\n<li>\n<p><strong>\u041e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0446\u0438\u044e<\/strong>: Docker Compose \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0432 \u0441\u0435\u0442\u044c \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p><strong>\u0425\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445<\/strong>: PostgreSQL \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0440\u043e\u043b\u0438 Keycloak.<\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<pre><code>. \u251c\u2500\u2500 .gitignore \u251c\u2500\u2500 docker-compose.yml \u251c\u2500\u2500 README.md \u251c\u2500\u2500 backend \u2502   \u251c\u2500\u2500 Dockerfile \u2502   \u251c\u2500\u2500 package.json \u2502   \u251c\u2500\u2500 server.js \u251c\u2500\u2500 frontend \u2502   \u251c\u2500\u2500 .env \u2502   \u251c\u2500\u2500 Dockerfile \u2502   \u251c\u2500\u2500 nginx.conf \u2502   \u251c\u2500\u2500 package.json \u2502   \u251c\u2500\u2500 public \u2502   \u2502   \u251c\u2500\u2500 index.html \u2502   \u251c\u2500\u2500 src \u2502   \u2502   \u251c\u2500\u2500 App.tsx \u2502   \u2502   \u251c\u2500\u2500 index.tsx \u2502   \u2502   \u251c\u2500\u2500 components \u2502   \u2502   \u2502   \u251c\u2500\u2500 ReportPage.tsx \u251c\u2500\u2500 keycloak \u2502   \u251c\u2500\u2500 realm-export.json \u251c\u2500\u2500 postgres-keycloak-data <\/code><\/pre>\n<p><strong>\u041f\u043e\u044f\u0441\u043d\u0435\u043d\u0438\u044f \u043a \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435<\/strong>:<\/p>\n<ul>\n<li>\n<p><strong>.gitignore<\/strong>: \u0418\u0441\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>node_modules<\/code>) \u0438\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p><strong>docker-compose.yml<\/strong>: \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0441\u0435\u0440\u0432\u0438\u0441\u044b (Keycloak, PostgreSQL, frontend, backend) \u0438 \u0441\u0435\u0442\u044c\u00a0<code>sprint-8-network<\/code>.<\/p>\n<\/li>\n<li>\n<p><a href=\"http:\/\/README.md\" rel=\"noopener noreferrer nofollow\"><strong>README.md<\/strong><\/a>: \u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0441 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>backend<\/strong>: Node.js-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 (<code>reports-api<\/code>):<\/p>\n<ul>\n<li>\n<p><code>Dockerfile<\/code>: \u0418\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 Docker-\u043e\u0431\u0440\u0430\u0437\u0430.<\/p>\n<\/li>\n<li>\n<p><code>package.json<\/code>: \u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 (express, jwks-rsa \u0434\u043b\u044f \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 JWT).<\/p>\n<\/li>\n<li>\n<p><code>server.js<\/code>: \u041e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u044b\u00a0<code>\/reports<\/code>.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>frontend<\/strong>: React-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 (<code>reports-frontend<\/code>):<\/p>\n<ul>\n<li>\n<p><code>.env<\/code>: \u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>REACT_APP_KEYCLOAK_URL<\/code>).<\/p>\n<\/li>\n<li>\n<p><code>Dockerfile<\/code>: \u0421\u0431\u043e\u0440\u043a\u0430 React-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p><code>nginx.conf<\/code>: \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0434\u043b\u044f \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b.<\/p>\n<\/li>\n<li>\n<p><code>package.json<\/code>: \u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 (react, @react-keycloak\/web).<\/p>\n<\/li>\n<li>\n<p><code>public\/index.html<\/code>: \u0413\u043b\u0430\u0432\u043d\u0430\u044f HTML-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430.<\/p>\n<\/li>\n<li>\n<p><code>src<\/code>: \u041a\u043e\u0434 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u0432\u043a\u043b\u044e\u0447\u0430\u044f\u00a0<code>App.tsx<\/code>\u00a0(\u043b\u043e\u0433\u0438\u043a\u0430 OIDC) \u0438\u00a0<code>ReportPage.tsx<\/code>\u00a0(\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043e\u0442\u0447\u0451\u0442\u043e\u0432).<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>keycloak<\/strong>: \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f Keycloak:<\/p>\n<ul>\n<li>\n<p><code>realm-export.json<\/code>: \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 realm, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u0440\u043e\u043b\u0435\u0439, \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>postgres-keycloak-data<\/strong>: Volume \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 PostgreSQL.<\/p>\n<\/li>\n<\/ul>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 Keycloak<\/h4>\n<p>Keycloak \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d \u0447\u0435\u0440\u0435\u0437 JSON-\u0438\u043c\u043f\u043e\u0440\u0442,\u00a0\u0441\u043e\u0437\u0434\u0430\u044e\u0449\u0438\u0439 realm\u00a0<code>reports-realm<\/code>,\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u00a0<code>access1<\/code>,\u00a0\u0440\u043e\u043b\u044c\u00a0<code>report_user<\/code>\u00a0\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432\u00a0<code>reports-frontend<\/code>,\u00a0<code>reports-api<\/code>.<\/p>\n<h3>\u0418\u043c\u043f\u043e\u0440\u0442 realm<\/h3>\n<p>\u0424\u0430\u0439\u043b\u00a0<code>realm-export.json<\/code>:<\/p>\n<pre><code class=\"json\">{   \"realm\": \"reports-realm\",   \"enabled\": true,   \"roles\": {     \"realm\": [       {         \"name\": \"user\",         \"description\": \"Regular user role\"       },       {         \"name\": \"administrator\",         \"description\": \"Administrator role\"       },       {         \"name\": \"report_user\",         \"description\": \"Prothetic user role with report access\"       }     ]   },   \"users\": [     {       \"username\": \"regular1\",       \"enabled\": true,       \"email\": \"regular1@example.com\",       \"firstName\": \"Regular\",       \"lastName\": \"One\",       \"credentials\": [         {           \"type\": \"password\",           \"value\": \"userpass1\",           \"temporary\": false         }       ],       \"realmRoles\": [\"user\"]     },     {       \"username\": \"superadmin1\",       \"enabled\": true,       \"email\": \"superadmin1@example.com\",       \"firstName\": \"Super\",       \"lastName\": \"Admin\",       \"credentials\": [         {           \"type\": \"password\",           \"value\": \"adminpass1\",           \"temporary\": false         }       ],       \"realmRoles\": [\"administrator\"]     },     {       \"username\": \"access1\",       \"enabled\": true,       \"email\": \"access1@example.com\",       \"firstName\": \"Access\",       \"lastName\": \"One\",       \"credentials\": [         {           \"type\": \"password\",           \"value\": \"accesspass1\",           \"temporary\": false         }       ],       \"realmRoles\": [\"report_user\"]     }   ],   \"clients\": [     {       \"clientId\": \"reports-frontend\",       \"enabled\": true,       \"publicClient\": true,       \"redirectUris\": [\"http:\/\/localhost:3000\/*\"],       \"webOrigins\": [\"http:\/\/localhost:3000\"],       \"directAccessGrantsEnabled\": true     },     {       \"clientId\": \"reports-api\",       \"enabled\": true,       \"clientAuthenticatorType\": \"client-secret\",       \"secret\": \"oNwoLQdvJAvRcL89SydqCWCe5ry1jMgq\",       \"bearerOnly\": true     }   ] } <\/code><\/pre>\n<p><strong>\u041f\u043e\u044f\u0441\u043d\u0435\u043d\u0438\u044f \u043a \u043a\u043e\u0434\u0443<\/strong>:<\/p>\n<ul>\n<li>\n<p><code>\"realm\": \"reports-realm\"<\/code>: \u0421\u043e\u0437\u0434\u0430\u0451\u0442 \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0434\u043e\u043c\u0435\u043d \u0434\u043b\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0433\u0434\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438, \u0440\u043e\u043b\u0438 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u044b.<\/p>\n<\/li>\n<li>\n<p><code>\"roles\"<\/code>: \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0440\u043e\u043b\u0438, \u0432\u043a\u043b\u044e\u0447\u0430\u044f\u00a0<code>report_user<\/code>, \u0434\u0430\u044e\u0449\u0443\u044e \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043e\u0442\u0447\u0451\u0442\u0430\u043c.<\/p>\n<\/li>\n<li>\n<p><code>\"users\"<\/code>: \u0421\u043e\u0437\u0434\u0430\u0451\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u00a0<code>access1<\/code>\u00a0\u0441 \u043f\u0430\u0440\u043e\u043b\u0435\u043c\u00a0<code>accesspass1<\/code>\u00a0\u0438 \u0440\u043e\u043b\u044c\u044e\u00a0<code>report_user<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 JWT.<\/p>\n<\/li>\n<li>\n<p><code>\"clients\"<\/code>: \u041d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442\u00a0<code>reports-frontend<\/code>\u00a0(public client \u0434\u043b\u044f React, \u0441 redirect URI \u0434\u043b\u044f OIDC) \u0438\u00a0<code>reports-api<\/code>\u00a0(bearer-only \u0434\u043b\u044f backend, \u0441 \u0441\u0435\u043a\u0440\u0435\u0442\u043e\u043c \u0434\u043b\u044f \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438).<\/p>\n<\/li>\n<\/ul>\n<h4>Docker Compose<\/h4>\n<p>\u0424\u0430\u0439\u043b\u00a0<code>docker-compose.yml<\/code>\u00a0\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0441\u0435\u0440\u0432\u0438\u0441\u044b:<\/p>\n<pre><code class=\"yaml\">services:   keycloak_db:     image: postgres:14     environment:       POSTGRES_DB: keycloak_db       POSTGRES_USER: keycloak_user       POSTGRES_PASSWORD: keycloak_password     volumes:       - .\/postgres-keycloak-data:\/var\/lib\/postgresql\/data     ports:       - \"5433:5432\"     healthcheck:       test: [\"CMD-SHELL\", \"pg_isready -U keycloak_user -d keycloak_db\"]       interval: 5s       timeout: 5s       retries: 5    keycloak:     image: quay.io\/keycloak\/keycloak:21.1     environment:       KEYCLOAK_ADMIN: admin       KEYCLOAK_ADMIN_PASSWORD: admin       KC_DB: postgres       KC_DB_URL: jdbc:postgresql:\/\/keycloak_db:5432\/keycloak_db       KC_DB_USERNAME: keycloak_user       KC_DB_PASSWORD: keycloak_password     command:        - start-dev       - --import-realm     volumes:       - .\/keycloak\/realm-export.json:\/opt\/keycloak\/data\/import\/realm-export.json     ports:       - \"8080:8080\"     depends_on:       keycloak_db:         condition: service_healthy    frontend:     build:       context: .\/frontend       dockerfile: Dockerfile     ports:       - \"3000:3000\"     environment:       REACT_APP_API_URL: http:\/\/localhost:8000       REACT_APP_KEYCLOAK_URL: http:\/\/localhost:8080       REACT_APP_KEYCLOAK_REALM: reports-realm       REACT_APP_KEYCLOAK_CLIENT_ID: reports-frontend     depends_on:       - backend       - keycloak    backend:     build:       context: .\/backend       dockerfile: Dockerfile     ports:       - \"8000:8000\"     depends_on:       - keycloak  networks:   default:     name: sprint-8-network <\/code><\/pre>\n<p><strong>\u041f\u043e\u044f\u0441\u043d\u0435\u043d\u0438\u044f \u043a \u043a\u043e\u0434\u0443<\/strong>:<\/p>\n<ul>\n<li>\n<p><strong>keycloak_db<\/strong>: PostgreSQL \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u0440\u043e\u043b\u0435\u0439 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 (<code>keycloak_db<\/code>, \u043b\u043e\u0433\u0438\u043d:\u00a0<code>keycloak_user<\/code>, \u043f\u0430\u0440\u043e\u043b\u044c:\u00a0<code>keycloak_password<\/code>).<\/p>\n<\/li>\n<li>\n<p><strong>keycloak<\/strong>: Keycloak-\u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043a PostgreSQL, \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442\u00a0<code>realm-export.json<\/code>\u00a0(<code>--import-realm<\/code>), \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430\u00a0<a href=\"http:\/\/localhost:8080\" rel=\"noopener noreferrer nofollow\"><code>http:\/\/localhost:8080<\/code><\/a>.<\/p>\n<\/li>\n<li>\n<p><strong>frontend<\/strong>: React-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 3000, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0441\u0432\u044f\u0437\u0438 \u0441 Keycloak (<code>reports-realm<\/code>,\u00a0<code>reports-frontend<\/code>) \u0438 backend (<a href=\"http:\/\/localhost:8000\" rel=\"noopener noreferrer nofollow\"><code>http:\/\/localhost:8000<\/code><\/a>).<\/p>\n<\/li>\n<li>\n<p><strong>backend<\/strong>: Node.js-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u043e\u0440\u0442\u0443 8000, \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 Keycloak \u0434\u043b\u044f \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0442\u043e\u043a\u0435\u043d\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p><strong>networks<\/strong>: \u041e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u0442 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0432 \u0441\u0435\u0442\u044c\u00a0<code>sprint-8-network<\/code>.<\/p>\n<\/li>\n<\/ul>\n<h4>Frontend-\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f<\/h4>\n<p>\u0424\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430\u00a0(<code>reports-frontend<\/code>)\u00a0\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 React \u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443\u00a0<code>@react-keycloak\/web<\/code>\u00a0\u0434\u043b\u044f OIDC-\u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438.\u00a0\u0412\u043e\u0442 \u043a\u043e\u0434\u00a0<code>App.tsx<\/code>:<\/p>\n<pre><code class=\"javascript\">import React from 'react'; import { ReactKeycloakProvider } from '@react-keycloak\/web'; import Keycloak, { KeycloakConfig } from 'keycloak-js'; import ReportPage from '.\/components\/ReportPage';  const keycloakConfig: KeycloakConfig = {   url: process.env.REACT_APP_KEYCLOAK_URL,   realm: process.env.REACT_APP_KEYCLOAK_REALM || \"reports-realm\",   clientId: process.env.REACT_APP_KEYCLOAK_CLIENT_ID || \"reports-frontend\" };  const keycloak = new Keycloak(keycloakConfig);  const App: React.FC = () =&gt; {   return (     &lt;ReactKeycloakProvider       authClient={keycloak}       initOptions={{         onLoad: 'login-required',         pkceMethod: 'S256'       }}     &gt;       &lt;div className=\"App\"&gt;         &lt;ReportPage \/&gt;       &lt;\/div&gt;     &lt;\/ReactKeycloakProvider&gt;   ); };  export default App; <\/code><\/pre>\n<p><strong>\u041f\u043e\u044f\u0441\u043d\u0435\u043d\u0438\u044f \u043a \u043a\u043e\u0434\u0443<\/strong>:<\/p>\n<ul>\n<li>\n<p><strong>keycloakConfig<\/strong>: \u0417\u0430\u0434\u0430\u0451\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a Keycloak: URL (<a href=\"http:\/\/localhost:8080\" rel=\"noopener noreferrer nofollow\"><code>http:\/\/localhost:8080<\/code><\/a>), realm (<code>reports-realm<\/code>), client (<code>reports-frontend<\/code>).<\/p>\n<\/li>\n<li>\n<p><strong>ReactKeycloakProvider<\/strong>: \u041e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u044f OIDC-\u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e.<\/p>\n<\/li>\n<li>\n<p><strong>initOptions<\/strong>:\u00a0<code>onLoad: 'login-required'<\/code>\u00a0\u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043b\u043e\u0433\u0438\u043d \u043f\u0440\u0438 \u0432\u0445\u043e\u0434\u0435;\u00a0<code>pkceMethod: 'S256'<\/code>\u00a0\u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 PKCE \u0434\u043b\u044f \u0437\u0430\u0449\u0438\u0442\u044b.<\/p>\n<\/li>\n<li>\n<p><strong>ReportPage<\/strong>: \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0449\u0438\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043e\u0442\u0447\u0451\u0442\u043e\u0432.<\/p>\n<\/li>\n<\/ul>\n<h3>\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 ReportPage<\/h3>\n<p>\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u00a0<code>ReportPage.tsx<\/code>\u00a0\u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0438 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442 \u043e\u0442\u0447\u0451\u0442 \u0447\u0435\u0440\u0435\u0437\u00a0<code>\/reports<\/code>:<\/p>\n<pre><code class=\"javascript\">import React, { useState } from 'react'; import { useKeycloak } from '@react-keycloak\/web';  const ReportPage: React.FC = () =&gt; {   const { keycloak, initialized } = useKeycloak();   const [loading, setLoading] = useState(false);   const [error, setError] = useState&lt;string | null&gt;(null);   const [reportData, setReportData] = useState&lt;any | null&gt;(null);    const downloadReport = async () =&gt; {     if (!keycloak?.token) {       setError('Not authenticated');       return;     }      try {       setLoading(true);       setError(null);        const response = await fetch(`${process.env.REACT_APP_API_URL}\/reports`, {         headers: {           'Authorization': `Bearer ${keycloak.token}`         }       });        if (!response.ok) {         throw new Error(`HTTP error! status: ${response.status}`);       }        const data = await response.json();       setReportData(data);       console.log('Report data:', data);     } catch (err) {       setError(err instanceof Error ? err.message : 'An error occurred');     } finally {       setLoading(false);     }   };    if (!initialized) {     return &lt;div&gt;Loading...&lt;\/div&gt;;   }    if (!keycloak.authenticated) {     return (       &lt;div className=\"flex flex-col items-center justify-center min-h-screen bg-gray-100\"&gt;         &lt;button           onClick={() =&gt; keycloak.login()}           className=\"px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600\"         &gt;           Login         &lt;\/button&gt;       &lt;\/div&gt;     );   }    return (     &lt;div className=\"flex flex-col items-center justify-center min-h-screen bg-gray-100\"&gt;       &lt;div className=\"p-8 bg-white rounded-lg shadow-md\"&gt;         &lt;h1 className=\"text-2xl font-bold mb-6\"&gt;Usage Reports&lt;\/h1&gt;                  &lt;button           onClick={downloadReport}           disabled={loading}           className={`px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 ${             loading ? 'opacity-50 cursor-not-allowed' : ''           }`}         &gt;           {loading ? 'Generating Report...' : 'Download Report'}         &lt;\/button&gt;          {error &amp;&amp; (           &lt;div className=\"mt-4 p-4 bg-red-100 text-red-700 rounded\"&gt;             {error}           &lt;\/div&gt;         )}          {reportData &amp;&amp; (           &lt;div className=\"mt-4 p-4 bg-green-100 text-green-700 rounded\"&gt;             &lt;h2 className=\"text-lg font-bold\"&gt;Report Data&lt;\/h2&gt;             &lt;p&gt;ID: {reportData.id}&lt;\/p&gt;             &lt;p&gt;Title: {reportData.title}&lt;\/p&gt;             &lt;p&gt;Content: {reportData.content}&lt;\/p&gt;             &lt;p&gt;User: {reportData.user}&lt;\/p&gt;           &lt;\/div&gt;         )}       &lt;\/div&gt;     &lt;\/div&gt;   ); };  export default ReportPage; <\/code><\/pre>\n<p><strong>\u041f\u043e\u044f\u0441\u043d\u0435\u043d\u0438\u044f \u043a \u043a\u043e\u0434\u0443<\/strong>:<\/p>\n<ul>\n<li>\n<p><strong>useKeycloak<\/strong>: \u0425\u0443\u043a \u0438\u0437\u00a0<code>@react-keycloak\/web<\/code>, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e Keycloak (<code>keycloak.token<\/code>,\u00a0<code>initialized<\/code>,\u00a0<code>authenticated<\/code>).<\/p>\n<\/li>\n<li>\n<p><strong>downloadReport<\/strong>: \u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430\u00a0<code>\/reports<\/code>\u00a0\u0441 JWT-\u0442\u043e\u043a\u0435\u043d\u043e\u043c \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435\u00a0<code>Authorization: Bearer ${keycloak.token}<\/code>. \u0415\u0441\u043b\u0438 \u0442\u043e\u043a\u0435\u043d \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442, \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u043e\u0448\u0438\u0431\u043a\u0443.<\/p>\n<\/li>\n<li>\n<p><strong>\u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435<\/strong>:\u00a0<code>loading<\/code>\u00a0\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438,\u00a0<code>error<\/code>\u00a0\u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, 403, \u0435\u0441\u043b\u0438 \u043d\u0435\u0442 \u0440\u043e\u043b\u0438\u00a0<code>report_user<\/code>),\u00a0<code>reportData<\/code>\u00a0\u0445\u0440\u0430\u043d\u0438\u0442 \u043e\u0442\u0432\u0435\u0442 \u043e\u0442\u00a0<code>\/reports<\/code>.<\/p>\n<\/li>\n<li>\n<p><strong>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441<\/strong>: \u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0435 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d, \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u043d\u043e\u043f\u043a\u0430 &#171;Login&#187;. \u041f\u043e\u0441\u043b\u0435 \u043b\u043e\u0433\u0438\u043d\u0430 \u2014 \u043a\u043d\u043e\u043f\u043a\u0430 &#171;Download Report&#187; \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0442\u0447\u0451\u0442\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>{ id: 123, title: \"Usage Report 45\" }<\/code>).<\/p>\n<\/li>\n<li>\n<p><strong>fetch<\/strong>: \u0417\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442\u00a0<code>\/reports<\/code>, \u043e\u0436\u0438\u0434\u0430\u044f JSON. \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u00a0<code>response.ok<\/code>\u00a0\u0438 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0438.<\/p>\n<\/li>\n<\/ul>\n<h4>Backend-\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f<\/h4>\n<p>API \u043e\u0442\u0447\u0451\u0442\u043e\u0432\u00a0(<code>reports-api<\/code>)\u00a0\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 JWT-\u0442\u043e\u043a\u0435\u043d\u044b.\u00a0\u0412\u043e\u0442 \u043a\u043e\u0434\u00a0<code>server.js<\/code>:<\/p>\n<pre><code class=\"javascript\">const express = require('express'); const jwt = require('jsonwebtoken'); const jwksClient = require('jwks-rsa'); const cors = require('cors');  const app = express();  app.use(cors({   origin: 'http:\/\/localhost:3000',   methods: ['GET', 'POST', 'OPTIONS'],   allowedHeaders: ['Content-Type', 'Authorization'], }));  app.use(express.json());  app.use((req, res, next) =&gt; {   console.log(`Received ${req.method} request to ${req.url}`);   next(); });  const keycloakRealm = 'reports-realm'; const keycloakUrl = 'http:\/\/keycloak:8080'; const issuerUrl = 'http:\/\/localhost:8080'; const jwksUri = `${keycloakUrl}\/realms\/${keycloakRealm}\/protocol\/openid-connect\/certs`;  const client = jwksClient({   jwksUri: jwksUri, });  function getKey(header, callback) {   client.getSigningKey(header.kid, (err, key) =&gt; {     if (err) {       console.error('Error fetching signing key:', err);       callback(err, null);     } else {       const signingKey = key?.getPublicKey();       callback(null, signingKey);     }   }); }  const verifyToken = (req, res, next) =&gt; {   const authHeader = req.headers['authorization'];   if (!authHeader) {     console.log('No Authorization header provided for', req.url);     return res.status(401).json({ error: 'No token provided' });   }    const token = authHeader.split(' ')[1];   if (!token) {     console.log('Invalid token format for', req.url);     return res.status(401).json({ error: 'Invalid token format' });   }    console.log('Token for', req.url, ':', token);    jwt.verify(token, getKey, {     issuer: `${issuerUrl}\/realms\/${keycloakRealm}`,     algorithms: ['RS256'],   }, (err, decoded) =&gt; {     if (err) {       console.error('Token verification failed for', req.url, ':', err.message);       return res.status(401).json({ error: 'Token verification failed', details: err.message });     }      if (decoded.azp !== 'reports-frontend') {       console.log('Invalid azp for', req.url, ':', decoded.azp);       return res.status(401).json({ error: 'Invalid client', details: 'azp does not match reports-frontend' });     }      if (!decoded.realm_access?.roles.includes('report_user')) {       console.log('User does not have required role for', req.url, ':', decoded.realm_access?.roles);       return res.status(403).json({ error: 'Insufficient permissions', details: 'report_user role required' });     }      console.log('Decoded token for', req.url, ':', decoded);     req.user = decoded;     next();   }); };  app.get('\/reports', verifyToken, (req, res) =&gt; {   const report = {     id: Math.floor(Math.random() * 1000),     title: `Usage Report ${Math.floor(Math.random() * 100)}`,     content: `This is a sample report generated on ${new Date().toISOString()}.`,     user: req.user.preferred_username,   };   res.json(report); });  app.listen(8000, () =&gt; console.log('Backend running on port 8000')); <\/code><\/pre>\n<p><strong>\u041f\u043e\u044f\u0441\u043d\u0435\u043d\u0438\u044f \u043a \u043a\u043e\u0434\u0443<\/strong>:<\/p>\n<ul>\n<li>\n<p><strong>CORS<\/strong>: \u0420\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0441\u00a0<a href=\"http:\/\/localhost:3000\" rel=\"noopener noreferrer nofollow\"><code>http:\/\/localhost:3000<\/code><\/a>\u00a0(\u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430), \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043e\u0448\u0438\u0431\u043e\u043a \u043a\u0440\u043e\u0441\u0441-\u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430.<\/p>\n<\/li>\n<li>\n<p><strong>\u041b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/strong>:\u00a0<code>app.use((req, res, next))<\/code>\u00a0\u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0434\u043b\u044f \u043e\u0442\u043b\u0430\u0434\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>Keycloak \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438<\/strong>:\u00a0<code>keycloakRealm<\/code>,\u00a0<code>keycloakUrl<\/code>,\u00a0<code>jwksUri<\/code>\u00a0\u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442 realm (<code>reports-realm<\/code>) \u0438 \u0430\u0434\u0440\u0435\u0441 Keycloak \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0445 \u043a\u043b\u044e\u0447\u0435\u0439 (JWKS).<\/p>\n<\/li>\n<li>\n<p><strong>getKey<\/strong>: \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u0438 JWT.<\/p>\n<\/li>\n<li>\n<p><strong>verifyToken<\/strong>: Middleware \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 JWT:<\/p>\n<ul>\n<li>\n<p>\u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0438\u0437\u00a0<code>Authorization: Bearer &lt;token&gt;<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043f\u043e\u0434\u043f\u0438\u0441\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e JWKS (<code>jwt.verify<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u0423\u0431\u0435\u0436\u0434\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0442\u043e\u043a\u0435\u043d \u0432\u044b\u0434\u0430\u043d \u0434\u043b\u044f\u00a0<code>reports-frontend<\/code>\u00a0(<code>decoded.azp<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u0440\u043e\u043b\u0438\u00a0<code>report_user<\/code>\u00a0\u0432\u00a0<code>realm_access.roles<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0442\u043e\u043a\u0435\u043d \u0432\u00a0<code>req.user<\/code>.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>\u042d\u043d\u0434\u043f\u043e\u0438\u043d\u0442 \/reports<\/strong>: \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0447\u0451\u0442\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>{ id: 123, title: \"Usage Report 45\" }<\/code>) \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0<code>report_user<\/code>.<\/p>\n<\/li>\n<\/ul>\n<h4>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h4>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u043f\u0440\u043e\u0435\u043a\u0442:<\/p>\n<pre><code class=\"bash\">docker compose up -d<\/code><\/pre>\n<ul>\n<li>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043f\u043e\u0440\u0442\u044b (8080, 3000, 8000) \u0441\u00a0<code>netstat -tuln<\/code>\u00a0(Linux) \u0438\u043b\u0438\u00a0<code>netstat -aon<\/code>\u00a0(Windows).<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0441\u0442\u0443\u043f:<\/p>\n<ul>\n<li>\n<p>\u0424\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430:\u00a0<a href=\"http:\/\/localhost:3000\" rel=\"noopener noreferrer nofollow\">http:\/\/localhost:3000<\/a>.<\/p>\n<\/li>\n<li>\n<p>Keycloak:\u00a0<a href=\"http:\/\/localhost:8080\" rel=\"noopener noreferrer nofollow\">http:\/\/localhost:8080<\/a>\u00a0(\u043b\u043e\u0433\u0438\u043d:\u00a0<code>admin\/admin<\/code>).<\/p>\n<\/li>\n<li>\n<p>Backend:\u00a0<a href=\"http:\/\/localhost:8000\/reports\" rel=\"noopener noreferrer nofollow\">http:\/\/localhost:8000\/reports<\/a>\u00a0(\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0442\u043e\u043a\u0435\u043d).<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><strong>\u0428\u0430\u0433\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f<\/strong>:<\/p>\n<ol>\n<li>\n<p>\u041e\u0442\u043a\u0440\u043e\u0439\u0442\u0435\u00a0<a href=\"http:\/\/localhost:3000\" rel=\"noopener noreferrer nofollow\">http:\/\/localhost:3000<\/a>, \u0432\u0432\u0435\u0434\u0438\u0442\u0435\u00a0<code>access1<\/code>\/<code>accesspass1<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0412 DevTools (\u0432\u043a\u043b\u0430\u0434\u043a\u0430 Network) \u043d\u0430\u0439\u0434\u0438\u0442\u0435 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a\u00a0<code>\/reports<\/code>, \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a\u00a0<code>Authorization: Bearer &lt;JWT&gt;<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0414\u0435\u043a\u043e\u0434\u0438\u0440\u0443\u0439\u0442\u0435 JWT \u043d\u0430 <a href=\"http:\/\/jwt.io\" rel=\"noopener noreferrer nofollow\">jwt.io<\/a>, \u0443\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u043e\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u00a0<code>realm_access.roles: [\"report_user\"]<\/code>,\u00a0<code>sub: access1<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043e\u0442\u0432\u0435\u0442 \u043e\u0442\u00a0<code>\/reports<\/code>\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>{ \"id\": 123, \"title\": \"Usage Report 45\" }<\/code>).<\/p>\n<\/li>\n<\/ol>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/68c\/09d\/7f1\/68c09d7f14eaf977c827b5e832a9e64e.png\" alt=\"\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043b\u043e\u0433\u0438\u043d\u0430 Keycloak \u0441 \u0444\u043e\u0440\u043c\u043e\u0439 \u0432\u0432\u043e\u0434\u0430\u00a0access3\" title=\"\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043b\u043e\u0433\u0438\u043d\u0430 Keycloak \u0441 \u0444\u043e\u0440\u043c\u043e\u0439 \u0432\u0432\u043e\u0434\u0430\u00a0access3\" width=\"2092\" height=\"1036\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/68c\/09d\/7f1\/68c09d7f14eaf977c827b5e832a9e64e.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/68c\/09d\/7f1\/68c09d7f14eaf977c827b5e832a9e64e.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043b\u043e\u0433\u0438\u043d\u0430 Keycloak \u0441 \u0444\u043e\u0440\u043c\u043e\u0439 \u0432\u0432\u043e\u0434\u0430\u00a0<code>access3<\/code><\/figcaption><\/div>\n<\/figure>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/661\/7f4\/e73\/6617f4e73f4c078abb5ba2098fe982bb.png\" alt=\" DevTools \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 (\u0432\u043a\u043b\u0430\u0434\u043a\u0430 Network), \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a\u00a0\/reports\u00a0\" title=\" DevTools \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 (\u0432\u043a\u043b\u0430\u0434\u043a\u0430 Network), \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a\u00a0\/reports\u00a0\" width=\"1836\" height=\"1305\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/661\/7f4\/e73\/6617f4e73f4c078abb5ba2098fe982bb.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/661\/7f4\/e73\/6617f4e73f4c078abb5ba2098fe982bb.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption> DevTools \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 (\u0432\u043a\u043b\u0430\u0434\u043a\u0430 Network), \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a\u00a0<code>\/reports<\/code>\u00a0<\/figcaption><\/div>\n<\/figure>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a55\/fe9\/287\/a55fe9287a27a06e7957f980e8d28e34.png\" alt=\"\u041e\u0442\u0432\u0435\u0442 \u043e\u0442\u00a0\/reports\u00a0\u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435, \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0447\u0451\u0442\u0430 \" title=\"\u041e\u0442\u0432\u0435\u0442 \u043e\u0442\u00a0\/reports\u00a0\u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435, \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0447\u0451\u0442\u0430 \" width=\"1404\" height=\"659\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/a55\/fe9\/287\/a55fe9287a27a06e7957f980e8d28e34.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a55\/fe9\/287\/a55fe9287a27a06e7957f980e8d28e34.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041e\u0442\u0432\u0435\u0442 \u043e\u0442\u00a0<code>\/reports<\/code>\u00a0\u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435, \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0447\u0451\u0442\u0430 <\/figcaption><\/div>\n<\/figure>\n<h4>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u044f<\/h4>\n<ul>\n<li>\n<p><strong>CORS<\/strong>: \u0415\u0441\u043b\u0438 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043e\u0442\u0432\u0435\u0442, \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 CORS \u0432\u00a0<code>server.js<\/code>\u00a0(<code>origin: '<\/code><a href=\"http:\/\/localhost:3000\" rel=\"noopener noreferrer nofollow\"><code>http:\/\/localhost:3000<\/code><\/a><code>'<\/code>).<\/p>\n<\/li>\n<li>\n<p><strong>JWT<\/strong>: \u0415\u0441\u043b\u0438 \u0442\u043e\u043a\u0435\u043d \u043d\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u00a0<code>report_user<\/code>, \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \u0440\u043e\u043b\u0435\u0439 \u0432 Keycloak (&#171;Role Mappings&#187;).<\/p>\n<\/li>\n<li>\n<p><strong>\u041b\u043e\u0433\u0438<\/strong>: \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u043a\u043e\u043d\u0441\u043e\u043b\u044c\u043d\u044b\u0435 \u043b\u043e\u0433\u0438 \u0432\u00a0<code>server.js<\/code>\u00a0\u0434\u043b\u044f \u043e\u0442\u043b\u0430\u0434\u043a\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0448\u0438\u0431\u043a\u0438 \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438).<\/p>\n<\/li>\n<\/ul>\n<h2>9. \u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438: \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c \u0447\u0435\u0440\u0435\u0437 Keycloak<\/h2>\n<p>\u041c\u044b \u043d\u0430\u0447\u0430\u043b\u0438 \u0441 \u0437\u0430\u0434\u0430\u0447\u0438:\u00a0\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u0438\u0437 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b\u00a0(<code>reports-frontend<\/code>)\u00a0\u043a API \u043e\u0442\u0447\u0451\u0442\u043e\u0432\u00a0(<code>reports-api<\/code>)\u00a0\u0447\u0435\u0440\u0435\u0437 \u043e\u0431\u0449\u0435\u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 Keycloak,\u00a0\u0447\u0442\u043e\u0431\u044b JWT-\u0442\u043e\u043a\u0435\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b \u0440\u043e\u043b\u044c\u00a0<code>report_user<\/code>.\u00a0\u0412 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 e-commerce \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043a\u0430\u043a \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430,\u00a0\u0433\u0434\u0435 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u044b \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u044e\u0442 \u043e\u0442\u0447\u0451\u0442\u044b \u043e \u043f\u0440\u043e\u0434\u0430\u0436\u0430\u0445,\u00a0\u0430 Keycloak \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0435\u0439 \u0447\u0435\u0440\u0435\u0437 Single Sign-On\u00a0(SSO).\u00a0\u041f\u043e\u0441\u043b\u0435 \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044f SSO,\u00a0OIDC,\u00a0Keycloak \u0438 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u00a0(\u0447\u0430\u0441\u0442\u044c 8)\u00a0\u043c\u044b \u0433\u043e\u0442\u043e\u0432\u044b \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c,\u00a0\u043a\u0430\u043a \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0440\u0435\u0448\u0430\u0435\u0442 \u044d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443.\u00a0\u0412 \u043a\u0440\u0443\u043f\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f\u0445 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043d\u0435 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 Keycloak \u0441\u0430\u043c,\u00a0\u0430 \u043f\u043e\u0434\u0430\u0451\u0442 \u0437\u0430\u044f\u0432\u043a\u0443\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u0432 Jira)\u00a0\u0438 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0438\u0440\u0443\u0435\u0442 \u0441 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430\u043c\u0438 Keycloak,\u00a0\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0438 API,\u00a0\u0430 \u0442\u0430\u043a\u0436\u0435 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430\u043c\u0438 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438.\u00a0\u041d\u0435\u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 OpenID Connect\u00a0(OIDC)\u00a0\u0438\u043b\u0438 Keycloak \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a \u043e\u0448\u0438\u0431\u043a\u0430\u043c \u0432 \u0437\u0430\u044f\u0432\u043a\u0435\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u0440\u043e\u043b\u0438\u00a0<code>report_user<\/code>\u00a0\u0432 \u0442\u043e\u043a\u0435\u043d\u0435)\u00a0\u0438\u043b\u0438 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0430\u043c \u0438\u0437-\u0437\u0430 \u043d\u0435\u044f\u0441\u043d\u043e\u0441\u0442\u0438,\u00a0\u0441 \u043a\u0435\u043c \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u0442\u044c \u0434\u0435\u0442\u0430\u043b\u0438.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u043d\u0430\u0447\u043d\u0451\u043c \u0441 \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u044b,\u00a0\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0435\u0439 \u043f\u043e\u0442\u043e\u043a \u0434\u043e\u0441\u0442\u0443\u043f\u0430:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9f1\/cb6\/9aa\/9f1cb69aae5616bafe02e664fb9cd5da.png\" alt=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430,\u00a0\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043b\u043e\u0433\u0438\u043d\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 Keycloak,\u00a0reports-frontend\u00a0\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0report_user,\u00a0\u0430\u00a0reports-api\u00a0\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430\" title=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430,\u00a0\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043b\u043e\u0433\u0438\u043d\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 Keycloak,\u00a0reports-frontend\u00a0\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0report_user,\u00a0\u0430\u00a0reports-api\u00a0\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430\" width=\"1812\" height=\"971\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/9f1\/cb6\/9aa\/9f1cb69aae5616bafe02e664fb9cd5da.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9f1\/cb6\/9aa\/9f1cb69aae5616bafe02e664fb9cd5da.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430,\u00a0\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043b\u043e\u0433\u0438\u043d\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 Keycloak,\u00a0<code>reports-frontend<\/code>\u00a0\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0<code>report_user<\/code>,\u00a0\u0430\u00a0<code>reports-api<\/code>\u00a0\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430<\/figcaption><\/div>\n<\/figure>\n<h4>\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430: \u043f\u043e\u0434\u0430\u0447\u0430 \u0437\u0430\u044f\u0432\u043a\u0438 \u0438 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0446\u0438\u044f<\/h4>\n<p>\u0412 \u043a\u0440\u0443\u043f\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0438\u043d\u0438\u0446\u0438\u0438\u0440\u0443\u0435\u0442 \u0437\u0430\u044f\u0432\u043a\u0443 \u043d\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 Keycloak,\u00a0\u0430 \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0435\u0451 \u0441\u0430\u043c.\u00a0\u042d\u0442\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0447\u0451\u0442\u043a\u043e\u0433\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u043c\u0438.\u00a0\u0411\u0435\u0437 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f OIDC \u0438 Keycloak \u0437\u0430\u044f\u0432\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435\u043f\u043e\u043b\u043d\u043e\u0439,\u00a0\u0447\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u0442 \u043a \u043e\u0448\u0438\u0431\u043a\u0430\u043c\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u0442\u043e\u043a\u0435\u043d \u0431\u0435\u0437\u00a0<code>report_user<\/code>).\u00a0\u0412\u043e\u0442 \u0448\u0430\u0433\u0438 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438:<\/p>\n<ol>\n<li>\n<p><strong>\u0421\u0431\u043e\u0440 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439<\/strong>:<\/p>\n<ul>\n<li>\n<p>\u0421 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430\u043c\u0438 API \u043e\u0442\u0447\u0451\u0442\u043e\u0432: \u041a\u0430\u043a\u0438\u0435 \u0440\u043e\u043b\u0438 \u043d\u0443\u0436\u043d\u044b? \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>report_user<\/code>\u00a0\u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043e\u0442\u0447\u0451\u0442\u0430\u043c,\u00a0<code>administrator<\/code>\u00a0\u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u043a\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 JWT? \u0420\u043e\u043b\u044c\u00a0<code>report_user<\/code>\u00a0\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u0430, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>department<\/code>\u00a0\u0434\u043b\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 \u043e\u0442\u0447\u0451\u0442\u043e\u0432).<\/p>\n<\/li>\n<li>\n<p>\u0420\u0438\u0441\u043a\u0438: \u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0435 \u0440\u043e\u043b\u0438 (\u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0447\u0443\u0436\u0438\u043c \u043e\u0442\u0447\u0451\u0442\u0430\u043c), \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432, \u043d\u0438\u0437\u043a\u0430\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>\u041f\u043e\u0434\u0430\u0447\u0430 \u0437\u0430\u044f\u0432\u043a\u0438<\/strong>:<\/p>\n<ul>\n<li>\n<p>\u0414\u043b\u044f \u0430\u0434\u043c\u0438\u043d\u043e\u0432 Keycloak: \u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0432 \u0437\u0430\u044f\u0432\u043a\u0443:<\/p>\n<ul>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 realm\u00a0<code>reports-realm<\/code>\u00a0(\u0438\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e).<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 (<code>access1<\/code>) \u0438\u043b\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044e \u0441 Active Directory (AD).<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0440\u043e\u043b\u0438\u00a0<code>report_user<\/code>\u00a0\u0438 \u0435\u0451 \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \u043d\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432:\u00a0<code>reports-frontend<\/code>\u00a0(public, redirect URI:\u00a0<a href=\"http:\/\/localhost:3000\/*\" rel=\"noopener noreferrer nofollow\"><code>http:\/\/localhost:3000\/*<\/code><\/a>, PKCE: Enforced),\u00a0<code>reports-api<\/code>\u00a0(bearer-only, \u0441 \u0441\u0435\u043a\u0440\u0435\u0442\u043e\u043c\u00a0<code>oNwoLQdvJAvRcL89SydqCWCe5ry1jMgq<\/code>).<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0442\u0435\u043a\u0441\u0442\u0430 \u0437\u0430\u044f\u0432\u043a\u0438:<\/p>\n<pre><code class=\"yaml\">\u0421\u043e\u0437\u0434\u0430\u0442\u044c realm reports-realm. \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f access1 \u0441 \u0440\u043e\u043b\u044c\u044e report_user. \u041d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u044b: - reports-frontend: public, redirect URI http:\/\/localhost:3000\/*, \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c PKCE (S256). - reports-api: bearer-only, \u0441\u0435\u043a\u0440\u0435\u0442 oNwoLQdvJAvRcL89SydqCWCe5ry1jMgq.<\/code><\/pre>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>\u041a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0446\u0438\u044f \u0441 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u043c\u0438<\/strong>:<\/p>\n<ul>\n<li>\n<p>\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b: \u0423\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e\u00a0<code>reports-frontend<\/code>\u00a0\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 OIDC \u0441 PKCE (\u043a\u0430\u043a \u0432\u00a0<code>App.tsx<\/code>,\u00a0<code>ReportPage.tsx<\/code>, \u0447\u0430\u0441\u0442\u044c 8).<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 API \u043e\u0442\u0447\u0451\u0442\u043e\u0432: \u041d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e JWT \u0441 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u043e\u0439\u00a0<code>report_user<\/code>\u00a0(\u043a\u0430\u043a \u0432\u00a0<code>server.js<\/code>, \u0447\u0430\u0441\u0442\u044c 8).<\/p>\n<\/li>\n<li>\n<p>DevOps: \u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c \u0437\u0430\u043f\u0443\u0441\u043a Keycloak \u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 (\u043a\u0430\u043a \u0432\u00a0<code>docker-compose.yml<\/code>, \u0447\u0430\u0441\u0442\u044c 8).<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b<\/strong>:<\/p>\n<ul>\n<li>\n<p>\u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439: AD (\u0434\u043b\u044f \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439) \u0438\u043b\u0438 PostgreSQL (\u0434\u043b\u044f \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u0430)?<\/p>\n<\/li>\n<li>\n<p>\u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c: HTTPS \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, PKCE \u0434\u043b\u044f\u00a0<code>reports-frontend<\/code>, MFA \u0434\u043b\u044f \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u044c: \u041f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043b\u0438 Keycloak \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u043e\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439?<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p><strong>\u0421\u0445\u0435\u043c\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438<\/strong>:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/333\/51d\/530\/33351d530f5730908e87001f3f05618b.png\" alt=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442,\u00a0\u043a\u0430\u043a \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0438\u0440\u0443\u0435\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u044f\u0432\u043a\u0443 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435.\" title=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442,\u00a0\u043a\u0430\u043a \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0438\u0440\u0443\u0435\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u044f\u0432\u043a\u0443 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435.\" width=\"1819\" height=\"761\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/333\/51d\/530\/33351d530f5730908e87001f3f05618b.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/333\/51d\/530\/33351d530f5730908e87001f3f05618b.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442,\u00a0\u043a\u0430\u043a \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0438\u0440\u0443\u0435\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u044f\u0432\u043a\u0443 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435.<\/figcaption><\/div>\n<\/figure>\n<p>\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d:<\/p>\n<ul>\n<li>\n<p>\u0421 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430\u043c\u0438 API: \u0423\u0442\u043e\u0447\u043d\u0438\u0442\u044c \u0440\u043e\u043b\u0438 (<code>report_user<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u0421 \u0430\u0434\u043c\u0438\u043d\u0430\u043c\u0438 Keycloak: \u041f\u043e\u0434\u0430\u0442\u044c \u0437\u0430\u044f\u0432\u043a\u0443 \u043d\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443\u00a0<code>reports-realm<\/code>, \u0440\u043e\u043b\u0435\u0439, \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>\u0421 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438: \u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c OIDC, PKCE, \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e JWT.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c: \u0414\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c JWT \u0432 DevTools, \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a\u00a0<code>\/reports<\/code>.<\/p>\n<\/li>\n<\/ul>\n<h2>10. \u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u041c\u044b \u043d\u0430\u0447\u0430\u043b\u0438 \u0441 \u0437\u0430\u0434\u0430\u0447\u0438:\u00a0\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u0438\u0437 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b\u00a0(<code>reports-frontend<\/code>)\u00a0\u043a API \u043e\u0442\u0447\u0451\u0442\u043e\u0432\u00a0(<code>reports-api<\/code>)\u00a0\u0447\u0435\u0440\u0435\u0437 \u043e\u0431\u0449\u0435\u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 Keycloak,\u00a0\u0447\u0442\u043e\u0431\u044b JWT-\u0442\u043e\u043a\u0435\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b \u0440\u043e\u043b\u044c\u00a0<code>report_user<\/code>.\u00a0\u0412 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 e-commerce \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043a\u0430\u043a \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430,\u00a0\u0433\u0434\u0435 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u044b \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u044e\u0442 \u043e\u0442\u0447\u0451\u0442\u044b \u043e \u043f\u0440\u043e\u0434\u0430\u0436\u0430\u0445,\u00a0\u0430 Keycloak \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0435\u0439 \u0447\u0435\u0440\u0435\u0437 Single Sign-On\u00a0(SSO).\u00a0\u0420\u0430\u0437\u043e\u0431\u0440\u0430\u0432 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u044b SSO,\u00a0OIDC,\u00a0\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b Keycloak\u00a0(realms,\u00a0\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430,\u00a0PKCE)\u00a0\u0438 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440\u00a0(\u0447\u0430\u0441\u0442\u044c 8),\u00a0\u043c\u044b \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0438,\u00a0\u043a\u0430\u043a \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0440\u0435\u0448\u0430\u0435\u0442 \u044d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443 \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u044f\u0432\u043a\u0438 \u0438 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0446\u0438\u044e \u0441 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u043c\u0438:\u00a0\u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430\u043c\u0438 Keycloak,\u00a0\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0438 API,\u00a0\u0430 \u0442\u0430\u043a\u0436\u0435 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430\u043c\u0438 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u0432\u043e\u0442 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u0445\u0435\u043c\u0430,\u00a0\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0430\u044f \u0440\u043e\u043b\u044c \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430 \u0432 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0446\u0438\u0438:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a17\/08d\/017\/a1708d0174c8b7cef6c1fe111b4ea664.png\" alt=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043f\u043e\u0434\u0430\u0451\u0442 \u0437\u0430\u044f\u0432\u043a\u0443 \u043d\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443\u00a0reports-realm,\u00a0\u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u044b\u0432\u0430\u0435\u0442 \u0440\u043e\u043b\u0438,\u00a0\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u0442 JWT \u0432 DevTools,\u00a0\u0447\u0442\u043e\u0431\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f,\u00a0\u0447\u0442\u043e \u0434\u043e\u0441\u0442\u0443\u043f \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.\" title=\"\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043f\u043e\u0434\u0430\u0451\u0442 \u0437\u0430\u044f\u0432\u043a\u0443 \u043d\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443\u00a0reports-realm,\u00a0\u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u044b\u0432\u0430\u0435\u0442 \u0440\u043e\u043b\u0438,\u00a0\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u0442 JWT \u0432 DevTools,\u00a0\u0447\u0442\u043e\u0431\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f,\u00a0\u0447\u0442\u043e \u0434\u043e\u0441\u0442\u0443\u043f \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.\" width=\"1162\" height=\"811\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/a17\/08d\/017\/a1708d0174c8b7cef6c1fe111b4ea664.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a17\/08d\/017\/a1708d0174c8b7cef6c1fe111b4ea664.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043f\u043e\u0434\u0430\u0451\u0442 \u0437\u0430\u044f\u0432\u043a\u0443 \u043d\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443\u00a0<code>reports-realm<\/code>,\u00a0\u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u044b\u0432\u0430\u0435\u0442 \u0440\u043e\u043b\u0438,\u00a0\u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u0442 JWT \u0432 DevTools,\u00a0\u0447\u0442\u043e\u0431\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f,\u00a0\u0447\u0442\u043e \u0434\u043e\u0441\u0442\u0443\u043f \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/figcaption><\/div>\n<\/figure>\n<h4>\u0418\u0442\u043e\u0433\u0438<\/h4>\n<p>Keycloak \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0437\u0430\u0434\u0430\u0447\u0443 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c \u0447\u0435\u0440\u0435\u0437 SSO:<\/p>\n<ul>\n<li>\n<p><strong>\u0426\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/strong>: \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043b\u043e\u0433\u0438\u043d\u044f\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u0447\u0435\u0440\u0435\u0437\u00a0<code>reports-realm<\/code>, \u043f\u043e\u043b\u0443\u0447\u0430\u044f \u0434\u043e\u0441\u0442\u0443\u043f \u043a\u00a0<code>reports-frontend<\/code>\u00a0\u0438\u00a0<code>reports-api<\/code>.<\/p>\n<\/li>\n<li>\n<p><strong>\u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c<\/strong>: \u0420\u043e\u043b\u044c\u00a0<code>report_user<\/code>\u00a0\u0432 JWT \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f, \u0430 PKCE \u0438 HTTPS \u0437\u0430\u0449\u0438\u0449\u0430\u044e\u0442 \u043e\u0442 \u0430\u0442\u0430\u043a.<\/p>\n<\/li>\n<li>\n<p><strong>\u0413\u0438\u0431\u043a\u043e\u0441\u0442\u044c<\/strong>: Keycloak \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 PostgreSQL \u0438\u043b\u0438 Active Directory \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u043b\u044f \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0443\u0440\u043e\u043a\u0438:<\/p>\n<ul>\n<li>\n<p><strong>\u0427\u0451\u0442\u043a\u0430\u044f \u0437\u0430\u044f\u0432\u043a\u0430<\/strong>: \u0423\u043a\u0430\u0437\u044b\u0432\u0430\u0439\u0442\u0435 \u0432 \u0437\u0430\u044f\u0432\u043a\u0435 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 Jira) \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435\u00a0<code>reports-realm<\/code>, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 (<code>access1<\/code>), \u0440\u043e\u043b\u0435\u0439 (<code>report_user<\/code>), \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 (<code>reports-frontend<\/code>,\u00a0<code>reports-api<\/code>), \u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 PKCE.<\/p>\n<\/li>\n<li>\n<p><strong>\u041a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0446\u0438\u044f<\/strong>: \u041e\u0431\u0441\u0443\u0436\u0434\u0430\u0439\u0442\u0435 \u0441 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430\u043c\u0438 API, \u043a\u0430\u043a\u0438\u0435 \u0440\u043e\u043b\u0438 \u043d\u0443\u0436\u043d\u044b, \u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u2014 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e OIDC, \u0441 \u0430\u0434\u043c\u0438\u043d\u0430\u043c\u0438 \u2014 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 Keycloak.<\/p>\n<\/li>\n<li>\n<p><strong>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/strong>: \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0439\u0442\u0435 JWT \u0432 DevTools (\u043a\u0430\u043a \u0432 \u0447\u0430\u0441\u0442\u044f\u0445 8\u20139), \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u0443\u044f \u0442\u043e\u043a\u0435\u043d \u043d\u0430 <a href=\"http:\/\/jwt.io\" rel=\"noopener noreferrer nofollow\">jwt.io<\/a>, \u0447\u0442\u043e\u0431\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043e\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u00a0<code>realm_access.roles: [\"report_user\"]<\/code>.<\/p>\n<\/li>\n<\/ul>\n<h4>\u0422\u0438\u043f\u0438\u0447\u043d\u044b\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b<\/h4>\n<ul>\n<li>\n<p><strong>\u041d\u0435\u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 OIDC<\/strong>: \u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0437\u043d\u0430\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 (\u0440\u043e\u043b\u0438, \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b) \u043d\u0443\u0436\u043d\u044b \u0432 JWT \u0438\u043b\u0438 \u0441 \u043a\u0435\u043c \u0438\u0445 \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u0442\u044c.<\/p>\n<\/li>\n<li>\n<p><strong>\u041e\u0448\u0438\u0431\u043a\u0438 \u0432 \u0437\u0430\u044f\u0432\u043a\u0435<\/strong>: \u041d\u0435\u043f\u043e\u043b\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435\u00a0<code>report_user<\/code>) \u043f\u0440\u0438\u0432\u043e\u0434\u044f\u0442 \u043a \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u043c \u0442\u043e\u043a\u0435\u043d\u0430\u043c.<\/p>\n<\/li>\n<li>\n<p><strong>\u0417\u0430\u0434\u0435\u0440\u0436\u043a\u0438<\/strong>: \u041d\u0435\u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u043d\u043d\u043e\u0441\u0442\u044c \u043c\u0435\u0436\u0434\u0443 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u043c\u0438 \u0442\u043e\u0440\u043c\u043e\u0437\u0438\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443.<\/p>\n<\/li>\n<\/ul>\n<h4>\u0427\u0442\u043e \u0434\u0430\u043b\u044c\u0448\u0435<\/h4>\n<p>\u0414\u043b\u044f \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438:<\/p>\n<ul>\n<li>\n<p><strong>MFA<\/strong>: \u0412\u043a\u043b\u044e\u0447\u0438\u0442\u0435 \u043c\u043d\u043e\u0433\u043e\u0444\u0430\u043a\u0442\u043e\u0440\u043d\u0443\u044e \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e \u0432 Keycloak \u0434\u043b\u044f \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d\u0430.<\/p>\n<\/li>\n<li>\n<p><strong>AD-\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f<\/strong>: \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 User Federation \u0434\u043b\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438\u0437 Active Directory.<\/p>\n<\/li>\n<li>\n<p><strong>\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f<\/strong>: \u0412\u0435\u0434\u0438\u0442\u0435 \u0440\u0435\u0435\u0441\u0442\u0440 \u0440\u043e\u043b\u0435\u0439 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0430\u0443\u0434\u0438\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p><strong>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/strong>: \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 penetration testing \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430\u043c \u0441\u0442\u043e\u0438\u0442 \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e Keycloak\u00a0(<a href=\"https:\/\/www.keycloak.org\/docs\" rel=\"noopener noreferrer nofollow\">https:\/\/www.keycloak.org\/docs<\/a>)\u00a0\u0438 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0437 \u0447\u0430\u0441\u0442\u0438 8:\u00a0\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u043f\u0440\u043e\u0435\u043a\u0442,\u00a0\u043f\u043e\u0434\u0430\u0439\u0442\u0435 \u0442\u0435\u0441\u0442\u043e\u0432\u0443\u044e \u0437\u0430\u044f\u0432\u043a\u0443 \u043d\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443\u00a0<code>reports-realm<\/code>,\u00a0\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 JWT \u0432 DevTools.\u00a0\u042d\u0442\u043e \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0443\u0432\u0435\u0440\u0435\u043d\u043d\u043e \u0440\u0435\u0448\u0430\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0438 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c!<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \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\/927286\/\"> https:\/\/habr.com\/ru\/articles\/927286\/<\/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<h2>1. \u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435: \u041f\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u0434\u0430\u0447\u0438 \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435<\/h2>\n<p>\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u044c\u0442\u0435,\u00a0\u0447\u0442\u043e \u0432\u044b\u00a0\u2014\u00a0\u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0432 \u043a\u0440\u0443\u043f\u043d\u043e\u0439 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438,\u00a0\u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0435\u0439 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043c\u0430\u0433\u0430\u0437\u0438\u043d\u043e\u043c.\u00a0\u0423 \u0432\u0430\u0441 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c:\u00a0\u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430\u00a0(\u0432\u0435\u0431-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430,\u00a0\u0433\u0434\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u044b \u043f\u0440\u043e\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u044e\u0442 \u0442\u043e\u0432\u0430\u0440\u044b \u0438 \u043e\u0444\u043e\u0440\u043c\u043b\u044f\u044e\u0442 \u0437\u0430\u043a\u0430\u0437\u044b),\u00a0\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043a\u0430\u0437\u043e\u0432\u00a0(backend,\u00a0\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u043a\u0430\u0437\u0430\u043c\u0438 \u0438 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u043e\u0439)\u00a0\u0438 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0434\u043b\u044f \u043e\u0442\u0447\u0451\u0442\u043e\u0432.\u00a0\u041f\u0440\u0438\u043b\u0435\u0442\u0430\u0435\u0442 \u0437\u0430\u0434\u0430\u0447\u0430:\u00a0\u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u0438\u0437 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430 \u043a \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043a\u0430\u0437\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 \u043e\u0431\u0449\u0435\u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 Keycloak\u00a0\u2014\u00a0\u0435\u0434\u0438\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438\u00a0(Identity Provider,\u00a0IdP).\u00a0\u0426\u0435\u043b\u044c\u00a0\u2014\u00a0\u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u044b \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430)\u00a0\u043c\u043e\u0433\u043b\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\u00a0(\u0441\u043a\u0430\u0436\u0435\u043c,\u00a0\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u0442\u044c \u0437\u0430\u043a\u0430\u0437\u044b),\u00a0\u0430 JWT-\u0442\u043e\u043a\u0435\u043d,\u00a0\u0432\u044b\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u0439 Keycloak,\u00a0\u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b \u043d\u0443\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435,\u00a0\u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u0440\u043e\u043b\u044c\u00a0<code>order_manager<\/code>\u00a0\u0438\u043b\u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442 \u043e\u0442\u0434\u0435\u043b\u0430.<\/p>\n<p>\u042d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0441 \u043d\u0443\u043b\u044f,\u00a0\u0430 \u0442\u0438\u043f\u0438\u0447\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430:\u00a0\u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0432 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435,\u00a0\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c,\u00a0\u043a\u0430\u043a\u0438\u0435 \u0440\u043e\u043b\u0438 \u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u043d\u0443\u0436\u043d\u044b,\u00a0\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044e.\u00a0\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0442\u043e\u043c,\u00a0\u0447\u0442\u043e \u0431\u0435\u0437 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f,\u00a0\u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 Keycloak \u0438 OIDC,\u00a0\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043c\u043e\u0436\u0435\u0442\u00a0&#171;\u0437\u0430\u043b\u0438\u043f\u043d\u0443\u0442\u044c&#187;.\u00a0\u0421 \u043a\u0435\u043c \u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f?\u00a0\u0421 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b,\u00a0\u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0442\u043e\u043a\u0435\u043d\u043e\u0432?\u00a0\u0421 \u0430\u0434\u043c\u0438\u043d\u0430\u043c\u0438 Keycloak,\u00a0\u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b\u0438 realm?\u00a0\u0421 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430\u043c\u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0437\u0430\u043a\u0430\u0437\u043e\u0432,\u00a0\u0447\u0442\u043e\u0431\u044b \u0443\u0442\u043e\u0447\u043d\u0438\u0442\u044c \u0440\u043e\u043b\u0438?\u00a0\u0418 \u0447\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u0442\u044c:\u00a0\u043a\u0430\u043a\u0438\u0435 scopes,\u00a0\u043a\u0430\u043a \u043c\u0430\u043f\u043f\u0438\u0442\u044c \u0440\u043e\u043b\u0438,\u00a0\u043a\u0430\u043a \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043a\u0435\u043d\u044b?\u00a0\u041d\u0435\u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0430\u043c,\u00a0\u043e\u0448\u0438\u0431\u043a\u0430\u043c \u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0430\u0445\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u0432\u0438\u0434\u0438\u0442 \u0447\u0443\u0436\u0438\u0435 \u0437\u0430\u043a\u0430\u0437\u044b)\u00a0\u0438\u043b\u0438 \u0434\u0430\u0436\u0435 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u044f\u043c.<\/p>\n<p>\u0426\u0435\u043b\u044c \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438\u00a0\u2014\u00a0\u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c,\u00a0\u043a\u0430\u043a \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u043c\u0443 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0443 \u043f\u043e\u0434\u043e\u0439\u0442\u0438 \u043a \u0442\u0430\u043a\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0435.\u00a0\u041c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u044b Single Sign-On\u00a0(SSO)\u00a0\u0438 OpenID Connect\u00a0(OIDC),\u00a0\u0438\u0437\u0443\u0447\u0438\u043c Keycloak \u043a\u0430\u043a \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0438\u0445 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438,\u00a0\u0438 \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u00a0(React-frontend,\u00a0Node.js-backend,\u00a0Docker)\u00a0\u043f\u043e\u043a\u0430\u0436\u0435\u043c,\u00a0\u043a\u0430\u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f.\u00a0\u0412 \u043a\u043e\u043d\u0446\u0435 \u0432\u0435\u0440\u043d\u0451\u043c\u0441\u044f \u043a \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0435 \u0438 \u043e\u0431\u044a\u044f\u0441\u043d\u0438\u043c,\u00a0\u043a\u0430\u043a \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c,\u00a0\u0447\u0442\u043e\u0431\u044b JWT \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b \u043d\u0443\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435,\u00a0\u0438 \u0447\u0442\u043e \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a.\u00a0\u042d\u0442\u043e \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u0448\u0438\u0442\u044c \u0437\u0430\u0434\u0430\u0447\u0443,\u00a0\u043d\u043e \u0438 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u0442\u0438\u043f\u0438\u0447\u043d\u044b\u0445 \u043e\u0448\u0438\u0431\u043e\u043a \u0432 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445.<\/p>\n<p>\u0414\u043b\u044f <strong>\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432<\/strong> \u0441\u0442\u0430\u0442\u044c\u044f \u0434\u0430\u0451\u0442 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 OIDC \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c PKCE \u0438 \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 JWT. \u042d\u0442\u043e \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0441\u0442\u0440\u043e \u0432\u043d\u0435\u0434\u0440\u0438\u0442\u044c SSO \u0431\u0435\u0437 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438. \u0414\u043b\u044f <strong>\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u043e\u0440\u043e\u0432<\/strong> \u0441\u0442\u0430\u0442\u044c\u044f \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442, \u043a\u0430\u043a Keycloak \u0432\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043d\u0443\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u044c (\u0447\u0435\u0440\u0435\u0437 PostgreSQL \u0438\u043b\u0438 Active Directory) \u0438 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c (PKCE, HTTPS). <\/p>\n<h2>2. \u041f\u0440\u0438\u043d\u0446\u0438\u043f\u044b SSO \u0438 OIDC<\/h2>\n<p>Single Sign-On\u00a0(SSO)\u00a0\u0438 OpenID Connect\u00a0(OIDC)\u00a0\u2014\u00a0\u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0438:\u00a0\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u0438\u0437 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b\u00a0(<code>reports-frontend<\/code>)\u00a0\u043a API \u043e\u0442\u0447\u0451\u0442\u043e\u0432\u00a0(<code>reports-api<\/code>)\u00a0\u0447\u0435\u0440\u0435\u0437 \u043e\u0431\u0449\u0435\u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 Keycloak,\u00a0\u0447\u0442\u043e\u0431\u044b JWT-\u0442\u043e\u043a\u0435\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b \u0440\u043e\u043b\u044c\u00a0<code>report_user<\/code>.\u00a0\u0412 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 e-commerce \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043a\u0430\u043a \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430,\u00a0\u0433\u0434\u0435 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u044b \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u044e\u0442 \u043e\u0442\u0447\u0451\u0442\u044b \u043e \u043f\u0440\u043e\u0434\u0430\u0436\u0430\u0445,\u00a0\u0430 Keycloak \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0435\u0439.\u00a0\u0414\u043b\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 SSO \u0438 OIDC \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u043e,\u00a0\u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0441\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0437\u0430\u044f\u0432\u043a\u0443 \u043d\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0438 \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u0442\u044c \u0441 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u043c\u0438\u00a0(\u0430\u0434\u043c\u0438\u043d\u044b Keycloak,\u00a0\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438,\u00a0\u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u044b API),\u00a0\u043a\u0430\u043a\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0432 \u0442\u043e\u043a\u0435\u043d\u0435.\u00a0\u0411\u0435\u0437 \u044d\u0442\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0437\u043d\u0430\u0442\u044c,\u00a0\u0447\u0442\u043e \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u0442\u044c\u00a0(\u0440\u043e\u043b\u0438,\u00a0\u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b)\u00a0\u0438 \u0441 \u043a\u0435\u043c,\u00a0\u0447\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u0442 \u043a \u043e\u0448\u0438\u0431\u043a\u0430\u043c,\u00a0\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u044e \u0440\u043e\u043b\u0438 \u0432 JWT.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u043d\u0430\u0447\u043d\u0451\u043c \u0441 \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u044b,\u00a0\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0435\u0439 \u043f\u043e\u0442\u043e\u043a OIDC:<\/p>\n<figure class=\"full-width\">\n<div><figcaption>\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043b\u043e\u0433\u0438\u043d\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 Keycloak,\u00a0\u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u0441 \u0440\u043e\u043b\u044c\u044e\u00a0<code>report_user<\/code>,\u00a0\u0430 API \u043e\u0442\u0447\u0451\u0442\u043e\u0432 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d,\u00a0\u0447\u0442\u043e\u0431\u044b \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0447\u0451\u0442\u0430.<\/figcaption><\/div>\n<\/figure>\n<h4>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 SSO<\/h4>\n<p>SSO\u00a0(Single Sign-On)\u00a0\u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0432\u043e\u0439\u0442\u0438 \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a\u043e \u0432\u0441\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0451\u043d\u043d\u044b\u043c \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u043c \u0431\u0435\u0437 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0433\u043e \u0432\u0432\u043e\u0434\u0430 \u043b\u043e\u0433\u0438\u043d\u0430 \u0438 \u043f\u0430\u0440\u043e\u043b\u044f.\u00a0\u0412 \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0435 \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442,\u00a0\u0447\u0442\u043e \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u0432\u0445\u043e\u0434\u0438\u0442 \u0432\u00a0<code>reports-frontend<\/code>\u00a0\u0438 \u0441\u0440\u0430\u0437\u0443 \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0438\u0442\u044c \u043e\u0442\u0447\u0451\u0442\u044b \u0447\u0435\u0440\u0435\u0437\u00a0<code>reports-api<\/code>.\u00a0SSO:<\/p>\n<ul>\n<li>\n<p><strong>\u0423\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u043e\u043f\u044b\u0442<\/strong>: \u041e\u0434\u0438\u043d \u043b\u043e\u0433\u0438\u043d \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0441\u0438\u0441\u0442\u0435\u043c.<\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u043e\u0432\u044b\u0448\u0430\u0435\u0442 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c<\/strong>: \u0426\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 Keycloak.<\/p>\n<\/li>\n<li>\n<p><strong>\u0421\u043d\u0438\u0436\u0430\u0435\u0442 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443<\/strong>: \u041c\u0435\u043d\u044c\u0448\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 IT-\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443.<\/p>\n<\/li>\n<\/ul>\n<p>SSO \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 Identity Provider\u00a0(IdP),\u00a0\u0442\u0430\u043a\u043e\u0439 \u043a\u0430\u043a Keycloak,\u00a0\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u0432\u044b\u0434\u0430\u0451\u0442 \u0442\u043e\u043a\u0435\u043d\u044b.\u00a0\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043d\u044f\u0442\u044c,\u00a0\u043a\u0430\u043a\u0438\u0435 \u0440\u043e\u043b\u0438\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>report_user<\/code>)\u00a0\u043d\u0443\u0436\u043d\u044b \u0432 \u0442\u043e\u043a\u0435\u043d\u0435 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a API.<\/p>\n<h4>OpenID Connect (OIDC) \u0438 \u0435\u0433\u043e \u0440\u043e\u043b\u044c<\/h4>\n<p>OIDC\u00a0\u2014\u00a0\u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438,\u00a0\u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u043f\u043e\u0432\u0435\u0440\u0445 OAuth 2.0,\u00a0\u0440\u0435\u0448\u0430\u044e\u0449\u0438\u0439 \u0434\u0432\u0435 \u0437\u0430\u0434\u0430\u0447\u0438:<\/p>\n<ul>\n<li>\n<p><strong>\u0410\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f<\/strong>: \u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u0435\u0442, \u043a\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>access1<\/code>).<\/p>\n<\/li>\n<li>\n<p><strong>\u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f<\/strong>: \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442, \u0447\u0442\u043e \u043e\u043d \u043c\u043e\u0436\u0435\u0442 \u0434\u0435\u043b\u0430\u0442\u044c (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043e\u0442\u0447\u0451\u0442\u0430\u043c \u0447\u0435\u0440\u0435\u0437\u00a0<code>report_user<\/code>).<\/p>\n<\/li>\n<\/ul>\n<p>OIDC \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 Authorization Code Flow:<\/p>\n<ol>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0437\u0430\u0445\u043e\u0434\u0438\u0442 \u0432\u00a0<code>reports-frontend<\/code>\u00a0\u0438 \u043a\u043b\u0438\u043a\u0430\u0435\u0442 &#171;\u0412\u043e\u0439\u0442\u0438&#187;.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u0430 Keycloak \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u043d\u0430.<\/p>\n<\/li>\n<li>\n<p>Keycloak \u0432\u044b\u0434\u0430\u0451\u0442 authorization code, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u043c\u0435\u043d\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 JWT-\u0442\u043e\u043a\u0435\u043d\u044b (ID Token \u0434\u043b\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438, Access Token \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430).<\/p>\n<\/li>\n<li>\n<p><code>reports-frontend<\/code>\u00a0\u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 Access Token \u043d\u0430\u00a0<code>\/reports<\/code>, \u0433\u0434\u0435 API \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0440\u043e\u043b\u044c\u00a0<code>report_user<\/code>.<\/p>\n<\/li>\n<\/ol>\n<p>\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u0442\u044c,\u00a0\u0447\u0442\u043e\u0431\u044b JWT \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b\u00a0<code>report_user<\/code>,\u00a0\u0438 \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c \u044d\u0442\u043e \u0441 \u0430\u0434\u043c\u0438\u043d\u0430\u043c\u0438 Keycloak \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 API.<\/p>\n<h4>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 JWT<\/h4>\n<p>JWT\u00a0(JSON Web Token)\u00a0\u2014\u00a0\u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u044b\u0439 \u0442\u043e\u043a\u0435\u043d \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON,\u00a0\u0432\u044b\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u0439 Keycloak.\u00a0\u041e\u043d \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0442\u0440\u0451\u0445 \u0447\u0430\u0441\u0442\u0435\u0439:\u00a0Header,\u00a0Payload,\u00a0Signature\u00a0(\u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u044b \u0442\u043e\u0447\u043a\u0430\u043c\u0438,\u00a0\u0437\u0430\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0432 base64).\u00a0Payload \u0432\u0430\u0436\u0435\u043d \u0434\u043b\u044f \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430,\u00a0\u0442\u0430\u043a \u043a\u0430\u043a \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442:<\/p>\n<ul>\n<li>\n<p><code>sub<\/code>: ID \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>access1<\/code>).<\/p>\n<\/li>\n<li>\n<p><code>name<\/code>,\u00a0<code>email<\/code>: \u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>access1@example.com<\/code>).<\/p>\n<\/li>\n<li>\n<p><code>realm_access.roles<\/code>: \u0420\u043e\u043b\u0438 \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 realm (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>[\"report_user\"]<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b: \u0415\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>department<\/code>), \u0438\u0445 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442 \u0447\u0435\u0440\u0435\u0437 \u043c\u0430\u043f\u043f\u0435\u0440\u044b \u0432 Keycloak.<\/p>\n<\/li>\n<\/ul>\n<p>\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0443\u0442\u043e\u0447\u043d\u0438\u0442\u044c \u0443 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0435\u0432 API,\u00a0\u043a\u0430\u043a\u0438\u0435 \u0440\u043e\u043b\u0438\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>report_user<\/code>)\u00a0\u043d\u0443\u0436\u043d\u044b \u0432 \u0442\u043e\u043a\u0435\u043d\u0435,\u00a0\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u044d\u0442\u043e \u0432 \u0437\u0430\u044f\u0432\u043a\u0435.<\/p>\n<h4>\u0421\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u0441 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430\u043c\u0438<\/h4>\n<p>OIDC\u00a0\u2014\u00a0\u043b\u0443\u0447\u0448\u0438\u0439 \u0432\u044b\u0431\u043e\u0440 \u0434\u043b\u044f \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439,\u00a0\u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a\u00a0<code>reports-frontend<\/code>:<\/p>\n<ul>\n<li>\n<p><strong>SAML<\/strong>: \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 XML, \u0441\u043b\u043e\u0436\u043d\u0435\u0435 \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435, \u0434\u043b\u044f \u0441\u0442\u0430\u0440\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c.<\/p>\n<\/li>\n<li>\n<p><strong>OAuth 2.0<\/strong>: \u0422\u043e\u043b\u044c\u043a\u043e \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f, \u0431\u0435\u0437 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>Kerberos<\/strong>: \u0414\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u0435\u0442\u0435\u0439, \u043d\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0432\u0435\u0431\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>OIDC \u043f\u0440\u043e\u0441\u0442 \u0432 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f JSON \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0435 Keycloak.<\/p>\n<h4>\u0420\u0438\u0441\u043a\u0438 \u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430<\/h4>\n<p>OIDC \u0443\u044f\u0437\u0432\u0438\u043c \u0431\u0435\u0437 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438:<\/p>\n<ul>\n<li>\n<p><strong>CSRF-\u0430\u0442\u0430\u043a\u0438<\/strong>: \u0417\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u043f\u043e\u0434\u0434\u0435\u043b\u044b\u0432\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441. \u0417\u0430\u0449\u0438\u0449\u0430\u0435\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u00a0<code>state<\/code>\u00a0(\u0441\u043b\u0443\u0447\u0430\u0439\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c\u0430\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c).<\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u0435\u0440\u0435\u0445\u0432\u0430\u0442 \u0442\u043e\u043a\u0435\u043d\u043e\u0432<\/strong>: \u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f HTTPS.<\/p>\n<\/li>\n<li>\n<p><strong>\u041e\u0448\u0438\u0431\u043a\u0438 \u0432 \u0442\u043e\u043a\u0435\u043d\u0435<\/strong>: \u0415\u0441\u043b\u0438\u00a0<code>report_user<\/code>\u00a0\u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442, \u0434\u043e\u0441\u0442\u0443\u043f \u043d\u0435 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/p>\n<\/li>\n<\/ul>\n<p>\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c:<\/p>\n<ul>\n<li>\n<p>\u0412\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u00a0<code>state<\/code>\u00a0\u0434\u043b\u044f \u0437\u0430\u0449\u0438\u0442\u044b.<\/p>\n<\/li>\n<li>\n<p>\u0420\u043e\u043b\u0438 \u0432 JWT (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>report_user<\/code>).<\/p>\n<\/li>\n<li>\n<p>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u043e\u0432 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430 <a href=\"http:\/\/jwt.io\" rel=\"noopener noreferrer nofollow\">jwt.io<\/a>).<\/p>\n<\/li>\n<\/ul>\n<p>\u0411\u0435\u0437 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f OIDC \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0437\u043d\u0430\u0442\u044c,\u00a0\u0447\u0442\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0432 \u0437\u0430\u044f\u0432\u043a\u0443 \u0438\u043b\u0438 \u0441 \u043a\u0435\u043c \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c,\u00a0\u0447\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u0442 \u043a \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0430\u043c.<\/p>\n<h2>3. Keycloak \u043a\u0430\u043a \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 OIDC<\/h2>\n<p>Keycloak\u00a0\u2014\u00a0\u044d\u0442\u043e \u043c\u043e\u0449\u043d\u044b\u0439 open-source \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0435\u0439 \u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c\u00a0(Identity and Access Management,\u00a0IAM),\u00a0\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 Single Sign-On\u00a0(SSO)\u00a0\u0447\u0435\u0440\u0435\u0437 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b OpenID Connect\u00a0(OIDC).\u00a0\u0412 \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0435 Keycloak \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u043a\u0430\u043a \u043e\u0431\u0449\u0435\u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 Identity Provider\u00a0(IdP),\u00a0\u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u044f \u0434\u043e\u0441\u0442\u0443\u043f \u0438\u0437 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0\u0432\u0435\u0431-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0434\u043b\u044f \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u043e\u0432)\u00a0\u043a \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043a\u0430\u0437\u043e\u0432.\u00a0Keycloak \u0431\u0435\u0440\u0451\u0442 \u043d\u0430 \u0441\u0435\u0431\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0432\u044b\u0434\u0430\u0447\u0443 JWT-\u0442\u043e\u043a\u0435\u043d\u043e\u0432 \u0441 \u0440\u043e\u043b\u044f\u043c\u0438\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>order_manager<\/code>)\u00a0\u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430\u043c\u0438\u00a0(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>department: sales<\/code>).\u00a0\u0414\u043b\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430 \u044d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 Keycloak \u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438,\u00a0\u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u0438 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430\u043c\u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b,\u00a0\u0447\u0442\u043e\u0431\u044b \u0442\u043e\u043a\u0435\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043b \u043d\u0443\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435,\u00a0\u0430 \u0434\u043e\u0441\u0442\u0443\u043f \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u043d\u0430\u0447\u043d\u0451\u043c \u0441 \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u044b,\u00a0\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0435\u0439,\u00a0\u043a\u0430\u043a Keycloak \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443 \u0437\u0430\u043a\u0430\u0437\u043e\u0432:<\/p>\n<figure class=\"full-width\">\n<div><figcaption>\u042d\u0442\u0430 \u0441\u0445\u0435\u043c\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442:\u00a0Keycloak \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 realm\u00a0(<code>store-realm<\/code>),\u00a0\u0433\u0434\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0438 \u0440\u043e\u043b\u0438.\u00a0\u0424\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430\u00a0(<code>store-frontend<\/code>)\u00a0\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 JWT \u043f\u043e\u0441\u043b\u0435 \u043b\u043e\u0433\u0438\u043d\u0430,\u00a0\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0437\u0430\u043a\u0430\u0437\u043e\u0432\u00a0(<code>orders-api<\/code>)\u00a0\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u043e\u043a\u0435\u043d,\u00a0\u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f.<\/figcaption><\/div>\n<\/figure>\n<h4>\u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 Keycloak<\/h4>\n<p>Keycloak \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0437\u0430\u0434\u0430\u0447\u0443 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430 \u0432 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445,\u00a0\u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a \u043d\u0430\u0448 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442-\u043c\u0430\u0433\u0430\u0437\u0438\u043d:<\/p>\n<ul>\n<li>\n<p><strong>\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f<\/strong>: \u041f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 OIDC \u0434\u043b\u044f \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u044f JSON-\u0442\u043e\u043a\u0435\u043d\u044b (JWT) \u0441 \u0440\u043e\u043b\u044f\u043c\u0438 \u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>\u0413\u0438\u0431\u043a\u043e\u0441\u0442\u044c<\/strong>: \u041f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c SSO \u043c\u0435\u0436\u0434\u0443 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439 \u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u043e\u0439 \u0437\u0430\u043a\u0430\u0437\u043e\u0432, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441 Active Directory \u0438\u043b\u0438 Google.<\/p>\n<\/li>\n<li>\n<p><strong>\u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c<\/strong>: \u0412\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u044b, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0430\u0440\u043e\u043b\u0435\u0439, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 MFA \u0438 \u0437\u0430\u0449\u0438\u0442\u0430 \u043e\u0442 \u0430\u0442\u0430\u043a (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0435\u0440\u0435\u0437 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u00a0<code>state<\/code>).<\/p>\n<\/li>\n<li>\n<p><strong>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441<\/strong>: \u0412\u0435\u0431-\u0430\u0434\u043c\u0438\u043d\u043a\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0443 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u0440\u043e\u043b\u0438 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u0431\u0435\u0437 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p><strong>Open-source<\/strong>: \u0411\u0435\u0441\u043f\u043b\u0430\u0442\u0435\u043d, \u0441 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u043e\u043c \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c \u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u044b,\u00a0\u043a\u0430\u043a \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u0442\u043e\u043a\u0435\u043d\u044b,\u00a0\u0441 \u0430\u0434\u043c\u0438\u043d\u0430\u043c\u0438 Keycloak\u00a0\u2014\u00a0\u043a\u0430\u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0440\u043e\u043b\u0438 \u0432 realm,\u00a0\u0438 \u0441 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430\u043c\u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0437\u0430\u043a\u0430\u0437\u043e\u0432\u00a0\u2014\u00a0\u043a\u0430\u043a\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0443\u0436\u043d\u044b \u0432 JWT.<\/p>\n<h4>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b Keycloak<\/h4>\n<p>Keycloak \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432,\u00a0\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c,\u00a0\u0447\u0442\u043e\u0431\u044b \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438:<\/p>\n<ul>\n<li>\n<p><strong>Realms<\/strong>: \u0418\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 &#171;\u0434\u043e\u043c\u0435\u043d\u044b&#187; \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u0440\u043e\u043b\u0435\u0439 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>store-realm<\/code>\u00a0\u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u043c\u0430\u0433\u0430\u0437\u0438\u043d\u0430 \u0438 \u0438\u0445 \u0440\u043e\u043b\u0438.<\/p>\n<\/li>\n<li>\n<p><strong>Clients<\/strong>: \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u044e\u0449\u0438\u0435\u0441\u044f \u043a Keycloak. \u0412 \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0435 \u044d\u0442\u043e\u00a0<code>store-frontend<\/code>\u00a0(\u0444\u0440\u043e\u043d\u0442-\u0441\u0438\u0441\u0442\u0435\u043c\u0430) \u0438\u00a0<code>orders-api<\/code>\u00a0(\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u0437\u0430\u043a\u0430\u0437\u043e\u0432). Clients \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442 redirect URI \u0438 scopes (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u0430\u043a\u0438\u0435 \u0440\u043e\u043b\u0438 \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0432 JWT).<\/p>\n<\/li>\n<li>\n<p><strong>Users \u0438 Roles<\/strong>: \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>access1<\/code>) \u0438 \u0438\u0445 \u0440\u043e\u043b\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>order_manager<\/code>). \u0420\u043e\u043b\u0438 \u0431\u044b\u0432\u0430\u044e\u0442 \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 realm \u0438\u043b\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p><strong>Flows<\/strong>: \u041d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438 \u043b\u043e\u0433\u0438\u043d\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0430\u0440\u043e\u043b\u044f \u0438\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 MFA.<\/p>\n<\/li>\n<\/ul>\n<p>\u042d\u0442\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0432\u043c\u0435\u0441\u0442\u0435:\u00a0realm \u0438\u0437\u043e\u043b\u0438\u0440\u0443\u0435\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438,\u00a0client \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442 \u0442\u043e\u043a\u0435\u043d\u044b,\u00a0\u0430 \u0440\u043e\u043b\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442 \u0434\u043e\u0441\u0442\u0443\u043f.\u00a0\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c,\u00a0\u0447\u0442\u043e\u0431\u044b\u00a0<code>order_manager<\/code>\u00a0\u043f\u043e\u043f\u0430\u043b\u0430 \u0432 JWT \u0434\u043b\u044f \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0437\u0430\u043a\u0430\u0437\u043e\u0432.<\/p>\n<h4>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0438 \u0431\u0430\u0437\u043e\u0432\u0430\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430<\/h4>\n<p>\u0414\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438\u043b\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 Keycloak \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 Docker \u0441 PostgreSQL \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445.\u00a0\u042d\u0442\u043e \u043d\u0435 \u0437\u0430\u0434\u0430\u0447\u0430 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0430,\u00a0\u043d\u043e \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441,\u00a0\u0447\u0442\u043e\u0431\u044b \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c \u0435\u0433\u043e \u0441 DevOps \u0438\u043b\u0438 \u0430\u0434\u043c\u0438\u043d\u0430\u043c\u0438.\u00a0\u0412\u043e\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u00a0<code>docker-compose.yml<\/code>:<\/p>\n<pre><code class=\"yaml\">services:   keycloak_db:     image: postgres:14     environment:       POSTGRES_DB: keycloak_db       POSTGRES_USER: keycloak_user       POSTGRES_PASSWORD: keycloak_password     volumes:       - .\/postgres-keycloak-data:\/var\/lib\/postgresql\/data     ports:       - \"5433:5432\"     healthcheck:       test: [\"CMD-SHELL\", \"pg_isready -U keycloak_user -d keycloak_db\"]       interval: 5s       timeout: 5s       retries: 5    keycloak:     image: quay.io\/keycloak\/keycloak:21.1     environment:       KEYCLOAK_ADMIN: admin       KEYCLOAK_ADMIN_PASSWORD: admin       KC_DB: postgres       KC_DB_URL:<\/code><\/pre>\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-467509","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/467509","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=467509"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/467509\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=467509"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=467509"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=467509"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}