{"id":347456,"date":"2023-05-15T09:00:50","date_gmt":"2023-05-15T09:00:50","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=347456"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=347456","title":{"rendered":"<span>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 Spring Cloud Gateway \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 OAuth2 \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u00a0 \u0438 KeyCloak \u0434\u043b\u044f \u0437\u0430\u0449\u0438\u0442\u044b \u0441\u043b\u0443\u0436\u0431<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<p><strong>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440!<\/strong><\/p>\n<p>\u042f, \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0439 Java-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u0441\u0442\u0443\u0434\u0435\u043d\u0442 3 \u043a\u0443\u0440\u0441\u0430, \u0438 \u044d\u0442\u043e &#8212; \u043c\u043e\u044f \u043f\u0435\u0440\u0432\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u0437\u0434\u0435\u0441\u044c. \u042f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0437\u0430\u043e\u0441\u0442\u0440\u044f\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0442\u0435\u043e\u0440\u0438\u0438, \u0442\u0430\u043a \u043a\u0430\u043a \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0441\u0442\u0430\u0442\u0435\u0439 \u043d\u0430 \u044d\u0442\u0443 \u0442\u0435\u043c\u0443, \u0430 \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0443\u0441\u044c \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0438 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0443 \u0441\u0432\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435. \u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043b\u0443\u0436\u0431, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e:  <\/p>\n<ul>\n<li>\n<p>Config server (\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Spring Cloud Config Server)  <\/p>\n<\/li>\n<li>\n<p>\u0421\u0435\u0440\u0432\u0438\u0441 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0441\u043b\u0443\u0436\u0431 (\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Eureka server)<\/p>\n<\/li>\n<li>\n<p>API-gateway (\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Spring Cloud Gateway)  <\/p>\n<\/li>\n<li>\n<p>Resource server (\u043d\u0430\u0448 \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u044b\u0439 \u0440\u0435\u0441\u0443\u0440\u0441)  <\/p>\n<\/li>\n<\/ul>\n<p><strong>\u041d\u0430 \u043a\u043e\u0433\u043e \u043d\u0430\u0446\u0435\u043b\u0435\u043d\u0430 \u044d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f?<\/strong><\/p>\n<p>\u0412 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0434\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u0434\u043b\u044f \u0442\u0430\u043a\u0438\u0445 \u0436\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0445 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u043a\u0430\u043a \u0438 \u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u044b\u0442\u0430\u044e\u0442\u0441\u044f \u043e\u0441\u0432\u043e\u0438\u0442\u044c \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 Spring Cloud \u0438 KeyCloak, \u043d\u043e \u0443\u0436\u0435 \u0438\u043c\u0435\u044e\u0442 \u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e \u043d\u0438\u0445.<\/p>\n<p><strong>\u0418\u0442\u0430\u043a, \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c!<\/strong><\/p>\n<p><strong>\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435<\/strong><\/p>\n<ol>\n<li>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 Keycloak  <\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u043b\u0443\u0436\u0431\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 (Config server)  <\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0441\u043b\u0443\u0436\u0431 (Eureka server)<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f API-\u0448\u043b\u044e\u0437\u0430 (Gateway server)  <\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u043e\u0433\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430 (Resource Server)<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u043b\u0443\u0436\u0431  <\/p>\n<\/li>\n<\/ol>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 Keycloak<\/h4>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u0434\u0442\u044f\u043d\u0435\u043c \u043e\u0431\u0440\u0430\u0437 KeyCloak \u0438\u0437 Docker \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b:<\/p>\n<p><code>docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io\/keycloak\/keycloak:21.1.1 start-dev<\/code>&nbsp;<\/p>\n<p>\u0433\u0434\u0435 \u0432\u043c\u0435\u0441\u0442\u043e KEYCLOAK_ADMIN \u0438&nbsp; KEYCLOAK_ADMIN_PASSWORD &nbsp; &nbsp;\u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0436\u0435\u043b\u0430\u0435\u043c\u044b\u0439 \u043b\u043e\u0433\u0438\u043d \u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0430\u0434\u043c\u0438\u043d\u0430.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/4ac\/288\/ae3\/4ac288ae3968795f0cd41ba31e905c58.png\" alt=\"\" title=\"\" width=\"1452\" height=\"701\"><\/figure>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430. \u041d\u0430\u043f\u043e\u043c\u043d\u044e, \u0447\u0442\u043e \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u043d\u0430\u0448 API-\u0448\u043b\u044e\u0437:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a45\/a33\/18d\/a45a3318d0387a007ae12bf21d0be88e.png\" alt=\"\" title=\"\" width=\"1530\" height=\"747\"><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/345\/2a2\/a8c\/3452a2a8c129139cec832a33a5606b5e.png\" alt=\"\" title=\"\" width=\"1268\" height=\"759\"><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b4f\/385\/c63\/b4f385c6300d259a8b7328f5de9cc48b.png\" alt=\"\" title=\"\" width=\"1507\" height=\"734\"><\/figure>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0432\u0435 \u0440\u043e\u043b\u0438 \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430 &#8212; \u0430\u0434\u043c\u0438\u043d \u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c:  <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c56\/ba2\/a02\/c56ba2a02f140b6bc5579521163fff53.png\" alt=\"\" title=\"\" width=\"1345\" height=\"453\"><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/0fe\/b80\/995\/0feb8099521f3e37ccf815ab3d04631c.png\" alt=\"\" title=\"\" width=\"1339\" height=\"415\"><\/figure>\n<p>\u0418 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c&nbsp; \u0434\u0432\u0443\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u043f\u0440\u0438\u0441\u0432\u043e\u0438\u043c \u0438\u043c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0440\u043e\u043b\u0438:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d7b\/4e6\/298\/d7b4e6298a760f74b5736c4291a7497e.png\" alt=\"\" title=\"\" width=\"1444\" height=\"777\"><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/264\/868\/d32\/264868d321872ba80492c656620a0381.png\" alt=\"\" title=\"\" width=\"1367\" height=\"494\"><\/figure>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u043f\u0430\u0440\u043e\u043b\u0438 \u0434\u043b\u044f \u043d\u0430\u0448\u0438\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/309\/e9d\/ae5\/309e9dae5917fe4b1448694208f7231b.png\" alt=\"\" title=\"\" width=\"685\" height=\"375\"><\/figure>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 KeyCloak \u043f\u043e\u0434\u043e\u0448\u043b\u0430 \u043a \u043a\u043e\u043d\u0446\u0443 \u0438 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0441\u043b\u0443\u0436\u0431\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438.  <\/p>\n<h4>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u043b\u0443\u0436\u0431\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 (Config server)  <\/h4>\n<p>\u042f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 (\u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044e \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u0441\u0442\u0430\u0442\u044c\u0438, \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u043d\u044b\u0435 \u0434\u0440\u0443\u0433\u0438\u043c \u0432\u0438\u0434\u0430\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438). \u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u043d\u0430\u0448\u0435\u043c pom.xml \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a: <\/p>\n<pre><code class=\"xml\">   &lt;dependency&gt;        &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt;        &lt;artifactId&gt;spring-cloud-config-server&lt;\/artifactId&gt;    &lt;\/dependency&gt;    &lt;dependency&gt;        &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;        &lt;artifactId&gt;spring-boot-devtools&lt;\/artifactId&gt;        &lt;scope&gt;runtime&lt;\/scope&gt;        &lt;optional&gt;true&lt;\/optional&gt;    &lt;\/dependency&gt;    &lt;dependency&gt;        &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;        &lt;artifactId&gt;spring-boot-configuration-processor&lt;\/artifactId&gt;        &lt;optional&gt;true&lt;\/optional&gt;    &lt;\/dependency&gt;    &lt;dependency&gt;        &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;        &lt;artifactId&gt;spring-boot-starter-test&lt;\/artifactId&gt;        &lt;scope&gt;test&lt;\/scope&gt;    &lt;\/dependency&gt; <\/code><\/pre>\n<p>\u041d\u0430\u0448 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0438 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:  <\/p>\n<p>ConfigServerApplication.java<\/p>\n<pre><code class=\"java\"> import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.config.server.EnableConfigServer;  @SpringBootApplication @EnableConfigServer public class ConfigServerApplication {     public static void main(String[] args) {        SpringApplication.run(ConfigServerApplication.class, args);    }  } <\/code><\/pre>\n<p>\u0410\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044f @EnableConfigServer \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043d\u0430\u0448 \u0441\u0435\u0440\u0432\u0438\u0441 \u0431\u0443\u0434\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438, \u0438 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043a\u0430\u0436\u0434\u0430\u044f \u0441\u043b\u0443\u0436\u0431\u0430 \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u043d\u0435\u043c\u0443, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u0432\u043e\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e.<\/p>\n<p>application.properties<\/p>\n<pre><code class=\"java\">spring.application.name=config-server spring.profiles.active=native server.port=8071 spring.cloud.config.server.native.search-locations=<\/code><\/pre>\n<ul>\n<li>\n<p>spring.application.name &#8212; \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043d\u0430\u0448\u0435\u0439 \u0441\u043b\u0443\u0436\u0431\u044b  <\/p>\n<\/li>\n<li>\n<p>spring.profiles.active &#8212; \u0434\u0430\u043d\u043d\u043e\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043d\u0430\u0448\u0430 \u0441\u043b\u0443\u0436\u0431\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0434\u043b\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p>spring.cloud.config.server.native.search-locations &#8212; \u0437\u0434\u0435\u0441\u044c \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0443\u0442\u044c \u0432 \u043d\u0430\u0448\u0435\u043c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435, \u0433\u0434\u0435 \u0431\u0443\u0434\u0443\u0442 \u043b\u0435\u0436\u0430\u0442\u044c properties \u0444\u0430\u0439\u043b\u044b \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u043b\u0443\u0436\u0431\u044b  <\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u043b\u0443\u0436\u0431\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0439 \u0437\u0430\u043a\u043e\u043d\u0447\u0435\u043d\u043e.<\/p>\n<h4>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0441\u043b\u0443\u0436\u0431 (Eureka server)<\/h4>\n<p>\u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0441\u043b\u0443\u0436\u0431. \u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 pom.xml:<\/p>\n<pre><code class=\"xml\">   &lt;dependency&gt;        &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt;        &lt;artifactId&gt;spring-cloud-starter-netflix-eureka-server&lt;\/artifactId&gt;    &lt;\/dependency&gt;    &lt;dependency&gt;        &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt;        &lt;artifactId&gt;spring-cloud-starter-config&lt;\/artifactId&gt;    &lt;\/dependency&gt;    &lt;dependency&gt;        &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;        &lt;artifactId&gt;spring-boot-devtools&lt;\/artifactId&gt;        &lt;scope&gt;runtime&lt;\/scope&gt;        &lt;optional&gt;true&lt;\/optional&gt;    &lt;\/dependency&gt;    &lt;dependency&gt;        &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;        &lt;artifactId&gt;spring-boot-configuration-processor&lt;\/artifactId&gt;        &lt;optional&gt;true&lt;\/optional&gt;    &lt;\/dependency&gt;    &lt;dependency&gt;        &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;        &lt;artifactId&gt;spring-boot-starter-test&lt;\/artifactId&gt;        &lt;scope&gt;test&lt;\/scope&gt;    &lt;\/dependency&gt; <\/code><\/pre>\n<p>EurekaServerApplication \u043a\u043b\u0430\u0441\u0441 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:  <\/p>\n<p>EurekaServerApplication.java  <\/p>\n<pre><code class=\"java\">@SpringBootApplication @EnableEurekaServer @RefreshScope public class EurekaServerApplication {     public static void main(String[] args) {        SpringApplication.run(EurekaServerApplication.class, args);    }  } <\/code><\/pre>\n<p>application.properties<\/p>\n<pre><code class=\"java\">spring.application.name=eserver spring.profiles.active=dev spring.config.import=optional:configserver:http:\/\/localhost:8071<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0441\u043b\u0443\u0436\u0431\u044b, \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0438 \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0441\u043b\u0443\u0436\u0431\u044b \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435:<\/p>\n<p><a href=\"http:\/\/localhost:8071\/eserver\/dev\" rel=\"noopener noreferrer nofollow\"><u>http:\/\/localhost:8071\/eserver\/dev<\/u><\/a><\/p>\n<p>\u0412 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b eserver-dev.properties \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u0441\u043b\u0443\u0436\u0431\u044b \u0438 \u0435\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435\u043c \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043d\u0435\u0433\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430:<\/p>\n<pre><code class=\"java\">eureka.client.register-with-eureka=false eureka.client.fetch-registry=false eureka.instance.hostname=localhost server.port=8070<\/code><\/pre>\n<ul>\n<li>\n<p>eureka.client.register-with-eureka \u2014 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442, \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043b\u0438 \u0441\u0435\u0440\u0432\u0438\u0441 \u043a\u0430\u043a \u043a\u043b\u0438\u0435\u043d\u0442 \u043d\u0430 Eureka Server.  <\/p>\n<\/li>\n<li>\n<p>eureka.client.fetch-registry \u2014 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0438\u043b\u0438 \u043d\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u0445.  <\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 API &#8212; \u0448\u043b\u044e\u0437\u0430.<\/p>\n<h4>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f API-\u0448\u043b\u044e\u0437\u0430 (Spring Cloud Gateway)<\/h4>\n<p>\u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 pom.xml:<\/p>\n<pre><code class=\"xml\">&lt;dependency&gt;    &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt;    &lt;artifactId&gt;spring-cloud-starter-gateway&lt;\/artifactId&gt; &lt;\/dependency&gt; &lt;dependency&gt;    &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt;    &lt;artifactId&gt;spring-cloud-starter-netflix-eureka-client&lt;\/artifactId&gt; &lt;\/dependency&gt; &lt;dependency&gt;    &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt;    &lt;artifactId&gt;spring-cloud-starter-config&lt;\/artifactId&gt;    &lt;version&gt;4.0.1&lt;\/version&gt; &lt;\/dependency&gt; &lt;dependency&gt;    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;    &lt;artifactId&gt;spring-boot-starter-oauth2-client&lt;\/artifactId&gt; &lt;\/dependency&gt; &lt;dependency&gt;    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;    &lt;artifactId&gt;spring-boot-devtools&lt;\/artifactId&gt;    &lt;scope&gt;runtime&lt;\/scope&gt;    &lt;optional&gt;true&lt;\/optional&gt; &lt;\/dependency&gt; &lt;dependency&gt;    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;    &lt;artifactId&gt;spring-boot-configuration-processor&lt;\/artifactId&gt;    &lt;optional&gt;true&lt;\/optional&gt; &lt;\/dependency&gt; &lt;dependency&gt;    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;    &lt;artifactId&gt;spring-boot-starter-test&lt;\/artifactId&gt;    &lt;scope&gt;test&lt;\/scope&gt; &lt;\/dependency&gt; <\/code><\/pre>\n<p>application.properties<\/p>\n<pre><code class=\"java\">spring.application.name=gateway spring.profiles.active=dev spring.config.import=optional:configserver:http:\/\/localhost:8071<\/code><\/pre>\n<p>gateway-dev.properties  <\/p>\n<pre><code class=\"java\">eureka.client.service-url.defaultZone=http:\/\/localhost:8070\/eureka eureka.client.register-with-eureka=true eureka.instance.prefer-ip-address=true eureka.client.fetch-registry=true eureka.instance.hostname=localhost spring.cloud.gateway.discovery.locator.enabled=true spring.cloud.gateway.discovery.locator.lower-case-service-id=true server.port=8081 spring.cloud.gateway.default-filters=TokenRelay= spring.security.oauth2.client.provider.keycloak.issuer-uri=http:\/\/localhost:8080\/realms\/habr spring.security.oauth2.client.registration.keycloak.provider=keycloak spring.security.oauth2.client.registration.keycloak.client-id=client-id spring.security.oauth2.client.registration.keycloak.client-secret=client-secret spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code spring.security.oauth2.client.registration.keycloak.scope=openid <\/code><\/pre>\n<ul>\n<li>\n<p>eureka.client.register-with-eureka &#8212; \u0441\u043b\u0443\u0436\u0431\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 Eureka server<\/p>\n<\/li>\n<li>\n<p>eureka.client.service-url.defaultZone &#8212; \u0441\u0441\u044b\u043b\u043a\u0430, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u0441\u043b\u0443\u0436\u0431\u0435 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u044f  <\/p>\n<\/li>\n<li>\n<p>spring.cloud.gateway.discovery.locator.enabled &#8212; \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u0432 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0441\u043b\u0443\u0436\u0431, \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0432 Eureka  <\/p>\n<\/li>\n<li>\n<p>spring.cloud.gateway.default-filters=TokenRelay= &#8212; \u043f\u0435\u0440\u0435\u0441\u044b\u043b\u043a\u0430 \u0442\u043e\u043a\u0435\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u043c\u0435\u0436\u0434\u0443 \u0441\u043b\u0443\u0436\u0431\u0430\u043c\u0438  <\/p>\n<\/li>\n<li>\n<p>spring.security.oauth2.client.provider.keycloak.issuer-uri &#8212; \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0432\u044b\u0434\u0430\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0430  <\/p>\n<\/li>\n<li>\n<p>spring.security.oauth2.client.registration.keycloak.client-id &#8212; \u0437\u0434\u0435\u0441\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c id \u043a\u043b\u0438\u0435\u043d\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u0432 KeyCloak  <\/p>\n<\/li>\n<li>\n<p>spring.security.oauth2.client.registration.keycloak.client-secret &#8212; Client Secret \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430  <\/p>\n<\/li>\n<\/ul>\n<p>\u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043f\u0440\u043e \u0432\u0441\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435:<\/p>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/701912\/\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/habr.com\/ru\/articles\/701912\/<\/u><\/a><\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f Security Config \u0434\u043b\u044f API-\u0448\u043b\u044e\u0437\u0430, \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u044e\u0449\u0438\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c:<\/p>\n<p>SecurityConfig.java<\/p>\n<pre><code class=\"java\">@Configuration @EnableWebFluxSecurity public class SecurityConfig {    @Autowired    private ReactiveClientRegistrationRepository registrationRepository;    @Bean    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {        http                .authorizeExchange()                .anyExchange()                .authenticated()                .and()                .oauth2Login()                .and()                .logout()                .logoutSuccessHandler(oidcLogoutSuccessHandler())        ;         return http.build();    }    @Bean    public ServerLogoutSuccessHandler oidcLogoutSuccessHandler() {        OidcClientInitiatedServerLogoutSuccessHandler successHandler = new OidcClientInitiatedServerLogoutSuccessHandler(registrationRepository);        successHandler.setPostLogoutRedirectUri(url);        return successHandler;    } } <\/code><\/pre>\n<h4>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u043e\u0433\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430 (Resource server)<\/h4>\n<p>\u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 pom.xml:<\/p>\n<pre><code class=\"xml\">&lt;dependency&gt;    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;    &lt;artifactId&gt;spring-boot-starter-oauth2-resource-server&lt;\/artifactId&gt; &lt;\/dependency&gt; &lt;dependency&gt;    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;    &lt;artifactId&gt;spring-boot-starter-web&lt;\/artifactId&gt; &lt;\/dependency&gt; &lt;dependency&gt;    &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt;    &lt;artifactId&gt;spring-cloud-starter-config&lt;\/artifactId&gt; &lt;\/dependency&gt; &lt;dependency&gt;    &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt;    &lt;artifactId&gt;spring-cloud-starter-netflix-eureka-client&lt;\/artifactId&gt; &lt;\/dependency&gt; &lt;dependency&gt;    &lt;groupId&gt;org.projectlombok&lt;\/groupId&gt;    &lt;artifactId&gt;lombok&lt;\/artifactId&gt;    &lt;optional&gt;true&lt;\/optional&gt; &lt;\/dependency&gt; &lt;dependency&gt;    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;    &lt;artifactId&gt;spring-boot-devtools&lt;\/artifactId&gt;    &lt;scope&gt;runtime&lt;\/scope&gt;    &lt;optional&gt;true&lt;\/optional&gt; &lt;\/dependency&gt; &lt;dependency&gt;    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;    &lt;artifactId&gt;spring-boot-configuration-processor&lt;\/artifactId&gt;    &lt;optional&gt;true&lt;\/optional&gt; &lt;\/dependency&gt; &lt;dependency&gt;    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;    &lt;artifactId&gt;spring-boot-starter-test&lt;\/artifactId&gt;    &lt;scope&gt;test&lt;\/scope&gt; &lt;\/dependency&gt; <\/code><\/pre>\n<p>resource-dev.properties  <\/p>\n<pre><code class=\"java\">server.port=0 eureka.client.service-url.defaultZone=http:\/\/localhost:8070\/eureka eureka.client.register-with-eureka=true eureka.instance.prefer-ip-address=true eureka.client.fetch-registry=true spring.security.oauth2.resourceserver.jwt.issuer-uri=http:\/\/localhost:8080\/realms\/habr spring.security.oauth2.resourceserver.jwt.jwk-set-uri=${spring.security.oauth2.resourceserver.jwt.issuer-uri}\/protocol\/openid-connect\/certs jwt.auth.converter.resource-id=habr-client jwt.auth.converter.principal-attribute=preferred_username<\/code><\/pre>\n<p>JWT \u0432\u043a\u043b\u044e\u0447\u0430\u044e\u0442 \u0432\u0441\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 \u0442\u043e\u043a\u0435\u043d\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043f\u043e\u0434\u043f\u0438\u0441\u044c \u0442\u043e\u043a\u0435\u043d\u0430, \u0447\u0442\u043e\u0431\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0435 \u0431\u044b\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u044b. \u0421\u0432\u043e\u0439\u0441\u0442\u0432\u043e jwk-set-uri \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u043a\u043b\u044e\u0447 , \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u044d\u0442\u043e\u0439 \u0446\u0435\u043b\u0438. \u0414\u0430\u043d\u043d\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f:  <\/p>\n<ul>\n<li>\n<p>jwt.auth.converter.resource-id &#8212; id \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430 KeyCloak  <\/p>\n<\/li>\n<li>\n<p>jwt.auth.converter.principal-attribute &#8212; \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044f JWT \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.  <\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043c\u0430\u043f\u043f\u0435\u0440\u044b \u0434\u043b\u044f \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u0438\u0437 JWT \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435:<\/p>\n<p>JwtAuthConverterProperties.java  <\/p>\n<pre><code class=\"java\">@Data @Validated @Configuration @ConfigurationProperties(prefix = \"jwt.auth.converter\") public class JwtAuthConverterProperties {     private String resourceId;    private String principalAttribute; } <\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u0431\u0443\u0434\u0435\u0442 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0442\u044c \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0435 \u0432\u044b\u0448\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 JwtAuthConverter:  <\/p>\n<p>JwtAuthConverter.java<\/p>\n<pre><code class=\"java\">@Component public class JwtAuthConverter implements Converter&lt;Jwt, AbstractAuthenticationToken&gt; {     private final JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();     private final JwtAuthConverterProperties properties;     public JwtAuthConverter(JwtAuthConverterProperties properties) {        this.properties = properties;    }     @Override    public AbstractAuthenticationToken convert(Jwt jwt) {        Collection&lt;GrantedAuthority&gt; authorities = Stream.concat(                jwtGrantedAuthoritiesConverter.convert(jwt).stream(),                extractResourceRoles(jwt).stream()).collect(Collectors.toSet());        return new JwtAuthenticationToken(jwt, authorities, getPrincipalClaimName(jwt));    }     private String getPrincipalClaimName(Jwt jwt) {        String claimName = JwtClaimNames.SUB;        if (properties.getPrincipalAttribute() != null) {            claimName = properties.getPrincipalAttribute();        }        return jwt.getClaim(claimName);    }     private Collection&lt;? extends GrantedAuthority&gt; extractResourceRoles(Jwt jwt) {        Map&lt;String, Object&gt; resourceAccess = jwt.getClaim(\"resource_access\");        Map&lt;String, Object&gt; resource;        Collection&lt;String&gt; resourceRoles;        if (resourceAccess == null                || (resource = (Map&lt;String, Object&gt;) resourceAccess.get(properties.getResourceId())) == null                || (resourceRoles = (Collection&lt;String&gt;) resource.get(\"roles\")) == null) {            return Set.of();        }        return resourceRoles.stream()                .map(role -&gt; new SimpleGrantedAuthority(\"ROLE_\" + role))                .collect(Collectors.toSet());    } } <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435 \u0438 \u0435\u0433\u043e \u0440\u043e\u043b\u044f\u0445. \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0431\u044b\u043b\u0438 \u0432\u0437\u044f\u0442\u044b \u0438\u0437 \u0441\u0442\u0430\u0442\u044c\u0438: <a href=\"https:\/\/medium.com\/geekculture\/using-keycloak-with-spring-boot-3-0-376fa9f60e0b\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/medium.com\/geekculture\/using-keycloak-with-spring-boot-3-0-376fa9f60e0b<\/u><\/a><\/p>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441 Message.<\/p>\n<p>Message.java<\/p>\n<pre><code class=\"java\">@Getter @Setter @NoArgsConstructor  public class Message {    private boolean status;     @JsonInclude(JsonInclude.Include.NON_NULL)    private String msg;     @JsonInclude(JsonInclude.Include.NON_NULL)    private Error error;     public Message(boolean status, Error error) {        this.status = status;        this.error = error;    }    public Message(boolean status, String message) {        this.status = status;        this.msg=message;    } } <\/code><\/pre>\n<p>Error.java  <\/p>\n<pre><code class=\"java\">@Getter @Setter @NoArgsConstructor public class Error {    public Error(String msg, int code) {        this.msg = msg;        this.code = code;    }    private String msg;    private int code;  } <\/code><\/pre>\n<p>\u041d\u0430\u0448 RestController \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0434\u0432\u0435 \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0435 \u0442\u043e\u0447\u043a\u0438 \u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:  <\/p>\n<pre><code class=\"java\">@RestController public class ResourceController {    @GetMapping(value = \"\/admin\")    public ResponseEntity&lt;Message&gt; helloAdmin(){        return new ResponseEntity&lt;&gt;(new Message(true, \"Hello from Admin\"), HttpStatusCode.valueOf(HttpStatus.OK.value()));    }     @GetMapping(value = \"\/user\")    public ResponseEntity&lt;Message&gt; helloUser(){        return new ResponseEntity&lt;&gt;(new Message(true, \"Hello from User\"), HttpStatusCode.valueOf(HttpStatus.OK.value()));    }  } <\/code><\/pre>\n<p>SecurityConfig.java<\/p>\n<pre><code class=\"java\">@Configuration @EnableWebSecurity public class SecurityConfig {    @Autowired    private  JwtAuthConverter jwtAuthConverter;    @Bean    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {        http                .authorizeHttpRequests((authz) -&gt; {                            try {                                authz                                        .requestMatchers(\"\/admin\").hasRole(\"ADMIN\")                                        .requestMatchers(\"\/user\").hasRole(\"USER\")                                        .anyRequest().authenticated()                                        .and()                                        .exceptionHandling().accessDeniedHandler(accessDeniedHandler())                                        .and()                                        .oauth2ResourceServer()                                        .jwt()                                        .jwtAuthenticationConverter(jwtAuthConverter);                            } catch (Exception e) {                                e.printStackTrace();                            }                        }                );        return http.build();    }    @Bean    public AccessDeniedHandler accessDeniedHandler(){        return new CustomAccessDeniedHandler();    } } <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u0430\u0448 JwtAuthConverter \u0438 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 AccessDeniedHandler, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 Message \u0441 \u043a\u043e\u0434\u043e\u043c 403, \u0435\u0441\u043b\u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u043c\u043e\u0433\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u043d\u0435\u0442 \u043f\u0440\u0430\u0432:<\/p>\n<pre><code class=\"json\">{   \"status\" : false,   \"error\" : {     \"msg\" : \"Forbidden\",     \"code\" : 403   } } <\/code><\/pre>\n<p>CustomAccessDeniedHandler.java  <\/p>\n<pre><code class=\"java\">public class CustomAccessDeniedHandler implements AccessDeniedHandler {     private static final ObjectMapper objectMapper = new ObjectMapper();    @Override    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {        response.setContentType(\"application\/json;charset=utf-8\");        response.setStatus(HttpStatus.FORBIDDEN.value());        response.getOutputStream().println(objectMapper.writerWithDefaultPrettyPrinter().                writeValueAsString(                        new Message(false,                                new Error(\"Forbidden\", 403))));    } } <\/code><\/pre>\n<h4>\u0417\u0430\u043f\u0443\u0441\u043a \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u043b\u0443\u0436\u0431 <\/h4>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c Config Server. \u041f\u0435\u0440\u0435\u0439\u0434\u044f, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u043e <a href=\"http:\/\/localhost:8071\/resource\/dev\" rel=\"noopener noreferrer nofollow\"><u>http:\/\/localhost:8071\/resource\/dev<\/u><\/a> \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f Resource server:  <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/02f\/e48\/f80\/02fe48f80aefce37bcbbcaaef627be33.png\" alt=\"\" title=\"\" width=\"1139\" height=\"478\"><\/figure>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c Eureka server. \u041f\u0435\u0440\u0435\u0439\u0434\u044f \u043f\u043e <a href=\"http:\/\/localhost:8070\" rel=\"noopener noreferrer nofollow\"><u>http:\/\/localhost:8070<\/u><\/a> \u043c\u044b \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043d\u0430 \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043a\u0443 Eureka:  <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/3be\/fdd\/c5f\/3befddc5f6977c9546fc549ca96198f5.png\" alt=\"\" title=\"\" width=\"1904\" height=\"939\"><\/figure>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u043d\u0430\u0448 \u0448\u043b\u044e\u0437 \u0438 resource server. \u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u0435\u0449\u0435 \u0440\u0430\u0437 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043a\u0443 Eureka \u0438 \u0443\u0431\u0435\u0434\u0438\u043c\u0441\u044f, \u0447\u0442\u043e \u043d\u0430\u0448\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0438\u0441\u044c:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/586\/dcb\/b01\/586dcbb01dfc0162ac897ba2f07979c2.png\" alt=\"\" title=\"\" width=\"1886\" height=\"939\"><\/figure>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u0438\u043c, \u043d\u0430\u0448\u0438 \u0441\u043b\u0443\u0436\u0431\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442, \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043f\u043e <a href=\"http:\/\/localhost:8081\/resource\/admin\" rel=\"noopener noreferrer nofollow\"><u>http:\/\/localhost:8081\/resource\/admin<\/u><\/a> (\u043d\u0430\u0448 API-\u0448\u043b\u044e\u0437 \u0441\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0441\u043b\u0443\u0436\u0431\u044b, \u0430 \u043f\u043e\u0441\u043b\u0435 &#8212; \u0430\u0434\u0440\u0435\u0441 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438)&nbsp; \u0438 \u043d\u0430\u0441 \u0434\u043e\u043b\u0436\u043d\u043e \u0440\u0435\u0434\u0438\u0440\u0435\u043a\u0442\u043d\u0443\u0442\u044c \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043a\u0443 KeyCloak. \u0412\u0432\u0435\u0434\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0437\u0430\u0434\u0430\u0432\u0430\u043b\u0438 \u0432 \u0441\u0430\u043c\u043e\u043c \u043d\u0430\u0447\u0430\u043b\u0435 \u0434\u043b\u044f \u0430\u0434\u043c\u0438\u043d\u0430 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0440\u0435\u0441\u0443\u0440\u0441\u0443.  <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b89\/9b6\/f3c\/b899b6f3c79bd9053d1b42901f51c8ed.png\" alt=\"\" title=\"\" width=\"1021\" height=\"645\"><\/figure>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e, \u043f\u043e <a href=\"http:\/\/localhost:8081\/resource\/admin\" rel=\"noopener noreferrer nofollow\"><u>http:\/\/localhost:8081\/resource\/admin<\/u><\/a> \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0442\u0430\u043a\u043e\u0439 \u043e\u0442\u0432\u0435\u0442:  <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f11\/f9f\/a76\/f11f9fa76c7c63d669f1ec316ca45dda.png\" alt=\"\" title=\"\" width=\"738\" height=\"213\"><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/474\/321\/dde\/474321dde2409818262029a920382fcd.png\" alt=\"\" title=\"\" width=\"629\" height=\"220\"><\/figure>\n<p>\u0415\u0441\u043b\u0438 \u0436\u0435 \u043c\u044b \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043f\u043e&nbsp; <a href=\"http:\/\/localhost:8081\/resource\/user\" rel=\"noopener noreferrer nofollow\">http:\/\/localhost:8081\/resource\/user<\/a>, \u043e\u0442\u0432\u0435\u0442 \u0431\u0443\u0434\u0435\u0442 \u0442\u0430\u043a\u0438\u043c:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/78c\/bd3\/faa\/78cbd3faa1ecd2cd548512f6cc329ea1.png\" alt=\"\" title=\"\" width=\"707\" height=\"207\"><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/022\/84c\/b2e\/02284cb2e6dae77ea9cd166d8df47cec.png\" alt=\"\" title=\"\" width=\"664\" height=\"158\"><\/figure>\n<p>\u041d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043c\u043e\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u043a \u043a\u043e\u043d\u0446\u0443, \u043d\u0430\u0434\u0435\u044e\u0441\u044c, \u0447\u0442\u043e \u0434\u0430\u043d\u043d\u0430\u044f \u0440\u0430\u0431\u043e\u0442\u0430 \u043f\u0440\u0438\u043d\u0435\u0441\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u0443. \u0422\u0430\u043a\u0436\u0435 \u0436\u0434\u0443 \u043a\u0430\u043a\u0438\u0445-\u043b\u0438\u0431\u043e \u0437\u0430\u043c\u0435\u0447\u0430\u043d\u0438\u0439 \u043e\u0442 \u043e\u043f\u044b\u0442\u043d\u044b\u0445 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432.  <\/p>\n<p><a href=\"https:\/\/github.com\/timofeyreedtz\/habr-keycloak-apigateway\" rel=\"noopener noreferrer nofollow\">\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442 GitHub<\/a><\/p>\n<p>\u0421\u0442\u0430\u0442\u044c\u0438 \u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438\u0441\u044c \u043c\u043d\u043e\u0439:  <\/p>\n<p><a href=\"https:\/\/medium.com\/geekculture\/using-keycloak-with-spring-boot-3-0-376fa9f60e0b\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/medium.com\/geekculture\/using-keycloak-with-spring-boot-3-0-376fa9f60e0b<\/u><\/a>  <\/p>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/701912\/\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/habr.com\/ru\/articles\/701912\/<\/u><\/a>  <\/p>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/otus\/articles\/590761\/\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/habr.com\/ru\/companies\/otus\/articles\/590761\/<\/u><\/a>  <\/p>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/701912\/\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/habr.com\/ru\/articles\/701912\/<\/u><\/a><\/p>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/otus\/articles\/539348\/\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/habr.com\/ru\/companies\/otus\/articles\/539348\/<\/u><\/a>  <\/p>\n<\/p>\n<\/div>\n<\/div>\n<p> <!----> <!----><\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/735076\/\"> https:\/\/habr.com\/ru\/articles\/735076\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<p><strong>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440!<\/strong><\/p>\n<p>\u042f, \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0439 Java-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u0441\u0442\u0443\u0434\u0435\u043d\u0442 3 \u043a\u0443\u0440\u0441\u0430, \u0438 \u044d\u0442\u043e &#8212; \u043c\u043e\u044f \u043f\u0435\u0440\u0432\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u0437\u0434\u0435\u0441\u044c. \u042f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0437\u0430\u043e\u0441\u0442\u0440\u044f\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0442\u0435\u043e\u0440\u0438\u0438, \u0442\u0430\u043a \u043a\u0430\u043a \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0441\u0442\u0430\u0442\u0435\u0439 \u043d\u0430 \u044d\u0442\u0443 \u0442\u0435\u043c\u0443, \u0430 \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0443\u0441\u044c \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0438 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0443 \u0441\u0432\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435. \u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043b\u0443\u0436\u0431, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e:  <\/p>\n<ul>\n<li>\n<p>Config server (\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Spring Cloud Config Server)  <\/p>\n<\/li>\n<li>\n<p>\u0421\u0435\u0440\u0432\u0438\u0441 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0441\u043b\u0443\u0436\u0431 (\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Eureka server)<\/p>\n<\/li>\n<li>\n<p>API-gateway (\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Spring Cloud Gateway)  <\/p>\n<\/li>\n<li>\n<p>Resource server (\u043d\u0430\u0448 \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u044b\u0439 \u0440\u0435\u0441\u0443\u0440\u0441)  <\/p>\n<\/li>\n<\/ul>\n<p><strong>\u041d\u0430 \u043a\u043e\u0433\u043e \u043d\u0430\u0446\u0435\u043b\u0435\u043d\u0430 \u044d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f?<\/strong><\/p>\n<p>\u0412 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0434\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u0434\u043b\u044f \u0442\u0430\u043a\u0438\u0445 \u0436\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0445 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u043a\u0430\u043a \u0438 \u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u044b\u0442\u0430\u044e\u0442\u0441\u044f \u043e\u0441\u0432\u043e\u0438\u0442\u044c \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 Spring Cloud \u0438 KeyCloak, \u043d\u043e \u0443\u0436\u0435 \u0438\u043c\u0435\u044e\u0442 \u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e \u043d\u0438\u0445.<\/p>\n<p><strong>\u0418\u0442\u0430\u043a, \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c!<\/strong><\/p>\n<p><strong>\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435<\/strong><\/p>\n<ol>\n<li>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 Keycloak  <\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u043b\u0443\u0436\u0431\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 (Config server)  <\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0441\u043b\u0443\u0436\u0431 (Eureka server)<\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f API-\u0448\u043b\u044e\u0437\u0430 (Gateway server)  <\/p>\n<\/li>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u043e\u0433\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u0430 (Resource Server)<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u043b\u0443\u0436\u0431  <\/p>\n<\/li>\n<\/ol>\n<h4>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 Keycloak<\/h4>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u0434\u0442\u044f\u043d\u0435\u043c \u043e\u0431\u0440\u0430\u0437 KeyCloak \u0438\u0437 Docker \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b:<\/p>\n<p><code>docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io\/keycloak\/keycloak:21.1.1 start-dev<\/code>&nbsp;<\/p>\n<p>\u0433\u0434\u0435 \u0432\u043c\u0435\u0441\u0442\u043e KEYCLOAK_ADMIN \u0438&nbsp; KEYCLOAK_ADMIN_PASSWORD &nbsp; &nbsp;\u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0436\u0435\u043b\u0430\u0435\u043c\u044b\u0439 \u043b\u043e\u0433\u0438\u043d \u0438 \u043f\u0430\u0440\u043e\u043b\u044c \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0430\u0434\u043c\u0438\u043d\u0430.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430. \u041d\u0430\u043f\u043e\u043c\u043d\u044e, \u0447\u0442\u043e \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u043d\u0430\u0448 API-\u0448\u043b\u044e\u0437:<\/p>\n<figure class=\"full-width\"><\/figure>\n<figure class=\"full-width\"><\/figure>\n<figure class=\"full-width\"><\/figure>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0432\u0435 \u0440\u043e\u043b\u0438 \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430 &#8212; \u0430\u0434\u043c\u0438\u043d \u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c:  <\/p>\n<figure class=\"full-width\"><\/figure>\n<figure class=\"full-width\"><\/figure>\n<p>\u0418 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c&nbsp; \u0434\u0432\u0443\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u043f\u0440\u0438\u0441\u0432\u043e\u0438\u043c \u0438\u043c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0440\u043e\u043b\u0438:<\/p>\n<figure class=\"full-width\"><\/figure>\n<figure class=\"full-width\"><\/figure>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u043f\u0430\u0440\u043e\u043b\u0438 \u0434\u043b\u044f \u043d\u0430\u0448\u0438\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439:<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 KeyCloak \u043f\u043e\u0434\u043e\u0448\u043b\u0430 \u043a \u043a\u043e\u043d\u0446\u0443 \u0438 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0441\u043b\u0443\u0436\u0431\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438.  <\/p>\n<h4>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u043b\u0443\u0436\u0431\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 (Config server)  <\/h4>\n<p>\u042f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 (\u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044e \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u0441\u0442\u0430\u0442\u044c\u0438, \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u043d\u044b\u0435 \u0434\u0440\u0443\u0433\u0438\u043c \u0432\u0438\u0434\u0430\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438). \u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u043d\u0430\u0448\u0435\u043c pom.xml \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a: <\/p>\n<pre><code class=\"xml\">   &lt;dependency&gt;        &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt;        &lt;artifactId&gt;spring-cloud-config-server&lt;\/artifactId&gt;    &lt;\/dependency&gt;    &lt;dependency&gt;        &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;        &lt;artifactId&gt;spring-boot-devtools&lt;\/artifactId&gt;        &lt;scope&gt;runtime&lt;\/scope&gt;        &lt;optional&gt;true&lt;\/optional&gt;    &lt;\/dependency&gt;    &lt;dependency&gt;        &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;        &lt;artifactId&gt;spring-boot-configuration-processor&lt;\/artifactId&gt;        &lt;optional&gt;true&lt;\/optional&gt;    &lt;\/dependency&gt;    &lt;dependency&gt;        &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;        &lt;artifactId&gt;spring-boot-starter-test&lt;\/artifactId&gt;        &lt;scope&gt;test&lt;\/scope&gt;    &lt;\/dependency&gt; <\/code><\/pre>\n<p>\u041d\u0430\u0448 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0438 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:  <\/p>\n<p>ConfigServerApplication.java<\/p>\n<pre><code class=\"java\"> import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.config.server.EnableConfigServer;  @SpringBootApplication @EnableConfigServer public class ConfigServerApplication {     public static void main(String[] args) {        SpringApplication.run(ConfigServerApplication.class, args);    }  } <\/code><\/pre>\n<p>\u0410\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u044f @EnableConfigServer \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043d\u0430\u0448 \u0441\u0435\u0440\u0432\u0438\u0441 \u0431\u0443\u0434\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438, \u0438 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043a\u0430\u0436\u0434\u0430\u044f \u0441\u043b\u0443\u0436\u0431\u0430 \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u043d\u0435\u043c\u0443, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u0432\u043e\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e.<\/p>\n<p>application.properties<\/p>\n<pre><code class=\"java\">spring.application.name=config-server spring.profiles.active=native server.port=8071 spring.cloud.config.server.native.search-locations=<\/code><\/pre>\n<ul>\n<li>\n<p>spring.application.name &#8212; \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043d\u0430\u0448\u0435\u0439 \u0441\u043b\u0443\u0436\u0431\u044b  <\/p>\n<\/li>\n<li>\n<p>spring.profiles.active &#8212; \u0434\u0430\u043d\u043d\u043e\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043d\u0430\u0448\u0430 \u0441\u043b\u0443\u0436\u0431\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0434\u043b\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<li>\n<p>spring.cloud.config.server.native.search-locations &#8212; \u0437\u0434\u0435\u0441\u044c \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0443\u0442\u044c \u0432 \u043d\u0430\u0448\u0435\u043c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435, \u0433\u0434\u0435 \u0431\u0443\u0434\u0443\u0442 \u043b\u0435\u0436\u0430\u0442\u044c properties \u0444\u0430\u0439\u043b\u044b \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u043b\u0443\u0436\u0431\u044b  <\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u0430 \u0434\u0430\u043d\u043d\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u043b\u0443\u0436\u0431\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0439 \u0437\u0430\u043a\u043e\u043d\u0447\u0435\u043d\u043e.<\/p>\n<h4>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0441\u043b\u0443\u0436\u0431 (Eureka server)<\/h4>\n<p>\u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0441\u043b\u0443\u0436\u0431. \u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 pom.xml:<\/p>\n<pre><code class=\"xml\">   &lt;dependency&gt;        &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt;        &lt;artifactId&gt;spring-cloud-starter-netflix-eureka-server&lt;\/artifactId&gt;    &lt;\/dependency&gt;    &lt;dependency&gt;        &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt;        &lt;artifactId&gt;spring-cloud-starter-config&lt;\/artifactId&gt;    &lt;\/dependency&gt;    &lt;dependency&gt;        &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;        &lt;artifactId&gt;spring-boot-devtools&lt;\/artifactId&gt;        &lt;scope&gt;runtime&lt;\/scope&gt;        &lt;optional&gt;true&lt;\/optional&gt;    &lt;\/dependency&gt;    &lt;dependency&gt;        &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;        &lt;artifactId&gt;spring-boot-configuration-processor&lt;\/artifactId&gt;        &lt;optional&gt;true&lt;\/optional&gt;    &lt;\/dependency&gt;    &lt;dependency&gt;        &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;        &lt;artifactId&gt;spring-boot-starter-test&lt;\/artifactId&gt;        &lt;scope&gt;test&lt;\/scope&gt;    &lt;\/dependency&gt; <\/code><\/pre>\n<p>EurekaServerApplication \u043a\u043b\u0430\u0441\u0441 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:  <\/p>\n<p>EurekaServerApplication.java  <\/p>\n<pre><code class=\"java\">@SpringBootApplication @EnableEurekaServer @RefreshScope public class EurekaServerApplication {     public static void main(String[] args) {        SpringApplication.run(EurekaServerApplication.class, args);    }  } <\/code><\/pre>\n<p>application.properties<\/p>\n<pre><code class=\"java\">spring.application.name=eserver spring.profiles.active=dev spring.config.import=optional:configserver:http:\/\/localhost:8071<\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0441\u043b\u0443\u0436\u0431\u044b, \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0438 \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0441\u043b\u0443\u0436\u0431\u044b \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435:<\/p>\n<p><a href=\"http:\/\/localhost:8071\/eserver\/dev\" rel=\"noopener noreferrer nofollow\"><u>http:\/\/localhost:8071\/eserver\/dev<\/u><\/a><\/p>\n<p>\u0412 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b eserver-dev.properties \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u0441\u043b\u0443\u0436\u0431\u044b \u0438 \u0435\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435\u043c \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043d\u0435\u0433\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430:<\/p>\n<pre><code class=\"java\">eureka.client.register-with-eureka=false eureka.client.fetch-registry=false eureka.instance.hostname=localhost server.port=8070<\/code><\/pre>\n<ul>\n<li>\n<p>eureka.client.register-with-eureka \u2014 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442, \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043b\u0438 \u0441\u0435\u0440\u0432\u0438\u0441 \u043a\u0430\u043a \u043a\u043b\u0438\u0435\u043d\u0442 \u043d\u0430 Eureka Server.  <\/p>\n<\/li>\n<li>\n<p>eureka.client.fetch-registry \u2014 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0438\u043b\u0438 \u043d\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u0445.  <\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 API &#8212; \u0448\u043b\u044e\u0437\u0430.<\/p>\n<h4>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f API-\u0448\u043b\u044e\u0437\u0430 (Spring Cloud Gateway)<\/h4>\n<p>\u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 pom.xml:<\/p>\n<pre><code class=\"xml\">&lt;dependency&gt;    &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt;    &lt;artifactId&gt;spring-cloud-starter-gateway&lt;\/artifactId&gt; &lt;\/dependency&gt; &lt;dependency&gt;    &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt;    &lt;artifactId&gt;spring-cloud-starter-netflix-eureka-client&lt;\/artifactId&gt; &lt;\/dependency&gt; &lt;dependency&gt;    &lt;groupId&gt;org.springframework.cloud&lt;\/groupId&gt;    &lt;artifactId&gt;spring-cloud-starter-config&lt;\/artifactId&gt;    &lt;version&gt;4.0.1&lt;\/version&gt; &lt;\/dependency&gt; &lt;dependency&gt;    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;    &lt;artifactId&gt;spring-boot-starter-oauth2-client&lt;\/artifactId&gt; &lt;\/dependency&gt; &lt;dependency&gt;    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;    &lt;artifactId&gt;spring-boot-devtools&lt;\/artifactId&gt;    &lt;scope&gt;runtime&lt;\/scope&gt;    &lt;optional&gt;true&lt;\/optional&gt; &lt;\/dependency&gt; &lt;dependency&gt;    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;    &lt;artifactId&gt;spring-boot-configuration-processor&lt;\/artifactId&gt;    &lt;optional&gt;true&lt;\/optional&gt; &lt;\/dependency&gt; &lt;dependency&gt;    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;    &lt;artifactId&gt;spring-boot-starter-test&lt;\/artifactId&gt;    &lt;scope&gt;test&lt;\/scope&gt; &lt;\/dependency&gt; <\/code><\/pre>\n<p>application.properties<\/p>\n<pre><code class=\"java\">spring.application.name=gateway spring.profiles.active=dev spring.config.import=optional:configserver:http:\/\/localhost:8071<\/code><\/pre>\n<p>gateway-dev.properties  <\/p>\n<pre><code class=\"java\">eureka.client.service-url.defaultZone=http:\/\/localhost:8070\/eureka eureka.client.register-with-eureka=true eureka.instance.prefer-ip-address=true eureka.client.fetch-registry=true eureka.instance.hostname=localhost spring.cloud.gateway.discovery.locator.enabled=true spring.cloud.gateway.discovery.locator.lower-case-service-id=true server.port=8081 spring.cloud.gateway.default-filters=TokenRelay= spring.security.oauth2.client.provider.keycloak.issuer-uri=http:\/\/localhost:8080\/realms\/habr spring.security.oauth2.client.registration.keycloak.provider=keycloak spring.security.oauth2.client.registration.keycloak.client-id=client-id spring.security.oauth2.client.registration.keycloak.client-secret=client-secret spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code spring.security.oauth2.client.registration.keycloak.scope=openid <\/code><\/pre>\n<ul>\n<li>\n<p>eureka.client.register-with-eureka &#8212; \u0441\u043b\u0443\u0436\u0431\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 Eureka server<\/p>\n<\/li>\n<li>\n<p>eureka.client.service-url.defaultZone &#8212; \u0441\u0441\u044b\u043b\u043a\u0430, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u0441\u043b\u0443\u0436\u0431\u0435 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u0438\u044f  <\/p>\n<\/li>\n<li>\n<p>spring.cloud.gateway.discovery.locator.enabled &#8212; \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u0432 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0441\u043b\u0443\u0436\u0431, \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0432 Eureka  <\/p>\n<\/li>\n<li>\n<p>spring.cloud.gateway.default-filters=TokenRelay= &#8212; \u043f\u0435\u0440\u0435\u0441\u044b\u043b\u043a\u0430 \u0442\u043e\u043a\u0435\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u043c\u0435\u0436\u0434\u0443 \u0441\u043b\u0443\u0436\u0431\u0430\u043c\u0438  <\/p>\n<\/li>\n<li>\n<p>spring.security.oauth2.client.provider.keycloak.issuer-uri &#8212; \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0438 \u0432\u044b\u0434\u0430\u0435\u0442 \u0442\u043e\u043a\u0435\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0430  <\/p>\n<\/li>\n<li>\n<p>spring.security.oauth2.client.registration.keycloak.client-id &#8212; \u0437\u0434\u0435\u0441\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c id \u043a\u043b\u0438\u0435\u043d\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u0432 KeyCloak  <\/p>\n<\/li>\n<li>\n<p>spring.security.oauth2.client.registration.keycloak.client-secret &#8212; Client Secret \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0430  <\/p>\n<\/li>\n<\/ul>\n<p>\u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043f\u0440\u043e \u0432\u0441\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435:<\/p>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/701912\/\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/habr.com\/ru\/articles\/701912\/<\/u><\/a><\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f Security Config \u0434\u043b\u044f API-\u0448\u043b\u044e\u0437\u0430, \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u044e\u0449\u0438\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c:<\/p>\n<p>SecurityConfig.java<\/p>\n<pre><code class=\"java\">@Configuration @EnableWebFluxSecurity public class SecurityConfig {    @Autowired    private ReactiveClientRegistrationRepository registrationRepository;    @Bean    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {        http                .authorizeExchange()                .anyExchange()                .authenticated()                .and()                .oauth2Login()                .and()                .logout()                .logoutSuccessHandler(oidcLogoutSuccessHandler())        ;         return http.build();    }    @Bean    public ServerLogoutSuccessHandler oidcLogoutSuccessHandler() {        OidcClientInitiatedServerLogoutSuccessHandler successHandler = new<\/code><\/pre>\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-347456","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/347456","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=347456"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/347456\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=347456"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=347456"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=347456"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}