{"id":329712,"date":"2022-02-16T15:02:47","date_gmt":"2022-02-16T15:02:47","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=329712"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2022-02-16T15:02:47","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=329712","title":{"rendered":"<span>\u041f\u0440\u0438\u043a\u0440\u0443\u0447\u0438\u0432\u0430\u0435\u043c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 KeyCloak \u043a \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0416\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u0439 \u0446\u0438\u043a\u043b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 \u043f\u0440\u0438\u0432\u0435\u043b \u043c\u0435\u043d\u044f \u043a, \u043f\u043e \u0441\u0443\u0442\u0438, \u0431\u0430\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0435 &#8212; \u201c\u043f\u0440\u0438\u043a\u0440\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u044e\u201d \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043a \u0444\u0440\u043e\u043d\u0442\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0438 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438, \u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u043c \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u043e\u043c \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u0442\u0430\u0442\u044c \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 Active Directory (\u0434\u0430\u043b\u0435\u0435 AD). <\/p>\n<p>\u0411\u044b\u043b\u043e \u043f\u0440\u0438\u043d\u044f\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 AD \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u043f\u0440\u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432 \u0432 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u0431\u0440\u043e\u043a\u0435\u0440 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u2013 KeyCloak.<\/p>\n<p>\u041f\u043e\u0447\u0435\u043c\u0443? \u0412\u043e\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438\u0447\u0438\u043d:<\/p>\n<ul>\n<li>\n<p>KeyCloak \u0438\u043c\u0435\u0435\u0442 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 OpenId Connect \u0438 \u0433\u043e\u0442\u043e\u0432\u043e\u0435 SSO \u0440\u0435\u0448\u0435\u043d\u0438\u0435<\/p>\n<\/li>\n<li>\n<p>KeyCloak \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u043e\u0432, \u043f\u043e\u043c\u0438\u043c\u043e AD. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0439 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0441 \u043a\u0430\u0436\u0434\u044b\u043c \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u043e\u043c, \u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0443\u044e\u0442\u0441\u044f \u201c\u043d\u0430 \u043e\u0434\u043d\u043e\u043c \u044f\u0437\u044b\u043a\u0435\u201d <\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0435\u0441\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 AD, \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0441 \u043d\u0438\u043c \u043a\u0440\u0430\u0439\u043d\u0435 \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u043e. \u0412\u0434\u043e\u0431\u0430\u0432\u043e\u043a \u043a\u0440\u0430\u0439\u043d\u0435 \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u0430 \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043a \u0433\u0440\u0443\u043f\u043f\u0430\u043c AD, \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0443\u0434\u043e\u0431\u043d\u0435\u0439, \u0434\u0430 \u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u0438\u043d\u044f\u0442\u043e, \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043a \u0440\u043e\u043b\u044f\u043c<\/p>\n<\/li>\n<\/ul>\n<h2>KeyCloak: \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438<\/h2>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 KeyCloak \u0438 \u043a\u0430\u043a \u043e\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f \u0447\u0442\u043e \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044c \u0432\u0441\u0435 \u044d\u0442\u043e \u0437\u043d\u0430\u0435\u0442, \u0438 \u0435\u0433\u043e \u0437\u0430\u0434\u0430\u0447\u0430 \u0441\u0445\u043e\u0436\u0430\u044f \u0441 \u043c\u043e\u0435\u0439 \u2013 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 KeyCloak \u0432 \u0441\u0432\u043e\u0435\u043c \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<p>\u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u0441\u0442\u0430\u0442\u044c\u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 KeyCloak \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435:<\/p>\n<p><strong>realm<\/strong> \u2013 myproject (\u0417\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0432 KeyCloak \u0438\u043c\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435)<\/p>\n<p><strong>client_id<\/strong> \u2013 myproject-app (\u0417\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0432 KeyCloak \u0438\u043c\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f)<\/p>\n<p>\u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043e \u044d\u0442\u0438\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445 \u2013 \u043d\u0438\u0436\u0435.<\/p>\n<h2>\u0421\u0435\u0440\u0432\u0438\u0441 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438<\/h2>\n<p>\u0418\u0442\u0430\u043a, \u043f\u0435\u0440\u0432\u043e\u0435 \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u2013 \u0441\u0435\u0440\u0432\u0438\u0441 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 (\u0434\u0430\u043b\u0435\u0435 auth server) \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 (\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 access_token), \u043f\u0440\u043e\u0434\u043b\u0435\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u0430 (refresh_token) \u0438 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u0442\u043e\u043a\u0435\u043d\u0430. \u0421\u0430\u043c \u0441\u0435\u0440\u0432\u0438\u0441 \u0431\u0443\u0434\u0435\u0442 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u044b\u043c \u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043c\u0438\u043d\u0438\u043c\u0443\u043c boilerplate \u043a\u043e\u0434\u0430, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0435\u0433\u043e \u0447\u0430\u0441\u0442\u044c\u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u043b\u043e\u0436\u0435\u043d\u0430 \u043d\u0430 \u201c\u043f\u043b\u0435\u0447\u0438\u201d KeyCloak.<\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0441\u0430\u043c auth server \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 Spring Boot, \u0434\u043b\u044f \u0435\u0433\u043e \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441 KeyCloak \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/wjw465150.gitbooks.io\/keycloak-documentation\/content\/securing_apps\/topics\/oidc\/java\/spring-boot-adapter.html\">Spring Boot KeyCloak Adapter<\/a>. \u0414\u0430\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e\u0442 \u0441\u0430\u043c\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 KeyCloak.<\/p>\n<h3>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430<\/h3>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u043e\u0435\u043a\u0442 auth server \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043d\u0435\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438. \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b pom.xml \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"xml\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?> &lt;project xmlns=\"http:\/\/maven.apache.org\/POM\/4.0.0\" xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"    xsi:schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0 https:\/\/maven.apache.org\/xsd\/maven-4.0.0.xsd\">    &lt;modelVersion>4.0.0&lt;\/modelVersion>    &lt;parent>       &lt;groupId>org.springframework.boot&lt;\/groupId>       &lt;artifactId>spring-boot-starter-parent&lt;\/artifactId>       &lt;version>2.6.1&lt;\/version>       &lt;relativePath\/>    &lt;\/parent>    &lt;groupId>ru.myproject&lt;\/groupId>    &lt;artifactId>auth-keycloak&lt;\/artifactId>    &lt;version>1.1&lt;\/version>    &lt;name>auth-keycloak&lt;\/name>    &lt;description>KeyCloak Corporate Auth Service&lt;\/description>    &lt;properties>       &lt;java.version>11&lt;\/java.version>    &lt;\/properties>     &lt;dependencies>       &lt;dependency>          &lt;groupId>org.springframework.boot&lt;\/groupId>          &lt;artifactId>spring-boot-starter&lt;\/artifactId>       &lt;\/dependency>       &lt;dependency>          &lt;groupId>org.springframework.boot&lt;\/groupId>          &lt;artifactId>spring-boot-starter-security&lt;\/artifactId>       &lt;\/dependency>       &lt;dependency>          &lt;groupId>org.springframework.boot&lt;\/groupId>          &lt;artifactId>spring-boot-starter-web&lt;\/artifactId>       &lt;\/dependency>       &lt;dependency>          &lt;groupId>org.keycloak&lt;\/groupId>          &lt;artifactId>keycloak-spring-boot-starter&lt;\/artifactId>       &lt;\/dependency>       &lt;dependency>          &lt;groupId>org.projectlombok&lt;\/groupId>          &lt;artifactId>lombok&lt;\/artifactId>          &lt;version>1.18.8&lt;\/version>       &lt;\/dependency>    &lt;\/dependencies>     &lt;build>       &lt;plugins>          &lt;plugin>             &lt;groupId>org.springframework.boot&lt;\/groupId>             &lt;artifactId>spring-boot-maven-plugin&lt;\/artifactId>          &lt;\/plugin>       &lt;\/plugins>    &lt;\/build>     &lt;dependencyManagement>       &lt;dependencies>          &lt;dependency>             &lt;groupId>org.keycloak.bom&lt;\/groupId>             &lt;artifactId>keycloak-adapter-bom&lt;\/artifactId>             &lt;version>12.0.3&lt;\/version>             &lt;type>pom&lt;\/type>             &lt;scope>import&lt;\/scope>          &lt;\/dependency>       &lt;\/dependencies>    &lt;\/dependencyManagement> &lt;\/project> <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043c\u044b \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043a \u043f\u0440\u043e\u0435\u043a\u0442\u0443, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 KeyCloak. \u0424\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 application.yml \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"yaml\">keycloak:   auth-server-url: http:\/\/keycloak.host   realm: myproject   resource: myproject-app   public-client: true   use-resource-role-mappings: true<\/code><\/pre>\n<p><strong>auth-server-url<\/strong>\u00a0 &#8212; \u043f\u0443\u0442\u044c \u0434\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 KeyCloak<\/p>\n<p><strong>realm<\/strong> \u2013 \u0438\u043c\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0432 KeyCloak<\/p>\n<p><strong>resource<\/strong> \u2013 \u0438\u043c\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043e\u043d\u043e \u0436\u0435 client_id \u0432 KeyCloak<\/p>\n<p><strong>use-resource-role-mappings<\/strong> \u2013 \u0444\u043b\u0430\u0433, \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0447\u0442\u043e \u043d\u0430\u0434\u043e \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0440\u043e\u043b\u0438<br \/> \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0438\u0435\u0441\u044f \u0432 \u0441\u0435\u043a\u0446\u0438\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043d\u043e\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f JWT-\u0442\u043e\u043a\u0435\u043d\u0430. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e\u0431 \u0443\u0440\u043e\u0432\u043d\u044f\u0445 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0440\u043e\u043b\u0435\u0439 \u0432 \u0442\u043e\u043a\u0435\u043d\u0435 &#8212; <a href=\"https:\/\/usmanshahid.medium.com\/levels-of-access-control-through-keycloak-part-3-access-control-through-roles-and-tokens-a1744c04895e\">\u0442\u0443\u0442<\/a><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e spring-security, \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0432\u00a0<code>KeycloakWebSecurityConfigurerAdapter<\/code>, \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0439 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0430\u0434\u0430\u043f\u0442\u0435\u0440\u043e\u043c:<\/p>\n<pre><code class=\"java\">@KeycloakConfiguration @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {      @Override     protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {         return new NullAuthenticatedSessionStrategy();     }      @Autowired     public void configureGlobal(AuthenticationManagerBuilder authManagerBuilder) {         KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();         keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());         authManagerBuilder.authenticationProvider(keycloakAuthenticationProvider);     }      @Bean     public KeycloakConfigResolver keycloakConfigResolver() {         return new KeycloakSpringBootConfigResolver();     }      @Override     protected void configure(HttpSecurity http) throws Exception {         super.configure(http);         http                 .authorizeRequests()                 .antMatchers(\"\/authenticate\", \"\/refresh\").permitAll()                 .anyRequest().fullyAuthenticated();     }      @Override     public void configure(WebSecurity web) throws Exception {         web.ignoring().antMatchers(\"\/authenticate\", \"\/refresh\");     } }<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0432 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f 2 \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0430 \u2013 \/authenticate \u0438 \/refresh, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0448 auth server \u0441\u043c\u043e\u0433 \u0438\u0445 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u043a \u043d\u0435\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435, \u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c &#8212; \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0438 \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0442\u043e\u043a\u0435\u043d.<\/p>\n<h3>\u041a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f KeyCloak<\/h3>\n<p>\u041a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f KeyCloak \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c 2 \u043c\u0435\u0442\u043e\u0434\u0430:<\/p>\n<ul>\n<li>\n<p>\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0432 keyCloak (\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u0430)<\/p>\n<\/li>\n<li>\n<p>refresh \u0442\u043e\u043a\u0435\u043d\u0430<\/p>\n<\/li>\n<\/ul>\n<p>\u041e\u0431\u0430 \u043c\u0435\u0442\u043e\u0434\u0430 \u0431\u0443\u0434\u0443\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441 <code>org.keycloak.representations.AccessTokenResponse.class<\/code> \u0438\u0437 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u043e\u0439 \u0440\u0430\u043d\u0435\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438. \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043a\u043b\u0430\u0441\u0441\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 <a href=\"https:\/\/openid.net\/specs\/openid-connect-core-1_0.html#TokenResponse\">\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438<\/a> OpenId Connect \u0434\u043b\u044f Successful Token Response.<\/p>\n<p>\u041a\u043e\u0434 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"java\">@Component @RequiredArgsConstructor public class KeyCloakClient {     @Value(\"${keycloak.auth-server-url}\")     private String keyCloakUrl;     @Value(\"${keycloak.resource}\")     private String clientId;     @Value(\"${keycloak.realm}\")     private String realm;      private final RestTemplate restTemplate;      public AccessTokenResponse authenticate(AuthRequestDto request) {         HttpHeaders headers = new HttpHeaders();         headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);          MultiValueMap&lt;String, String> parameters = new LinkedMultiValueMap&lt;>();         parameters.add(\"username\",request.getUsername());         parameters.add(\"password\",request.getPassword());         parameters.add(\"grant_type\", \"password\");         parameters.add(\"client_id\", clientId);          HttpEntity&lt;MultiValueMap&lt;String, String>> entity = new HttpEntity&lt;>(parameters, headers);          return restTemplate.exchange(getAuthUrl(),                 HttpMethod.POST,                 entity,                 AccessTokenResponse.class).getBody();     }      public AccessTokenResponse refreshToken(String refreshToken) {         HttpHeaders headers = new HttpHeaders();         headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);          MultiValueMap&lt;String, String> parameters = new LinkedMultiValueMap&lt;>();         parameters.add(\"grant_type\", \"refresh_token\");         parameters.add(\"client_id\", clientId);         parameters.add(\"refresh_token\", refreshToken);          HttpEntity&lt;MultiValueMap&lt;String, String>> entity = new HttpEntity&lt;>(parameters, headers);          return restTemplate.exchange(getAuthUrl(),                 HttpMethod.POST,                 entity,                 AccessTokenResponse.class).getBody();     }      private String getAuthUrl() {         return UriComponentsBuilder.fromHttpUrl(keyCloakUrl)                 .pathSegment(\"realms\")                 .pathSegment(realm)                 .pathSegment(\"protocol\")                 .pathSegment(\"openid-connect\")                 .pathSegment(\"token\")                 .toUriString();     } }<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0441\u0441\u044b\u043b\u043a\u0438 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043a KeyCloak \u0438 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430, \u0434\u043b\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441 KeyCloak \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 application.yml, \u0432\u043d\u0435\u0441\u0435\u043d\u043d\u044b\u0435 \u0440\u0430\u043d\u0435\u0435. <\/p>\n<p>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u0443\u043a\u0430\u0437\u0430\u043b\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435:<\/p>\n<p><strong>grant_type<\/strong> \u2013 \u0442\u0438\u043f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u0430. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0438\u043f \u00abpassword\u00bb \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u0440\u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u0442\u0438\u043f \u00abrefresh_token\u00bb \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430.<\/p>\n<p><strong>client_id<\/strong> \u2013 \u0438\u043c\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0432 KeyCloak. \u041e\u043d \u0436\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 keycloak.resource \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 KeyCloak Adapter \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0440\u0430\u043d\u0435\u0435.<\/p>\n<p><strong>username\/password<\/strong> \u2013 credentials \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0439 \u0443\u0447\u0435\u0442\u043a\u0438, \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430.<\/p>\n<p><strong>refresh_token<\/strong> \u2013 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e refresh_token, \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430.<\/p>\n<p>\u0418 \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0438 refresh \u0442\u043e\u043a\u0435\u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043e\u0434\u043d\u0443 \u0438 \u0442\u0443 \u0436\u0435 \u0441\u0441\u044b\u043b\u043a\u0443 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043a KeyCloak. \u0412 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u0441\u043e <a href=\"https:\/\/www.keycloak.org\/docs\/latest\/securing_apps\/#authentication\">\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0435\u0439 KeyCloak<\/a> \u0444\u043e\u0440\u043c\u0430\u0442 \u0441\u0441\u044b\u043b\u043a\u0438, \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0431\u0443\u0434\u0435\u0442 \u0442\u0430\u043a\u0438\u043c:<\/p>\n<p><u>http:\/\/keycloak.host \/auth\/realms\/myproject\/protocol\/openid-connect\/token<\/u>.<\/p>\n<p><strong>myproject<\/strong> &#8212; realm \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<p><strong>keycloak.host<\/strong> &#8212; \u0445\u043e\u0441\u0442, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432\u0430\u0448 KeyCloak<\/p>\n<h3>\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b<\/h3>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u043e\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0441 \u043c\u0435\u0442\u043e\u0434\u043e\u043c \u0434\u043b\u044f \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 <code>AuthenticateController.java<\/code>:<\/p>\n<pre><code class=\"java\">@RestController @RequiredArgsConstructor @RequestMapping(\"\/authenticate\") public class AuthenticateController {     private final KeyCloakClient keyCloakClient;      @PostMapping     public ResponseEntity&lt;AccessTokenResponse> authenticate(@RequestBody AuthRequestDto request) {         return ResponseEntity.ok(keyCloakClient.authenticate(request));     } }<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u0435\u0442\u043e\u0434 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 (\u0444\u0440\u043e\u043d\u0442\u0430) \u043e\u0431\u044a\u0435\u043a\u0442, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u043b\u043e\u0433\u0438\u043d \u0438 \u043f\u0430\u0440\u043e\u043b\u044c. \u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u0441\u0442\u0430\u0442\u044c\u0438 \u043b\u043e\u0433\u0438\u043d \u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u0432\u0438\u0434\u0435 \u0438 \u0432 \u0442\u0435\u043b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u0414\u0430\u043b\u0435\u0435 \u043c\u044b \u0434\u0435\u043b\u0430\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u0432 KeyCloak \u0447\u0435\u0440\u0435\u0437 <code>KeyCloakClient.java<\/code> \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u043e\u0442\u0432\u0435\u0442 \u043e\u0442 KeyCloak, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0443.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043e\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0442\u043e\u043a\u0435\u043d\u043e\u043c <code>TokenController.java<\/code>:<\/p>\n<pre><code class=\"java\">@RestController @RequiredArgsConstructor public class TokenController {     private final KeyCloakClient keyCloakClient;      @ExceptionHandler(AuthenticationCredentialsNotFoundException.class)     public ResponseEntity handleAuthNotFoundException() {         return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();     }      @GetMapping(\"\/validate\")     @PreAuthorize(\"hasRoles('MY_APP_USER', 'MY_APP_ADMIN')\")     public ResponseEntity validate() {         return ResponseEntity.ok().build();     }      @PostMapping(\"\/refresh\")     public ResponseEntity&lt;AccessTokenResponse> refresh(@RequestHeader(\"refresh-token\") String refreshToken) {         return ResponseEntity.ok(keyCloakClient.refreshToken(refreshToken));     } }<\/code><\/pre>\n<p>\u0412 \u043c\u0435\u0442\u043e\u0434\u0435 \/validate \u2013 \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0447\u0435\u0440\u0435\u0437 \u0441\u043f\u0440\u0438\u043d\u0433\u043e\u0432\u0443\u044e \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044e <code>@PreAuthorize(\"hasRole('MY_APP_USER')\")<\/code> &#8212; \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043b\u0438 \u0442\u043e\u043a\u0435\u043d \u043f\u0440\u0438\u0448\u0435\u0434\u0448\u0438\u0439 \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0443\u044e \u0434\u043b\u044f \u043d\u0430\u0441 \u0440\u043e\u043b\u044c. \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u044b \u0440\u043e\u043b\u0438 &#8212; \u00abROLE_MY_APP_USER\u00bb \u0438 \u00abROLE_MY_APP_ADMIN\u00bb \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p><strong><em>\u0412\u0410\u0416\u041d\u041e!<\/em><\/strong><em> \u0414\u0430, \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 hasRole \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0440\u043e\u043b\u0438 \u0431\u0435\u0437 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u0430 ROLE_ (\u0442.\u043a. \u0441\u043f\u0440\u0438\u043d\u0433 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u044d\u0442\u043e\u0442 \u043f\u0440\u0435\u0444\u0438\u043a\u0441 \u043f\u0440\u0438 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0440\u043e\u043b\u0435\u0439).<\/em><\/p>\n<h2>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 NGINX<\/h2>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0444\u0440\u043e\u043d\u0442 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c, \u043d\u0443\u0436\u043d\u0430 \u0435\u0434\u0438\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0444\u0440\u043e\u043d\u0442\u0430 \u0441 \u043d\u0438\u043c\u0438. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0435\u0434\u0438\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438 \u0431\u044b\u043b \u0432\u044b\u0431\u0440\u0430\u043d nginx.<\/p>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0448 \u0444\u0440\u043e\u043d\u0442 \u0441\u043c\u043e\u0433 \u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438, \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437 \u043d\u0438\u0445 \u00a0location. \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0431\u0449\u0430\u0435\u0442\u0441\u044f \u0441 \u0434\u0432\u0443\u043c\u044f \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438:<\/p>\n<pre><code class=\"nginx\">location \/my-servece-1 { auth_request \/validate; \u00a0\u00a0proxy_pass http:\/\/\u0425\u043e\u0441\u0442\u0421\u0435\u0440\u0432\u0438\u0441\u04301:\u041f\u043e\u0440\u0442; }  location \/my-service-2 { \u00a0\u00a0auth_request \/validate; \u00a0\u00a0proxy_pass http:\/\/\u0425\u043e\u0441\u0442\u0421\u0435\u0440\u0432\u0438\u0441\u04302:\u041f\u043e\u0440\u0442; }<\/code><\/pre>\n<p>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 auth_request \u2013 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 nginx, \u0447\u0442\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u044b (\u0441\u0435\u0440\u0432\u0438\u0441\u044b) \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u043c\u044b\u0435 \u043f\u043e \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0430\u043c \/my-service-1 \u0438 \/my-service-2 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. <\/p>\n<p>\u0412 <strong>proxy_pass<\/strong> \u2013 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0443\u0442\u044c \u043a \u0441\u0430\u043c\u043e\u043c\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u0443.<\/p>\n<p>\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u044d\u0442\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c: \u043a\u043e\u0433\u0434\u0430 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u044d\u0442\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u044b, Nginx \u0434\u0435\u043b\u0430\u0435\u0442 \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \/validate. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0435\u0441\u043b\u0438 \/validate \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0441 http status = 200 OK, \u0442\u043e Nginx \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0434\u0430\u043b\u0435\u0435 \u043d\u0430 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u043c\u044b\u0439 \u0440\u0435\u0441\u0443\u0440\u0441, \u0435\u0441\u043b\u0438 401 Unauthorized \u2013 \u043d\u0435 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u044d\u0442\u043e\u0442 \u0441\u0442\u0430\u0442\u0443\u0441 \u043a\u043b\u0438\u0435\u043d\u0442\u0443.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u043e\u0442 \u0441\u0430\u043c\u044b\u0439 \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \/validate, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u043e\u0434\u043d\u043e\u0438\u043c\u0435\u043d\u043d\u043e\u043c\u0443 rest-\u043c\u0435\u0442\u043e\u0434\u0443 \u043d\u0430\u0448\u0435\u0433\u043e auth server<strong>,<\/strong> \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u0432 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0435 \u0440\u0430\u043d\u0435\u0435:<\/p>\n<pre><code class=\"nginx\">location = \/validate { internal;   proxy_set_header Content-Length \"\"; proxy_pass http:\/\/\u0425\u043e\u0441\u0442\u041d\u0430\u0448\u0435\u0433\u043eAuthServer:\u041f\u043e\u0440\u0442\/validate; }<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435, \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043c\u044b \u043c\u043e\u0433\u043b\u0438 \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u0441 \u0444\u0440\u043e\u043d\u0442\u0430 \u043a \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u043c \u0435\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430\u043c auth server, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e &#8212; \u043c\u0435\u0442\u043e\u0434\u0430\u043c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 refresh \u0442\u043e\u043a\u0435\u043d\u0430, \u043f\u0440\u043e\u043f\u0438\u0448\u0435\u043c \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \/auth-server:<\/p>\n<pre><code class=\"nginx\">location \/auth-server { proxy_pass http:\/\/\u0425\u043e\u0441\u0442\u041d\u0430\u0448\u0435\u0433\u043eAuthServer:\u041f\u043e\u0440\u0442; }<\/code><\/pre>\n<h2>\u201c\u041f\u0440\u0438\u043a\u0440\u0443\u0447\u0438\u0432\u0430\u0435\u043c\u201d \u043a \u0444\u0440\u043e\u043d\u0442\u0443<\/h2>\n<h3>\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u0442\u043e\u043a\u0435\u043d\u0430\u043c\u0438<\/h3>\n<p>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u043e\u0442 KeyCloak access_token \u0438 refresh_token \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 localStorage. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0442\u043e\u043a\u0435\u043d\u0430\u043c\u0438 \u0438 localStorage \u0443\u0442\u0438\u043b\u0438\u0442\u0430\u0440\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 <code>TokenUtils.js<\/code>:<\/p>\n<pre><code class=\"javascript\">import jwt_decode from 'jwt-decode'; import Keycloak from \"keycloak-verify\/src\";  const TOKEN_KEY = 'myproject_access_token'; const REFRESH_TOKEN_KEY = 'myproject_refresh_token'; const PUBLIC_KEY = '-----BEGIN CERTIFICATE-----[PUBLIC_KEY \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043e\u0442 KeyCloak]-----END CERTIFICATE-----';  export const getToken = () => localStorage.getItem(TOKEN_KEY); export const setToken = token => localStorage.setItem(TOKEN_KEY, token); export const getRefreshToken = () => localStorage.getItem(REFRESH_TOKEN_KEY); export const setRefreshToken = refreshToken => localStorage.setItem(REFRESH_TOKEN_KEY, refreshToken);  const getDetailsFromToken = () => {     return jwt_decode(getToken()); };  export const getUserRoles = () => getDetailsFromToken()?.resource_access[\"myproject-app\"]?.roles; export const hasRole = role => getUserRoles()?.includes(role);  export const verifyToken = () => (     Keycloak(         {publicKey: PUBLIC_KEY}     ).verifyOffline(getToken()) ); <\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434\u044b \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 \u0431\u0443\u0434\u0443\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u0434\u043b\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0445 \u043d\u0438\u0436\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439. \u041f\u0440\u043e\u0439\u0434\u0435\u043c\u0441\u044f \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043f\u043e \u043a\u0430\u0436\u0434\u043e\u043c\u0443:<\/p>\n<p><code>getToken\/setToken<\/code> \u2013 getter\/setter \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f\/\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 token \u0438\u0437\/\u0432 localStorage<\/p>\n<p><code>getRefreshToken\/setRefreshToken<\/code> \u2013 getter\/setter \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f\/\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 refreshToken \u0438\u0437\/\u0432 localStorage<\/p>\n<p><code>getDetailsFromToken<\/code> \u2013 \u043f\u0430\u0440\u0441\u0438\u043d\u0433 \u0442\u043e\u043a\u0435\u043d\u0430 \u0432 json-\u0444\u043e\u0440\u043c\u0430\u0442 (\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043d\u0438\u0436\u0435)<\/p>\n<p><code>getUserRoles<\/code> \u2013 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0440\u043e\u043b\u0435\u0439, \u0437\u0430\u0448\u0438\u0442\u044b\u0445 \u0432 access_token. \u0417\u0434\u0435\u0441\u044c, \u043a\u0430\u043a \u0431\u044b\u043b\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u043e \u0432\u044b\u0448\u0435, \u043c\u044b \u0431\u0435\u0440\u0435\u043c \u0440\u043e\u043b\u0438 \u0438\u0437 \u0443\u0440\u043e\u0432\u043d\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0442\u043e\u043a\u0435\u043d\u0430 (\u0443\u0440\u043e\u0432\u043d\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0431\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u043a \u043f\u043e\u043b\u044e resource_access \u0438 \u043a \u0435\u0433\u043e \u0434\u043e\u0447\u0435\u0440\u043d\u0435\u043c\u0443 \u043f\u043e\u043b\u044e, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c\u0443 \u043d\u0430\u0448\u0435\u043c\u0443 client_id (\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0432 KeyCloak). \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e \u2013 \u00abmyproject-app\u00bb.<\/p>\n<p><strong>hasRole<\/strong> \u2013 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0439 \u0440\u043e\u043b\u0438 \u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<p><strong>verifyToken<\/strong> \u2013 \u043c\u0435\u0442\u043e\u0434 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0439 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0442\u043e\u043a\u0435\u043d\u0430. <\/p>\n<p>\u0417\u0434\u0435\u0441\u044c \u043f\u043e\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435. \u041c\u0435\u0442\u043e\u0434 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u0434\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435, \u043a\u043e\u0433\u0434\u0430 \u0442\u043e\u043a\u0435\u043d \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u0435\u043d (\u0438\u0441\u0442\u0435\u043a \u0441\u0440\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f)<\/p>\n<p>\u042f \u0432\u044b\u0431\u0440\u0430\u043b \u0434\u043b\u044f \u0446\u0435\u043b\u0435\u0439 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0442\u043e\u043a\u0435\u043d\u0430 \u043d\u0430 \u0444\u0440\u043e\u043d\u0442\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/www.npmjs.com\/package\/keycloak-verify\">keycloak-verify<\/a>. \u0414\u0430\u043d\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442 2 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0442\u043e\u043a\u0435\u043d\u0430 \u2013 <em>offline<\/em> \u0438 <em>online<\/em>. <em>Online<\/em> \u2013 \u0431\u043e\u043b\u0435\u0435 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0439, \u043d\u043e \u0438 \u0431\u043e\u043b\u0435\u0435 \u0437\u0430\u0442\u0440\u0430\u0442\u043d\u044b\u0439, \u0442.\u043a. \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0444\u0440\u043e\u043d\u0442\u0430 \u043a \u0441\u0435\u0440\u0432\u0438\u0441\u0443. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u044f \u0445\u043e\u0447\u0443, \u0447\u0442\u043e\u0431\u044b \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0444\u0440\u043e\u043d\u0442 \u043e\u0431\u0440\u0430\u0449\u0430\u043b\u0441\u044f \u043a \u0441\u0435\u0440\u0432\u0438\u0441\u0443 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430, \u044f \u0432\u044b\u0431\u0440\u0430\u043b <em>offline<\/em>-\u0432\u0430\u0440\u0438\u0430\u043d\u0442. <\/p>\n<p>\u0414\u043b\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0442\u043e\u043a\u0435\u043d\u0430 <em>offline<\/em> \u043c\u0435\u0442\u043e\u0434\u043e\u043c \u2013 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c public_key. \u0415\u0433\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u0441\u043e\u043b\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f KeyCloak \u0438\u043b\u0438 \u0441\u0434\u0435\u043b\u0430\u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 &#8212; GET <a href=\"http:\/\/keycloak.host\/auth\/realms\/myproject\">http:\/\/keycloak.host\/auth\/realms\/myproject<\/a><\/p>\n<p>\u0413\u0434\u0435 <strong>myproject<\/strong> \u2013 \u0438\u043c\u044f \u043d\u0430\u0448\u0435\u0433\u043e realm.<\/p>\n<p>public_key \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u043e\u0434\u043d\u043e\u0438\u043c\u0435\u043d\u043d\u043e\u043c \u043f\u043e\u043b\u0435 \u043e\u0442\u0432\u0435\u0442\u0430:<\/p>\n<pre><code class=\"julia\">{     \"realm\": \"myproject\",     \"public_key\": \"MIIBIjANBgkqhkiG \u2026 ZyR6F6wIDAQAB\",     \"token-service\": \"http:\/\/keycloak.host\/auth\/realms\/myproject\/protocol\/openid-connect\",     \"account-service\": \"http:\/\/keycloak.host\/auth\/realms\/myproject\/account\",     \"tokens-not-before\": 0 }<\/code><\/pre>\n<p>\u0415\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0433\u0434\u0435-\u0442\u043e \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0444\u0440\u043e\u043d\u0442\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043b\u0438\u0431\u043e \u0432 ENV-\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439. \u0414\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u0443\u0442\u0438\u043b\u0438\u0442\u0430\u0440\u043d\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 <code>TokenUtils.js<\/code>.<\/p>\n<p><strong><em>\u0412\u0410\u0416\u041d\u041e:<\/em><\/strong><em> \u0414\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, public_key \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043f\u043e\u043c\u0435\u0449\u0435\u043d \u0432\u043d\u0443\u0442\u0440\u044c \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0431\u043b\u043e\u043a\u0430:<\/em><\/p>\n<pre><code>-----BEGIN CERTIFICATE-----Your public key-----END CERTIFICATE-----<\/code><\/pre>\n<h3>\u0412\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0444\u0440\u043e\u043d\u0442\u0430 \u0441 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438. AXIOS<\/h3>\n<p>\u0414\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/www.npmjs.com\/package\/axios\">AXIOS<\/a>. <\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0443\u0442 2 \u0442\u0438\u043f\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432:\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 (\u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438) \u0438 \u043d\u0435\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 (\u0434\u043b\u044f \u0441\u0430\u043c\u043e\u0439 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 refresh \u0442\u043e\u043a\u0435\u043d\u0430) &#8212; \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0430\u043d\u0441 axios.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0443\u0442\u0438\u043b\u0438\u0442\u0430\u0440\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0441 \u043d\u0430\u0448\u0438\u043c\u0438 axios \u2013 <code>AxiosInstance.js<\/code> \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043d\u0435\u0433\u043e \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 axios \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432:<\/p>\n<pre><code class=\"javascript\">export const axiosInstance = axios.create({     headers: { Authorization: `Bearer ${getToken()}` } });<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u2013 bearer-token. \u041e\u043d \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0441\u044b\u043b\u0430\u0442\u044c\u0441\u044f \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435.<\/p>\n<p>\u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043f\u0435\u0440\u0435\u0434 \u043a\u0430\u0436\u0434\u044b\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c \u0441 \u0444\u0440\u043e\u043d\u0442\u0430 \u043d\u0430\u043c \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0441\u0442\u044c \u0442\u043e\u043a\u0435\u043d\u0430 \u0438, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0435\u0441\u043b\u0438 \u043e\u043d \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u0435\u043d (\u0438\u0441\u0442\u0435\u043a \u0441\u0440\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440) &#8212; \u0434\u0435\u043b\u0430\u0442\u044c \u0435\u0433\u043e refresh. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u0443\u0439\u0434\u0435\u0442 \u0443\u0436\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439 token.<\/p>\n<p>\u0418\u0442\u0430\u043a, \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432\u044b\u0437\u043e\u0432 \u043c\u0435\u0442\u043e\u0434\u0430 <code>verifyToken<\/code> \u0432 axios request interceptor:<\/p>\n<pre><code class=\"javascript\">axiosInstance.interceptors.request.use(request => {     verifyToken().catch(() => refreshToken(getRefreshToken()));     return request; });<\/code><\/pre>\n<p>\u0412 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0442\u043e\u043a\u0435\u043d \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u0435\u043d, \u043c\u0435\u0442\u043e\u0434 \u043a\u0438\u0434\u0430\u0435\u0442 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435, \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u0430 \u043c\u0435\u0442\u043e\u0434\u043e\u043c <code>refreshToken<\/code>, \u0430 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0435\u0433\u043e \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c refresh_token \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0432 \u043d\u0430\u0448\u0435\u043c localStorage \u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0439 \u0447\u0435\u0440\u0435\u0437 \u0443\u0442\u0438\u043b\u0438\u0442\u0430\u0440\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 <code>getRefreshToken<\/code>. <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u0442\u0430\u0442\u0443\u0441 \u043e\u0442\u0432\u0435\u0442\u0430 \u0432 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445. \u0421\u0434\u0435\u043b\u0430\u0435\u043c \u044d\u0442\u043e \u0447\u0435\u0440\u0435\u0437 axios response interceptors:<\/p>\n<pre><code class=\"javascript\">axiosInstance.interceptors.response.use(response => {     if (response?.headers?.authorization) {         setToken(response.headers.authorization);     }     return response; }, error => {     if (error?.response?.status === 401) {         logout();     }     return Promise.reject(error); });<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 httpStatus = 401, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 (\u0434\u0435\u043b\u0430\u0435\u043c logout), \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0447\u0438\u0441\u0442\u0438\u0432 localStorage \u043e\u0442 access token \u0438 refresh token, \u0442.\u043a. \u043e\u043d\u0438 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b.<\/p>\n<p>\u041c\u0435\u0442\u043e\u0434 <code>logout<\/code> \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"javascript\">export const logout = () => {     clearTokenData()     window.location.href = '\/'; }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043d\u0435\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 (\u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 refresh \u0442\u043e\u043a\u0435\u043d\u0430) \u2013 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u0439:<\/p>\n<pre><code class=\"javascript\">export const axiosInstanceDefault = axios.create();<\/code><\/pre>\n<h3>\u041a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f auth server<\/h3>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043b\u0430\u0441\u0441 <code>AuthClient.js<\/code> \u0441 \u043c\u0435\u0442\u043e\u0434\u043e\u043c \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0438 refresh \u0442\u043e\u043a\u0435\u043d\u0430:<\/p>\n<pre><code class=\"javascript\">import { axiosInstanceAuth } from \"..\/services\/AxiosInstance\"; import {setRefreshToken, setToken} from \".\/TokenUtils\";  const AUTH_SERVICE = \"\/auth-server\";  export const authenticate = async (login, password) => {     return axiosInstanceDefault.post(`${AUTH_SERVICE}\/authenticate`, {             username: login, password: password         }     ).then(response => {         setToken(response.data.access_token);         setRefreshToken(response.data.refresh_token);         return Promise.resolve();     }).catch(() => Promise.reject()); };  export const refreshToken = async () => {     axiosInstanceDefault.post(`${AUTH_SERVICE}\/refresh`, getRefreshToken())         .then(response => {             setToken(response.data.access_token);             setRefreshToken(response.data.refresh_token)         })         .catch(() => logout()); };<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c, \u0432 \u043e\u0431\u043e\u0438\u0445 \u043c\u0435\u0442\u043e\u0434\u0430\u0445, \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0443\u0441\u043f\u0435\u0445\u0430 \u2013 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0432 localStorage &#8212; access_token \u0438 refresh_token \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0443\u0442\u0438\u043b\u0438\u0442\u0430\u0440\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u043a\u043b\u0430\u0441\u0441\u0430 <code>TokenUtils.js<\/code>. <\/p>\n<p>\u041c\u0435\u0442\u043e\u0434 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0443\u0441\u043f\u0435\u0445\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0443\u0441\u043f\u0435\u0448\u043d\u044b\u0439 <code>Promise<\/code>, \u0430 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u2013 \u043e\u0448\u0438\u0431\u043e\u0447\u043d\u044b\u0439 <code>Promise<\/code>. \u0412 \u043d\u0438\u0445 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0432 \u043c\u0435\u0441\u0442\u0430\u0445 \u0432\u044b\u0437\u043e\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u0430, \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e \u043d\u0438\u0445 \u2013 \u043d\u0438\u0436\u0435 (\u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u201c\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438\u201d).<\/p>\n<p>\u0414\u043b\u044f \u043c\u0435\u0442\u043e\u0434\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u0435 Promise \u043d\u0435 \u043d\u0443\u0436\u043d\u043e, \u0442.\u043a. \u043f\u0440\u0438 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u043c \u0435\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0432\u044b\u0437\u043e\u0432\u0430 \u043d\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438\u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0435\u0442\u043e\u0434\u0430 <code>logout<\/code>. \u041c\u0435\u0442\u043e\u0434 refreshToken \u043c\u044b \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0440\u0430\u043d\u0435\u0435 \u0432 <code>axois.request.interceptor<\/code> \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430 \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0435\u0440\u0435\u0434 \u043a\u0430\u0436\u0434\u044b\u043c axios-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c.<\/p>\n<h3>\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438<\/h3>\n<p>\u041d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043c\u0435\u0442\u043e\u0434 <code>login<\/code> \u0438 \u043f\u043e\u0432\u0435\u0441\u0438\u043c \u0435\u0433\u043e \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 \u00ab\u0412\u043e\u0439\u0442\u0438\u00bb.<\/p>\n<p><code>AuthPage.js:<\/code><\/p>\n<pre><code class=\"javascript\">const login = async () => {     await authenticate(credentials.login, credentials.password)         .then(() => {             window.location.href = '\/';         }).catch(() => setError(true)); };<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u0440\u0430\u043d\u0435\u0435 \u043c\u0435\u0442\u043e\u0434 authenticate, \u0430 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043c\u0435\u0442\u043e\u0434\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0440\u0435\u0434\u0438\u0440\u0435\u043a\u0442 \u043d\u0430 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (&#8216;\/&#8217;). \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043c\u0435\u0442\u043e\u0434\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0432\u044b\u0437\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 setError, \u0432 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u2013 \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0445\u0443\u043a\u0430 error, \u043e\u0437\u043d\u0430\u0447\u0430\u044e\u0449\u0435\u0433\u043e, \u0447\u0442\u043e \u043d\u0430\u0434\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435. <\/p>\n<h3>\u0420\u0430\u0437\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u043f\u043e \u0440\u043e\u043b\u044f\u043c<\/h3>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043d\u0430 \u0444\u0440\u043e\u043d\u0442\u0435 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0443\/\u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0443 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043a\u0430\u0436\u0434\u043e\u0439 \u0440\u043e\u043b\u0438, \u043d\u0430\u043c \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043c\u0435\u0441\u0442\u0430\u0445 \u0440\u0430\u043d\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 <code>TokenUtils.hasRole(\u2018role_name\u2019)<\/code>.<\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 Tab \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"xml\">&lt;Tabs>     {(hasRole(\u2018ROLE_MY_APP_USER\u2019) || hasRole(\u2018ROLE_MY_APP_ADMIN\u2019)) &amp;&amp; &lt;Tab label=\"\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 tab\" value=\"someUserTab\"\/>}     { hasRole(\u2018ROLE_MY_APP_ADMIN\u2019) &amp;&amp; &lt;Tab label=\"\u0410\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0441\u043a\u0438\u0439 tab\" value=\"someAdminTab\"\/>} &lt;\/Tabs><\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0442\u0430\u0431 \u0434\u043b\u044f \u043d\u0435\u043a\u043e\u0433\u043e \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430 \u00ab\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 tab\u00bb \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438 \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0440\u043e\u043b\u0438 \u00abROLE_MY_APP_USER\u00bb \u0438 \u0434\u043b\u044f \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0441\u043a\u043e\u0439 \u0440\u043e\u043b\u0438 \u00abROLE_MY_APP_ADMIN\u00bb. <\/p>\n<p>\u201c\u0410\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0441\u043a\u0438\u0439 tab\u201d,\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0440\u043e\u043b\u0438 \u00abROLE_MY_APP_ADMIN\u00bb.<\/p>\n<h2>\u0412 \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>\u0414\u043b\u044f \u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d\u043e\u0441\u0442\u0438 \u0441\u0442\u0430\u0442\u044c\u0438 \u044f \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u043b \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u043f\u044b\u0442\u0430\u044f\u0441\u044c \u0430\u043a\u0446\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u0435.<\/p>\n<p>\u0421\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0444\u0440\u043e\u043d\u0442\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u00a0 \u043e\u0434\u043d\u0438\u043c \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u043c, \u0441\u0442\u043e\u0438\u0442 \u043f\u0435\u0440\u0435\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0432 nginx, \u043a\u0430\u043a \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u0441\u0442\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (\u043c\u0435\u0442\u043e\u0434 \/validate \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0439 \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043f\u0435\u0440\u0435\u0434 \u0432\u044b\u0437\u043e\u0432\u043e\u043c \u0441\u0435\u0440\u0432\u0438\u0441\u0430). \u0412 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u0435\u0441\u044c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0440\u0430\u0431\u043e\u0442\u044b \u0441 spring-keycloak-adapter \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u0432 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 (back).<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u0431\u0443\u0434\u0443\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/company\/reksoft\/blog\/552346\/\">https:\/\/habr.com\/ru\/company\/reksoft\/blog\/552346\/<\/a> &#8212; \u0441\u0442\u0430\u0442\u044c\u044f \u043e \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441 KeyCloak SpringBoot \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 KeyCloak Adapter. \u0422\u0430\u043a\u0436\u0435 \u0435\u0441\u0442\u044c \u043a\u0440\u0430\u0442\u043a\u0430\u044f \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f \u043f\u043e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e KeyCloak.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/company\/X5Group\/blog\/486778\/\">https:\/\/habr.com\/ru\/company\/X5Group\/blog\/486778\/<\/a> &#8212; \u0442\u0435\u043e\u0440\u0438\u044f, \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u0438 \u0447\u0435\u043c \u0445\u043e\u0440\u043e\u0448 KeyCloak<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/openid.net\/specs\/openid-connect-core-1_0.html\">https:\/\/openid.net\/specs\/openid-connect-core-1_0.html<\/a> &#8212; \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f OpenId Connect \u2013 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 KeyCloak.<\/p>\n<\/li>\n<\/ul>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/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\/company\/alfastrah\/blog\/651861\/\"> https:\/\/habr.com\/ru\/company\/alfastrah\/blog\/651861\/<\/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_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0416\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u0439 \u0446\u0438\u043a\u043b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 \u043f\u0440\u0438\u0432\u0435\u043b \u043c\u0435\u043d\u044f \u043a, \u043f\u043e \u0441\u0443\u0442\u0438, \u0431\u0430\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0435 &#8212; \u201c\u043f\u0440\u0438\u043a\u0440\u0443\u0447\u0438\u0432\u0430\u043d\u0438\u044e\u201d \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0439 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043a \u0444\u0440\u043e\u043d\u0442\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0438 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438, \u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u043c \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u043e\u043c \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u0442\u0430\u0442\u044c \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 Active Directory (\u0434\u0430\u043b\u0435\u0435 AD). <\/p>\n<p>\u0411\u044b\u043b\u043e \u043f\u0440\u0438\u043d\u044f\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 AD \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u043f\u0440\u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u043e\u0432 \u0432 \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u0431\u0440\u043e\u043a\u0435\u0440 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u2013 KeyCloak.<\/p>\n<p>\u041f\u043e\u0447\u0435\u043c\u0443? \u0412\u043e\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438\u0447\u0438\u043d:<\/p>\n<ul>\n<li>\n<p>KeyCloak \u0438\u043c\u0435\u0435\u0442 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 OpenId Connect \u0438 \u0433\u043e\u0442\u043e\u0432\u043e\u0435 SSO \u0440\u0435\u0448\u0435\u043d\u0438\u0435<\/p>\n<\/li>\n<li>\n<p>KeyCloak \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u043e\u0432, \u043f\u043e\u043c\u0438\u043c\u043e AD. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0439 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0441 \u043a\u0430\u0436\u0434\u044b\u043c \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u043e\u043c, \u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0443\u044e\u0442\u0441\u044f \u201c\u043d\u0430 \u043e\u0434\u043d\u043e\u043c \u044f\u0437\u044b\u043a\u0435\u201d <\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0435\u0441\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 AD, \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0441 \u043d\u0438\u043c \u043a\u0440\u0430\u0439\u043d\u0435 \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u043e. \u0412\u0434\u043e\u0431\u0430\u0432\u043e\u043a \u043a\u0440\u0430\u0439\u043d\u0435 \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u0430 \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043a \u0433\u0440\u0443\u043f\u043f\u0430\u043c AD, \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0443\u0434\u043e\u0431\u043d\u0435\u0439, \u0434\u0430 \u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u0438\u043d\u044f\u0442\u043e, \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043a \u0440\u043e\u043b\u044f\u043c<\/p>\n<\/li>\n<\/ul>\n<h2>KeyCloak: \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438<\/h2>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 KeyCloak \u0438 \u043a\u0430\u043a \u043e\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f \u0447\u0442\u043e \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044c \u0432\u0441\u0435 \u044d\u0442\u043e \u0437\u043d\u0430\u0435\u0442, \u0438 \u0435\u0433\u043e \u0437\u0430\u0434\u0430\u0447\u0430 \u0441\u0445\u043e\u0436\u0430\u044f \u0441 \u043c\u043e\u0435\u0439 \u2013 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 KeyCloak \u0432 \u0441\u0432\u043e\u0435\u043c \u0432\u0435\u0431-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<p>\u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u0441\u0442\u0430\u0442\u044c\u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 KeyCloak \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435:<\/p>\n<p><strong>realm<\/strong> \u2013 myproject (\u0417\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0432 KeyCloak \u0438\u043c\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435)<\/p>\n<p><strong>client_id<\/strong> \u2013 myproject-app (\u0417\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0432 KeyCloak \u0438\u043c\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f)<\/p>\n<p>\u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043e \u044d\u0442\u0438\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445 \u2013 \u043d\u0438\u0436\u0435.<\/p>\n<h2>\u0421\u0435\u0440\u0432\u0438\u0441 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438<\/h2>\n<p>\u0418\u0442\u0430\u043a, \u043f\u0435\u0440\u0432\u043e\u0435 \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u2013 \u0441\u0435\u0440\u0432\u0438\u0441 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 (\u0434\u0430\u043b\u0435\u0435 auth server) \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 (\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 access_token), \u043f\u0440\u043e\u0434\u043b\u0435\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u0430 (refresh_token) \u0438 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u0442\u043e\u043a\u0435\u043d\u0430. \u0421\u0430\u043c \u0441\u0435\u0440\u0432\u0438\u0441 \u0431\u0443\u0434\u0435\u0442 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u044b\u043c \u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043c\u0438\u043d\u0438\u043c\u0443\u043c boilerplate \u043a\u043e\u0434\u0430, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0435\u0433\u043e \u0447\u0430\u0441\u0442\u044c\u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u043b\u043e\u0436\u0435\u043d\u0430 \u043d\u0430 \u201c\u043f\u043b\u0435\u0447\u0438\u201d KeyCloak.<\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0441\u0430\u043c auth server \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 Spring Boot, \u0434\u043b\u044f \u0435\u0433\u043e \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441 KeyCloak \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/wjw465150.gitbooks.io\/keycloak-documentation\/content\/securing_apps\/topics\/oidc\/java\/spring-boot-adapter.html\">Spring Boot KeyCloak Adapter<\/a>. \u0414\u0430\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e\u0442 \u0441\u0430\u043c\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 KeyCloak.<\/p>\n<h3>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430<\/h3>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u043e\u0435\u043a\u0442 auth server \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043d\u0435\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438. \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b pom.xml \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"xml\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?> &lt;project xmlns=\"http:\/\/maven.apache.org\/POM\/4.0.0\" xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\"    xsi:schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0 https:\/\/maven.apache.org\/xsd\/maven-4.0.0.xsd\">    &lt;modelVersion>4.0.0&lt;\/modelVersion>    &lt;parent>       &lt;groupId>org.springframework.boot&lt;\/groupId>       &lt;artifactId>spring-boot-starter-parent&lt;\/artifactId>       &lt;version>2.6.1&lt;\/version>       &lt;relativePath\/>    &lt;\/parent>    &lt;groupId>ru.myproject&lt;\/groupId>    &lt;artifactId>auth-keycloak&lt;\/artifactId>    &lt;version>1.1&lt;\/version>    &lt;name>auth-keycloak&lt;\/name>    &lt;description>KeyCloak Corporate Auth Service&lt;\/description>    &lt;properties>       &lt;java.version>11&lt;\/java.version>    &lt;\/properties>     &lt;dependencies>       &lt;dependency>          &lt;groupId>org.springframework.boot&lt;\/groupId>          &lt;artifactId>spring-boot-starter&lt;\/artifactId>       &lt;\/dependency>       &lt;dependency>          &lt;groupId>org.springframework.boot&lt;\/groupId>          &lt;artifactId>spring-boot-starter-security&lt;\/artifactId>       &lt;\/dependency>       &lt;dependency>          &lt;groupId>org.springframework.boot&lt;\/groupId>          &lt;artifactId>spring-boot-starter-web&lt;\/artifactId>       &lt;\/dependency>       &lt;dependency>          &lt;groupId>org.keycloak&lt;\/groupId>          &lt;artifactId>keycloak-spring-boot-starter&lt;\/artifactId>       &lt;\/dependency>       &lt;dependency>          &lt;groupId>org.projectlombok&lt;\/groupId>          &lt;artifactId>lombok&lt;\/artifactId>          &lt;version>1.18.8&lt;\/version>       &lt;\/dependency>    &lt;\/dependencies>     &lt;build>       &lt;plugins>          &lt;plugin>             &lt;groupId>org.springframework.boot&lt;\/groupId>             &lt;artifactId>spring-boot-maven-plugin&lt;\/artifactId>          &lt;\/plugin>       &lt;\/plugins>    &lt;\/build>     &lt;dependencyManagement>       &lt;dependencies>          &lt;dependency>             &lt;groupId>org.keycloak.bom&lt;\/groupId>             &lt;artifactId>keycloak-adapter-bom&lt;\/artifactId>             &lt;version>12.0.3&lt;\/version>             &lt;type>pom&lt;\/type>             &lt;scope>import&lt;\/scope>          &lt;\/dependency>       &lt;\/dependencies>    &lt;\/dependencyManagement> &lt;\/project> <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043c\u044b \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043a \u043f\u0440\u043e\u0435\u043a\u0442\u0443, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 KeyCloak. \u0424\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 application.yml \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"yaml\">keycloak:   auth-server-url: http:\/\/keycloak.host   realm: myproject   resource: myproject-app   public-client: true   use-resource-role-mappings: true<\/code><\/pre>\n<p><strong>auth-server-url<\/strong>\u00a0 &#8212; \u043f\u0443\u0442\u044c \u0434\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 KeyCloak<\/p>\n<p><strong>realm<\/strong> \u2013 \u0438\u043c\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0432 KeyCloak<\/p>\n<p><strong>resource<\/strong> \u2013 \u0438\u043c\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043e\u043d\u043e \u0436\u0435 client_id \u0432 KeyCloak<\/p>\n<p><strong>use-resource-role-mappings<\/strong> \u2013 \u0444\u043b\u0430\u0433, \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0447\u0442\u043e \u043d\u0430\u0434\u043e \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0440\u043e\u043b\u0438<br \/> \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0438\u0435\u0441\u044f \u0432 \u0441\u0435\u043a\u0446\u0438\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043d\u043e\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f JWT-\u0442\u043e\u043a\u0435\u043d\u0430. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e\u0431 \u0443\u0440\u043e\u0432\u043d\u044f\u0445 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0440\u043e\u043b\u0435\u0439 \u0432 \u0442\u043e\u043a\u0435\u043d\u0435 &#8212; <a href=\"https:\/\/usmanshahid.medium.com\/levels-of-access-control-through-keycloak-part-3-access-control-through-roles-and-tokens-a1744c04895e\">\u0442\u0443\u0442<\/a><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e spring-security, \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0432\u00a0<code>KeycloakWebSecurityConfigurerAdapter<\/code>, \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0439 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0430\u0434\u0430\u043f\u0442\u0435\u0440\u043e\u043c:<\/p>\n<pre><code class=\"java\">@KeycloakConfiguration @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {      @Override     protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {         return new NullAuthenticatedSessionStrategy();     }      @Autowired     public void configureGlobal(AuthenticationManagerBuilder authManagerBuilder) {         KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();         keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());         authManagerBuilder.authenticationProvider(keycloakAuthenticationProvider);     }      @Bean     public KeycloakConfigResolver keycloakConfigResolver() {         return new KeycloakSpringBootConfigResolver();     }      @Override     protected void configure(HttpSecurity http) throws Exception {         super.configure(http);         http                 .authorizeRequests()                 .antMatchers(\"\/authenticate\", \"\/refresh\").permitAll()                 .anyRequest().fullyAuthenticated();     }      @Override     public void configure(WebSecurity web) throws Exception {         web.ignoring().antMatchers(\"\/authenticate\", \"\/refresh\");     } }<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0432 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f 2 \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0430 \u2013 \/authenticate \u0438 \/refresh, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0448 auth server \u0441\u043c\u043e\u0433 \u0438\u0445 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u043a \u043d\u0435\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435, \u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c &#8212; \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0438 \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0442\u043e\u043a\u0435\u043d.<\/p>\n<h3>\u041a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f KeyCloak<\/h3>\n<p>\u041a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f KeyCloak \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c 2 \u043c\u0435\u0442\u043e\u0434\u0430:<\/p>\n<ul>\n<li>\n<p>\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0432 keyCloak (\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u0430)<\/p>\n<\/li>\n<li>\n<p>refresh \u0442\u043e\u043a\u0435\u043d\u0430<\/p>\n<\/li>\n<\/ul>\n<p>\u041e\u0431\u0430 \u043c\u0435\u0442\u043e\u0434\u0430 \u0431\u0443\u0434\u0443\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441 <code>org.keycloak.representations.AccessTokenResponse.class<\/code> \u0438\u0437 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u043e\u0439 \u0440\u0430\u043d\u0435\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438. \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043a\u043b\u0430\u0441\u0441\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 <a href=\"https:\/\/openid.net\/specs\/openid-connect-core-1_0.html#TokenResponse\">\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438<\/a> OpenId Connect \u0434\u043b\u044f Successful Token Response.<\/p>\n<p>\u041a\u043e\u0434 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"java\">@Component @RequiredArgsConstructor public class KeyCloakClient {     @Value(\"${keycloak.auth-server-url}\")     private String keyCloakUrl;     @Value(\"${keycloak.resource}\")     private String clientId;     @Value(\"${keycloak.realm}\")     private String realm;      private final RestTemplate restTemplate;      public AccessTokenResponse authenticate(AuthRequestDto request) {         HttpHeaders headers = new HttpHeaders();         headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);          MultiValueMap&lt;String, String> parameters = new LinkedMultiValueMap&lt;>();         parameters.add(\"username\",request.getUsername());         parameters.add(\"password\",request.getPassword());         parameters.add(\"grant_type\", \"password\");         parameters.add(\"client_id\", clientId);          HttpEntity&lt;MultiValueMap&lt;String, String>> entity = new HttpEntity&lt;>(parameters, headers);          return restTemplate.exchange(getAuthUrl(),                 HttpMethod.POST,                 entity,                 AccessTokenResponse.class).getBody();     }      public AccessTokenResponse refreshToken(String refreshToken) {         HttpHeaders headers = new HttpHeaders();         headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);          MultiValueMap&lt;String, String> parameters = new LinkedMultiValueMap&lt;>();         parameters.add(\"grant_type\", \"refresh_token\");         parameters.add(\"client_id\", clientId);         parameters.add(\"refresh_token\", refreshToken);          HttpEntity&lt;MultiValueMap&lt;String, String>> entity = new HttpEntity&lt;>(parameters, headers);          return restTemplate.exchange(getAuthUrl(),                 HttpMethod.POST,                 entity,                 AccessTokenResponse.class).getBody();     }      private String getAuthUrl() {         return UriComponentsBuilder.fromHttpUrl(keyCloakUrl)                 .pathSegment(\"realms\")                 .pathSegment(realm)                 .pathSegment(\"protocol\")                 .pathSegment(\"openid-connect\")                 .pathSegment(\"token\")                 .toUriString();     } }<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0441\u0441\u044b\u043b\u043a\u0438 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043a KeyCloak \u0438 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430, \u0434\u043b\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441 KeyCloak \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 application.yml, \u0432\u043d\u0435\u0441\u0435\u043d\u043d\u044b\u0435 \u0440\u0430\u043d\u0435\u0435. <\/p>\n<p>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u0443\u043a\u0430\u0437\u0430\u043b\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435:<\/p>\n<p><strong>grant_type<\/strong> \u2013 \u0442\u0438\u043f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u0430. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0438\u043f \u00abpassword\u00bb \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u0440\u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u0442\u0438\u043f \u00abrefresh_token\u00bb \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430.<\/p>\n<p><strong>client_id<\/strong> \u2013 \u0438\u043c\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0432 KeyCloak. \u041e\u043d \u0436\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 keycloak.resource \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 KeyCloak Adapter \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0440\u0430\u043d\u0435\u0435.<\/p>\n<p><strong>username\/password<\/strong> \u2013 credentials \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0439 \u0443\u0447\u0435\u0442\u043a\u0438, \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430.<\/p>\n<p><strong>refresh_token<\/strong> \u2013 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e refresh_token, \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u043a\u0435\u043d\u0430.<\/p>\n<p>\u0418 \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0438 refresh \u0442\u043e\u043a\u0435\u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043e\u0434\u043d\u0443 \u0438 \u0442\u0443 \u0436\u0435 \u0441\u0441\u044b\u043b\u043a\u0443 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043a KeyCloak. \u0412 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u0441\u043e <a href=\"https:\/\/www.keycloak.org\/docs\/latest\/securing_apps\/#authentication\">\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0435\u0439 KeyCloak<\/a> \u0444\u043e\u0440\u043c\u0430\u0442 \u0441\u0441\u044b\u043b\u043a\u0438, \u0432 \u043d\u0430\u0448\u0435\u043c <\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-329712","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/329712","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=329712"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/329712\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=329712"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=329712"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=329712"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}