{"id":379296,"date":"2024-06-20T21:00:17","date_gmt":"2024-06-20T21:00:17","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=379296"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=379296","title":{"rendered":"<span>\u041a\u0430\u043a \u0437\u0430\u0449\u0438\u0442\u0438\u0442\u044c \u0432\u0435\u0431 \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0448\u043b\u044e\u0437\u0430 OpenIG<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0435 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0432\u0435\u0431 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u2014 \u043e\u0434\u043d\u0430 \u0438\u0437 \u0432\u0430\u0436\u043d\u044b\u0445 \u0447\u0430\u0441\u0442\u0435\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u0415\u0441\u043b\u0438 \u0435\u0441\u043b\u0438 \u0432 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432, \u0442\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043d\u0438\u0445 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u043b\u0436\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0437\u0430\u0449\u0438\u0449\u0435\u043d. \u0415\u0441\u043b\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u043e\u043b\u0438\u0442\u0438\u043a \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0441\u0435\u0440\u0432\u0438\u0441\u0435, \u0442\u043e \u0437\u0430\u0442\u0440\u0430\u0442\u044b \u043d\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0442\u0430\u043a\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0430\u044e\u0442. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0435 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u0438 \u043e\u0448\u0438\u0431\u043e\u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u041f\u043e\u044d\u0442\u043e\u043c\u0443, \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u043c. \u0414\u0430\u043b\u0435\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u0437\u0430\u0449\u0438\u0442\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 API-\u0448\u043b\u044e\u0437\u0430 \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c <a href=\"https:\/\/github.com\/OpenIdentityPlatform\/OpenIG\" rel=\"noopener noreferrer nofollow\">OpenIG<\/a>, \u0430 \u0442\u0430\u043a \u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0441 JWT \u0442\u043e\u043a\u0435\u043d\u043e\u043c<\/p>\n<p>\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0434\u043b\u044f \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/github.com\/maximthomas\/openig-protect-ws\/\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/maximthomas\/openig-protect-ws\/<\/a><\/p>\n<h2>\u0414\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441<\/h2>\n<p>\u041f\u0443\u0441\u0442\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0441\u0435\u0440\u0432\u0438\u0441, \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0439 \u043d\u0430 Spring Boot, \u0441 \u0434\u0432\u0443\u043c\u044f endpoint <code>\/<\/code> \u2014 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0439 \u0438 <code>\/secure<\/code> \u2014 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0439, \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u043e\u0433\u0443\u0442 \u0438\u043c\u0435\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438.<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0441\u0435\u0440\u0432\u0438\u0441\u0430:<\/p>\n<pre><code class=\"java\">package org.openidentityplatform.sampleservice;  import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;  import javax.servlet.http.HttpServletRequest; import java.util.Collections; import java.util.Map;  @SpringBootApplication public class SampleServiceApplication {     public static void main(String[] args) {         SpringApplication.run(SampleServiceApplication.class, args);     }      @RestController     public class IndexController {         @RequestMapping(\"\/\")         public Map&lt;String, String> index() {             return Collections.singletonMap(\"hello\", \"world\");         }          @RequestMapping(\"\/secure\")         public Map&lt;String, String> secure(HttpServletRequest request) {             return Collections.singletonMap(\"hello\", request.getHeader(\"X-Auth-Username\"));         }     } } <\/code><\/pre>\n<h3>\u0417\u0430\u043f\u0443\u0441\u043a \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430<\/h3>\n<p>\u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 <code>docker-compose.yaml<\/code> \u0444\u0430\u0439\u043b \u0438 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 \u043d\u0435\u0433\u043e \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441:<\/p>\n<pre><code class=\"yaml\">services:   sample-service: image: maximthomas\/sample-service     restart: always <\/code><\/pre>\n<p>\u0414\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0431\u0435\u0437 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0438\u0437 \u0432\u043d\u0435\u0448\u043d\u0435\u0439 \u0441\u0435\u0442\u0438. \u0414\u0430\u043b\u0435\u0435 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043c Docker \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0441\u043e \u0448\u043b\u044e\u0437\u043e\u043c OpenIG, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u0430\u043b\u0438\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0438 \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0434\u043e \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430<\/p>\n<h2>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 OpenIG<\/h2>\n<p>\u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439 OpenIG &#8212; <code>openig-config<\/code> \u0432 \u044d\u0442\u043e\u0439 \u043f\u0430\u043f\u043a\u0435 \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0435\u0449\u0435 \u043e\u0434\u043d\u0443 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>config<\/code> . \u0412 \u043f\u0430\u043f\u043a\u0435 <code>openig-config\/config<\/code> \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 2 \u0444\u0430\u0439\u043b\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438:<\/p>\n<p><code>admin.json<\/code><\/p>\n<pre><code class=\"json\">{   \"prefix\" : \"openig\",   \"mode\": \"PRODUCTION\" } <\/code><\/pre>\n<p>\u0438 <code>config.json<\/code><\/p>\n<pre><code class=\"json\">{   \"heap\": [   ],   \"handler\": {     \"type\": \"Chain\",     \"config\": {       \"filters\": [        ],       \"handler\": {         \"type\": \"Router\",         \"name\": \"_router\",         \"capture\": \"all\"       }     }   } } <\/code><\/pre>\n<p>\u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0441\u0435\u0440\u0432\u0438\u0441 OpenIG \u0432 \u0444\u0430\u0439\u043b <code>docker-compose.yaml<\/code> \u0421\u043c\u043e\u043d\u0442\u0438\u0440\u0443\u0439\u0442\u0435 \u043f\u0430\u043f\u043a\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 <code>openig-config<\/code> \u043a Docker \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0443 OpenIG. \u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0439 \u043e\u043f\u0446\u0438\u0438 \u00a0<code>-Dopenig.base<\/code> \u0434\u043e\u043b\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430 \u0441\u043c\u043e\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e.<\/p>\n<pre><code class=\"yaml\">services:   sample-service:     build:       context: .\/sample-service     restart: always    #OpenIG service   openig:     image: openidentityplatform\/openig:latest     restart: always     volumes:       - .\/openig-config:\/usr\/local\/openig-config     environment:       #OpenIG options       CATALINA_OPTS: -Dopenig.base=\/usr\/local\/openig-config     ports:       - \"8080:8080\" <\/code><\/pre>\n<h3>\u041f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a \u0441\u0435\u0440\u0432\u0438\u0441\u0443<\/h3>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 OpenIG \u043a \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u043c\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u0443. \u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u0443\u044e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 <code>-Dendpoint.api<\/code>. \u041e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430 URL \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0438 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u0432 OpenIG. \u0412\u044b, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0435 \u0442\u043e\u0447\u043a\u0438 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0435, \u043d\u043e, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0445 \u043e\u043f\u0446\u0438\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u043c\u044b\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u043c.<\/p>\n<p><code>docker-compose.yaml<\/code>:<\/p>\n<pre><code class=\"yaml\">...   openig:     image: openidentityplatform\/openig:latest     restart: always     volumes:       - .\/openig-config:\/usr\/local\/openig-config     environment:       #OpenIG options       CATALINA_OPTS: -Dopenig.base=\/usr\/local\/openig-config -Dendpoint.api=http:\/\/sample-service:8080\/     ports:       - \"8080:808 <\/code><\/pre>\n<p>\u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043c\u0430\u0440\u0448\u0440\u0443\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u0441\u0435\u0440\u0432\u0438\u0441. \u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u043f\u0430\u043f\u043a\u0443 <code>routes<\/code> \u0441 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430\u043c\u0438 \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438  <code>openig-config\/config\/<\/code>. \u0418 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 \u043d\u0435\u0435 \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430<\/p>\n<p><code>10-api.json<\/code><\/p>\n<pre><code class=\"json\">{   \"name\": \"${matches(request.uri.path, '^\/')}\",   \"condition\": \"${matches(request.uri.path, '^\/')}\",   \"monitor\": true,   \"timer\": true,   \"handler\": {     \"type\": \"Chain\",     \"config\": {       \"filters\": [        ],       \"handler\": \"EndpointHandler\"     }   },   \"heap\": [     {       \"name\": \"EndpointHandler\",       \"type\": \"DispatchHandler\",       \"config\": {         \"bindings\": [           {             \"handler\": \"ClientHandler\",             \"capture\": \"all\",             \"baseURI\": \"${system['endpoint.api']}\"           }         ]       }     }   ] } <\/code><\/pre>\n<p>\u0422\u0430\u043a\u043e\u0439 \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u0443\u0435\u0442 \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u0438\u0437 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0442\u0432\u0435\u0442\u044b \u0431\u0435\u0437 \u043a\u0430\u043a\u0438\u0445 \u043b\u0438\u0431\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a.<\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c 404 \u0441\u0442\u0430\u0442\u0443\u0441 \u043d\u0430 \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b<\/p>\n<p><code>99-default.json<\/code>:<\/p>\n<pre><code class=\"json\">{   \"name\": \"99-default\",   \"handler\": {     \"type\": \"StaticResponseHandler\",     \"config\": {       \"status\": 404,       \"reason\": \"Not Found\",       \"headers\": {         \"Content-Type\": [ \"application\/json\" ]       },       \"entity\": \"{ \\\"error\\\": \\\"Not Found\\\"}\"     }   },   \"audit\": \"\/404\" } <\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0434\u0435\u043c\u043e \u0441\u0435\u0440\u0432\u0438\u0441 \u0438 OpenIG \u0432 Docker \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u0445:<\/p>\n<pre><code class=\"bash\">docker-compose up <\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c<\/p>\n<pre><code class=\"bash\">curl -v -X GET http:\/\/localhost:8080\/ Note: Unnecessary use of -X or --request, GET is already inferred. *   Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8080 (#0) > GET \/ HTTP\/1.1 > Host: localhost:8080 > User-Agent: curl\/7.58.0 > Accept: *\/* > &lt; HTTP\/1.1 200 OK &lt; Server: Apache-Coyote\/1.1 &lt; Date: Wed, 24 Apr 2019 15:06:17 GMT &lt; Content-Type: application\/json;charset=UTF-8 &lt; Transfer-Encoding: chunked &lt; * Connection #0 to host localhost left intact {\"hello\":\"world\"}  curl -v -X GET http:\/\/localhost:8080\/secure Note: Unnecessary use of -X or --request, GET is already inferred. *   Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8080 (#0) > GET \/secure HTTP\/1.1 > Host: localhost:8080 > User-Agent: curl\/7.58.0 > Accept: *\/* > &lt; HTTP\/1.1 200 OK &lt; Server: Apache-Coyote\/1.1 &lt; Date: Wed, 24 Apr 2019 15:04:49 GMT &lt; Content-Type: application\/json;charset=UTF-8 &lt; Transfer-Encoding: chunked &lt; * Connection #0 to host localhost left intact {\"name\":null} <\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430<\/p>\n<h2>\u0417\u0430\u0449\u0438\u0442\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430<\/h2>\n<p>\u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0432\u043e\u0437\u044c\u043c\u0435\u043c <a href=\"https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/REST_Security_Cheat_Sheet.md\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438 OWASP<\/a> \u043f\u043e \u0437\u0430\u0449\u0438\u0442\u0435 REST \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432.<\/p>\n<h3>\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 HTTP<\/h3>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043a \u0441\u0435\u0440\u0432\u0438\u0441\u0443 \u0442\u043e\u043b\u044c\u043a\u043e GET \u0438 POST \u0437\u0430\u043f\u0440\u043e\u0441\u044b. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043c\u0430\u0440\u0448\u0440\u0443\u0442 <code>10-api.json<\/code> \u0444\u0438\u043b\u044c\u0442\u0440 <code>SwitchFilter<\/code><\/p>\n<pre><code class=\"json\">{   \"name\": \"${matches(request.uri.path, '^\/')}\",   \"condition\": \"${matches(request.uri.path, '^\/')}\",   \"monitor\": true,   \"timer\": true,   \"handler\": {     \"type\": \"Chain\",     \"config\": {       \"filters\": [         {           \"type\": \"SwitchFilter\",           \"config\": {             \"onRequest\": [               {                 \"condition\": \"${request.method != 'POST' and request.method != 'GET'}\",                 \"handler\": {                   \"type\": \"StaticResponseHandler\",                   \"config\": {                     \"status\": 405,                     \"reason\": \"Method not allowed\",                     \"headers\": {                       \"Content-Type\": [                         \"application\/json\"                       ]                     },                     \"entity\": \"{ \\\"error\\\": \\\"Method not allowed\\\"}\"                   }                 }               }             ]           }         }       ],        \"handler\": \"EndpointHandler\"     }   },   \"heap\": [     {       \"name\": \"EndpointHandler\",       \"type\": \"DispatchHandler\",       \"config\": {         \"bindings\": [           {             \"handler\": \"ClientHandler\",             \"capture\": \"all\",             \"baseURI\": \"${system['endpoint.api']}\"           }         ]       }     }   ] } <\/code><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0435 GET \u0438 \u043d\u0435 POST \u0448\u043b\u044e\u0437 \u0432\u0435\u0440\u043d\u0435\u0442 \u0441\u0442\u0430\u0442\u0443\u0441 405:<\/p>\n<pre><code class=\"bash\">$ curl -v -X PUT http:\/\/localhost:8080\/ *   Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8080 (#0) > PUT \/ HTTP\/1.1 > Host: localhost:8080 > User-Agent: curl\/7.58.0 > Accept: *\/* > &lt; HTTP\/1.1 405 Method Not Allowed &lt; Server: Apache-Coyote\/1.1 &lt; Content-Type: application\/json &lt; Content-Length: 32 &lt; Date: Wed, 24 Apr 2019 15:13:04 GMT &lt; * Connection #0 to host localhost left intact { \"error\": \"Method not allowed\"}  <\/code><\/pre>\n<h3>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 Content-Type<\/h3>\n<p>\u041f\u0443\u0441\u0442\u044c \u0434\u043b\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b <code>POST<\/code> \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0441 <code>Content-Type: application\/json<\/code> . \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 <code>SwitchFilter<\/code> \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 <code>Content-Type<\/code><\/p>\n<p><code>10-api.json<\/code>:<\/p>\n<pre><code class=\"json\">...       {           \"type\": \"SwitchFilter\",           \"config\": {             \"onRequest\": [               {                 \"condition\": \"${request.method != 'POST' and request.method != 'GET'}\",                 \"handler\": {                   \"type\": \"StaticResponseHandler\",                   \"config\": {                     \"status\": 405,                     \"reason\": \"Method not allowed\",                     \"headers\": {                       \"Content-Type\": [                         \"application\/json\"                       ]                     },                     \"entity\": \"{ \\\"error\\\": \\\"Method not allowed\\\"}\"                   }                 }               },               {                 \"condition\": \"${request.method == 'POST' and request.headers['Content-Type'][0].split(';')[0] != 'application\/json'}\",                 \"handler\": {                   \"type\": \"StaticResponseHandler\",                   \"config\": {                     \"status\": 415,                     \"reason\": \"Unsupported Media Type\",                     \"headers\": {                       \"Content-Type\": [ \"application\/json\" ]                     },                     \"entity\": \"{ \\\"error\\\": \\\"Unsupported Media Type\\\"}\"                   }                 }               }             ]           }         } ...         <\/code><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u0447\u0442\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0434\u043b\u044f <code>Content-Type: application\/xml<\/code><\/p>\n<pre><code class=\"bash\">$ curl -v -X POST -H 'Content-Type: application\/xml' http:\/\/localhost:8080\/ *   Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8080 (#0) > POST \/ HTTP\/1.1 > Host: localhost:8080 > User-Agent: curl\/7.58.0 > Accept: *\/* > Content-Type: application\/xml > &lt; HTTP\/1.1 415 Unsupported Media Type &lt; Server: Apache-Coyote\/1.1 &lt; Content-Type: application\/json &lt; Content-Length: 36 &lt; Date: Wed, 24 Apr 2019 15:21:04 GMT &lt; * Connection #0 to host localhost left intact { \"error\": \"Unsupported Media Type\"} <\/code><\/pre>\n<h3>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u044f \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 Accept \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 Content-Type \u043e\u0442\u0432\u0435\u0442\u0430<\/h3>\n<p>\u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 <code>Content-Type<\/code> \u043e\u0442\u0432\u0435\u0442\u0430 \u0434\u043e\u043b\u0436\u043d\u043e \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0442\u044c \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 <code>Accept<\/code> \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 <code>config<\/code> \u0444\u0438\u043b\u044c\u0442\u0440\u0430 <code>SwitchFilter<\/code> \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430:<\/p>\n<p><code>10-api.json<\/code>:<\/p>\n<pre><code class=\"json\">...           \"onResponse\" : [               {                 \"condition\" : \"${response.headers['Content-Type'][0].split(';')[0] != request.headers['Accept'][0].split(';')[0] }\",                 \"handler\": {                   \"type\": \"StaticResponseHandler\",                   \"config\": {                     \"status\": 406,                     \"reason\": \"Not Acceptable\",                     \"headers\": {                       \"Content-Type\": [ \"application\/json\" ]                     },                     \"entity\": \"{ \\\"error\\\": \\\"Not Acceptable\\\"}\"                   }                 }               }             ] ...              <\/code><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u0441 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c <code>Accept: application\/xml<\/code><\/p>\n<pre><code class=\"json\">curl -v -X POST -H 'Content-Type: application\/json' -H 'Accept: application\/xml'  http:\/\/localhost:8080\/ *   Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8080 (#0) > POST \/ HTTP\/1.1 > Host: localhost:8080 > User-Agent: curl\/7.58.0 > Content-Type: application\/json > Accept: application\/xml > &lt; HTTP\/1.1 406 Not Acceptable &lt; Server: Apache-Coyote\/1.1 &lt; Content-Type: application\/json &lt; Content-Length: 28 &lt; Date: Wed, 24 Apr 2019 15:28:54 GMT &lt; * Connection #0 to host localhost left intact { \"error\": \"Not Acceptable\"} <\/code><\/pre>\n<h3>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 X-Frame-Options \u0438 X-Content-Type-Options<\/h3>\n<p>OpenIG \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 <code>X-Frame-Options: deny<\/code> \u0438 <code>X-Content-Type-Options: nosniff<\/code>, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0442\u0438\u0442\u044c MIME sniffing, XSS \u0438 drag&#8217;n drop clickjacking \u0430\u0442\u0430\u043a\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 <code>HeaderFilter<\/code> \u0432 \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 \u043f\u043e\u0441\u043b\u0435 <code>SwitchFilter<\/code>:<\/p>\n<p><code>10-api.json<\/code>:<\/p>\n<pre><code class=\"json\">{   \"type\": \"HeaderFilter\",   \"comment\": \"Add security headers to response\",   \"config\": {     \"messageType\": \"response\",     \"add\": {       \"X-Frame-Options\": [ \"deny\" ],       \"X-Content-Type-Options\": [ \"nosniff\" ]     }   } } <\/code><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u043e\u0442\u0432\u0435\u0442\u0430:<\/p>\n<pre><code class=\"bash\">curl -v -X POST -H 'Content-Type: application\/json' -H 'Accept: application\/json'  http:\/\/localhost:8080\/ *   Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8080 (#0) > POST \/ HTTP\/1.1 > Host: localhost:8080 > User-Agent: curl\/7.58.0 > Content-Type: application\/json > Accept: application\/json > &lt; HTTP\/1.1 200 OK &lt; Server: Apache-Coyote\/1.1 &lt; Date: Wed, 24 Apr 2019 15:31:31 GMT &lt; X-Content-Type-Options: nosniff &lt; X-Frame-Options: deny &lt; Content-Type: application\/json;charset=UTF-8 &lt; Transfer-Encoding: chunked &lt; * Connection #0 to host localhost left intact {\"hello\":\"world\"} <\/code><\/pre>\n<h2>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438<\/h2>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0449\u0438\u0442\u0438\u0442\u044c \u0441\u0435\u0440\u0432\u0438\u0441 \u043e\u0442 \u043d\u0435 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430, \u043d\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043d\u0430 OpenIG. \u0418 \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d, \u043e\u0431\u043e\u0433\u0430\u0442\u0438\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043e\u0431 \u0443\u0447\u0435\u0442\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u0435\u0440\u0432\u0438\u0441 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439\u00a0<a href=\"https:\/\/en.wikipedia.org\/wiki\/JSON_Web_Token\" rel=\"noopener noreferrer nofollow\">JSON Web Token<\/a>\u00a0(JWT) \u0438 \u0448\u043b\u044e\u0437 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c JWT \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0441\u0435\u0440\u0432\u0438\u0441\u0443. \u0412 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 OpenIG \u043b\u0435\u0436\u0438\u0442 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0438 OpenIG \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043f\u043e\u0434\u043f\u0438\u0441\u044c JWT \u0441 \u044d\u0442\u0438\u043c \u043a\u043b\u044e\u0447\u043e\u043c, \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0443\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u0438\u0442\u044c\u0441\u044f \u0432 \u043f\u043e\u0434\u043b\u0438\u043d\u043d\u043e\u0441\u0442\u0438 JWT.<\/p>\n<p>\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0439\u0442\u0435 \u043f\u0430\u0440\u0443 \u043a\u043b\u044e\u0447\u0435\u0439<\/p>\n<p>\u041f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439<\/p>\n<pre><code class=\"bash\">openssl genrsa -out private_key.pem 4096 <\/code><\/pre>\n<p>\u0418 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439<\/p>\n<pre><code class=\"bash\">openssl rsa -pubout -in private_key.pem -out public_key.pem <\/code><\/pre>\n<p>\u0423\u0436\u0435 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u044e\u0447\u0438 \u043b\u0435\u0436\u0430\u0442 \u0432 GitHub \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 <a href=\"https:\/\/github.com\/maximthomas\/openig-protect-ws\/tree\/master\/openig-config\/keys\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/maximthomas\/openig-protect-ws\/tree\/master\/openig-config\/keys<\/a><\/p>\n<p>\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0439\u0442\u0435 JWT \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0441\u0430\u0439\u0442\u0430 <a href=\"https:\/\/jwt.io\/\" rel=\"noopener noreferrer nofollow\">https:\/\/jwt.io<\/a> \u0438 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430 <code>private_key.pem<\/code><\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 JWT:<\/p>\n<pre><code class=\"bash\">eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzYW1wbGUtc2VydmljZSIsInN1YiI6IjEyMzQ1Njc4OTAiLCJuYW1lIjoiSm9obiBEb2UiLCJyb2xlIjoibWFuYWdlciIsImlhdCI6MTUxNjIzOTAyMiwiZXhwIjoxNzI2MjM5MDIyfQ.bhzhwj2cY1iYbpx7Mzbukfi1jOCvWP-Pdd9dm3hf7lZDDuokNVDUXU3jvHial4QN-bOTSNCUKVy907hokcVeQaFwbiYoZs485Kr230Z0y9MU6zbDe8yQp68-71TDgJGIZ78YYOKvJTrzCWgWgE_Py1DskG_ViSxfGFlETpFQa056Rk2bty-9iuc_Cx5_Wr6RCcJTG6WYRrBtdWGIFxljEjxSAcJYmGPPA8dHHORDOnmka2OAjWURnsqbz50aI_SrWpnqp4i2eXVA1b5QD5rlsgc_QAqJptghrijBlRPhasTk1N-kXE8Ozboa0FwGfIRr7gNiG-3if7INZe2R5NUCmjlAlywcSfOunWuSzY8tLGTHV2swnQPP8lBXwVJcS5nJMqBNIbcLcFWHk3ryvvtf-LYty_jAY8v1zDe9-DwFPWI0rry8fmiZj7yhAnvX5EHZHvSQtp_zyPpVWvOXFPwasI0jdKoxhWvyJpbmw-D95J5CgJAMfkrWPDQKVt3ipebwnMJStA3xAPPyl28mTBYhJrT6gzIOS3DseoVKK4adn34ZrQi2Hm-wyUtbdulopK739MKM73NYgoFXSJeVUqcy4iw3-In5XmOhdRnUL50TSiaNBbkys8iK7r00HD3kI3CH0GfaPdrcgRgaFXKmVDhX-tEaPJYcuEUTHfQAxWwMdiw <\/code><\/pre>\n<h3>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 JWT \u0432 OpenIG<\/h3>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0442\u043e\u0447\u043a\u0438 <code>\/secured<\/code> \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d <code>SwitchFilter<\/code> , \u043a\u043e\u0442\u043e\u0440\u044b\u0439, \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0432\u044b\u0437\u043e\u0432\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<code>Chain<\/code> \u0435\u0441\u043b\u0438 \u0446\u0435\u043b\u0435\u0432\u0430\u044f \u043a\u043e\u043d\u0435\u0447\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <code>secured<\/code> . \u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a <code>Chain<\/code> \u0444\u0438\u043b\u044c\u0442\u0440 <code>ScriptableFilter<\/code> , \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0441\u0442\u044c JWT \u0438 \u043e\u0431\u043e\u0433\u0430\u0449\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c \u0443\u0447\u0435\u0442\u043d\u043e\u0439 \u0437\u0430\u043f\u0438\u0441\u0438 \u0438\u0437 JWT.<\/p>\n<p><code>10-api.json<\/code>:<\/p>\n<pre><code class=\"json\">...         {           \"type\": \"SwitchFilter\",           \"config\": {             \"onRequest\": [               {                 \"condition\": \"${matches(request.uri.path, '^\/secure')}\",                 \"handler\": {                   \"type\": \"Chain\",                   \"config\": {                     \"filters\": [                       {                         \"type\": \"ScriptableFilter\",                         \"config\": {                           \"type\": \"application\/x-groovy\",                           \"file\": \"jwt.groovy\",                           \"args\": {                             \"iss\": {                               \"sample-service\": \"${read('\/usr\/local\/openig-config\/keys\/public_key.pem')}\"                             }                           }                         }                       }                     ],                     \"handler\": \"EndpointHandler\"                   }                 }               }             ]           }         } ...         <\/code><\/pre>\n<p>\u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0444\u0430\u0439\u043b <code>jwt.groovy<\/code> \u0432 \u043f\u0430\u043f\u043a\u0443 \u00a0<code>\/openig-config\/scripts\/groovy\/<\/code> . \u0421\u043a\u0440\u0438\u043f\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043f\u043e\u0434\u043f\u0438\u0441\u044c, \u0438, \u0435\u0441\u043b\u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u044c \u0432\u0435\u0440\u043d\u0430, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0441\u0440\u043e\u043a \u0438\u0441\u0442\u0435\u0447\u0435\u043d\u0438\u044f JWT.  \u0415\u0441\u043b\u0438 JWT \u0432\u0430\u043b\u0438\u0434\u0435\u043d, \u0441\u043a\u0440\u0438\u043f\u0442 \u043e\u0431\u043e\u0433\u0430\u0449\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c <code>X-Auth-Username<\/code> \u0438\u0437 \u043f\u043e\u043b\u044f <code>name<\/code> \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 JWT. \u0412 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f 401 \u0441\u0442\u0430\u0442\u0443\u0441 HTTP.<\/p>\n<p><code>jwt.groovy<\/code>:<\/p>\n<pre><code class=\"java\">import java.security.KeyFactory import org.forgerock.json.jose.builders.JwtBuilderFactory import org.forgerock.json.jose.jws.SignedJwt import org.forgerock.json.jose.jws.SigningManager import org.forgerock.http.protocol.Status import java.security.spec.X509EncodedKeySpec  \/\/extract jwt from request header def jwt = request.headers['Authorization']?.firstValue  if (jwt!=null &amp;&amp; jwt.startsWith(\"Bearer eyJ\")) {     jwt=jwt.replace(\"Bearer \", \"\")      try {         \/\/parse jwt         def sjwt=new JwtBuilderFactory().reconstruct(jwt, SignedJwt.class)          \/\/verify jwt signature         if (!sjwt.verify(new SigningManager().newRsaSigningHandler(getKey(sjwt.getClaimsSet())))) {             throw new Exception(\"invalid signature\")         }          \/\/check jwt expiration         if ((sjwt.getClaimsSet().getExpirationTime()!=null &amp;&amp; sjwt.getClaimsSet().getExpirationTime().before(new Date()))) {             throw new Exception(\"signature expired \"+sjwt.getClaimsSet().getExpirationTime())         }          \/\/add name from JWT claim to header         request.headers.put('X-Auth-Username', sjwt.getClaimsSet().getClaim(\"name\"))          return next.handle(new org.forgerock.openig.openam.StsContext(context, jwt), request)     } catch(Exception e) {         e.printStackTrace();         return getErrorResponse(Status.UNAUTHORIZED, e.getMessage())     } } else {     \/\/returns 401 status if JWT not present in request     return getErrorResponse(Status.UNAUTHORIZED, \"Not Authenticated\") }  return next.handle(context, request)  def getErrorResponse(status, message) {     def response = new Response()     response.status = status     response.headers['Content-Type'] = \"application\/json\"     response.setEntity(\"{'error' : '\" + message + \"'}\")     return response }  def getKey(claims) {     def pem=iss[claims.getIssuer()]     if (pem != null) {         def pemReplaced = pem.replaceFirst(\"(?m)(?s)^---*BEGIN.*---*\\$(.*)^---*END.*---*\\$.*\", \"\\$1\")         byte[] encoded = Base64.getMimeDecoder().decode(pemReplaced)         def kf = KeyFactory.getInstance(\"RSA\")         def pubKey = kf.generatePublic(new X509EncodedKeySpec(encoded))         println 'got pub key' + pubKey         return pubKey     }      throw new Exception('Unknown issuer') }  <\/code><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441 c \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u043c JWT:<\/p>\n<pre><code class=\"bash\">curl -v GET -H 'Content-Type: application\/json' -H 'Accept: application\/json' -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzYW1wbGUtc2VydmljZSIsInN1YiI6IjEyMzQ1Njc4OTAiLCJuYW1lIjoiSm9obiBEb2UiLCJyb2xlIjoibWFuYWdlciIsImlhdCI6MTUxNjIzOTAyMiwiZXhwIjoxNzI2MjM5MDIyfQ.bhzhwj2cY1iYbpx7Mzbukfi1jOCvWP-Pdd9dm3hf7lZDDuokNVDUXU3jvHial4QN-bOTSNCUKVy907hokcVeQaFwbiYoZs485Kr230Z0y9MU6zbDe8yQp68-71TDgJGIZ78YYOKvJTrzCWgWgE_Py1DskG_ViSxfGFlETpFQa056Rk2bty-9iuc_Cx5_Wr6RCcJTG6WYRrBtdWGIFxljEjxSAcJYmGPPA8dHHORDOnmka2OAjWURnsqbz50aI_SrWpnqp4i2eXVA1b5QD5rlsgc_QAqJptghrijBlRPhasTk1N-kXE8Ozboa0FwGfIRr7gNiG-3if7INZe2R5NUCmjlAlywcSfOunWuSzY8tLGTHV2swnQPP8lBXwVJcS5nJMqBNIbcLcFWHk3ryvvtf-LYty_jAY8v1zDe9-DwFPWI0rry8fmiZj7yhAnvX5EHZHvSQtp_zyPpVWvOXFPwasI0jdKoxhWvyJpbmw-D95J5CgJAMfkrWPDQKVt3ipebwnMJStA3xAPPyl28mTBYhJrT6gzIOS3DseoVKK4adn34ZrQi2Hm-wyUtbdulopK739MKM73NYgoFXSJeVUqcy4iw3-In5XmOhdRnUL50TSiaNBbkys8iK7r00HD3kI3CH0GfaPdrcgRgaFXKmVDhX-tEaPJYcuEUTHfQAxWwMdiw' http:\/\/localhost:8080\/secure  * Could not resolve host: GET * Closing connection 0 curl: (6) Could not resolve host: GET *   Trying 127.0.0.1:8080... * Connected to localhost (127.0.0.1) port 8080 (#1) > GET \/secure HTTP\/1.1 > Host: localhost:8080 > User-Agent: curl\/8.1.2 > Content-Type: application\/json > Accept: application\/json > Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzYW1wbGUtc2VydmljZSIsInN1YiI6IjEyMzQ1Njc4OTAiLCJuYW1lIjoiSm9obiBEb2UiLCJyb2xlIjoibWFuYWdlciIsImlhdCI6MTUxNjIzOTAyMiwiZXhwIjoxNzI2MjM5MDIyfQ.bhzhwj2cY1iYbpx7Mzbukfi1jOCvWP-Pdd9dm3hf7lZDDuokNVDUXU3jvHial4QN-bOTSNCUKVy907hokcVeQaFwbiYoZs485Kr230Z0y9MU6zbDe8yQp68-71TDgJGIZ78YYOKvJTrzCWgWgE_Py1DskG_ViSxfGFlETpFQa056Rk2bty-9iuc_Cx5_Wr6RCcJTG6WYRrBtdWGIFxljEjxSAcJYmGPPA8dHHORDOnmka2OAjWURnsqbz50aI_SrWpnqp4i2eXVA1b5QD5rlsgc_QAqJptghrijBlRPhasTk1N-kXE8Ozboa0FwGfIRr7gNiG-3if7INZe2R5NUCmjlAlywcSfOunWuSzY8tLGTHV2swnQPP8lBXwVJcS5nJMqBNIbcLcFWHk3ryvvtf-LYty_jAY8v1zDe9-DwFPWI0rry8fmiZj7yhAnvX5EHZHvSQtp_zyPpVWvOXFPwasI0jdKoxhWvyJpbmw-D95J5CgJAMfkrWPDQKVt3ipebwnMJStA3xAPPyl28mTBYhJrT6gzIOS3DseoVKK4adn34ZrQi2Hm-wyUtbdulopK739MKM73NYgoFXSJeVUqcy4iw3-In5XmOhdRnUL50TSiaNBbkys8iK7r00HD3kI3CH0GfaPdrcgRgaFXKmVDhX-tEaPJYcuEUTHfQAxWwMdiw >  &lt; HTTP\/1.1 200  &lt; Date: Wed, 19 Jun 2024 08:59:06 GMT &lt; X-Content-Type-Options: nosniff &lt; X-Frame-Options: deny &lt; Content-Type: application\/json &lt; Transfer-Encoding: chunked &lt;  * Connection #1 to host localhost left intact {\"hello\":\"John Doe\"} <\/code><\/pre>\n<p>\u0417\u0430\u043f\u0440\u043e\u0441 \u0431\u0435\u0437 JWT:<\/p>\n<pre><code class=\"bash\">curl -v GET -H 'Content-Type: application\/json' -H 'Accept: application\/json'  http:\/\/localhost:8080\/secure * Could not resolve host: GET * Closing connection 0 curl: (6) Could not resolve host: GET *   Trying 127.0.0.1:8080... * Connected to localhost (127.0.0.1) port 8080 (#1) > GET \/secure HTTP\/1.1 > Host: localhost:8080 > User-Agent: curl\/8.1.2 > Content-Type: application\/json > Accept: application\/json >  &lt; HTTP\/1.1 401  &lt; X-Content-Type-Options: nosniff &lt; X-Frame-Options: deny &lt; Content-Type: application\/json &lt; Content-Length: 31 &lt; Date: Wed, 19 Jun 2024 08:59:43 GMT &lt;  * Connection #1 to host localhost left intact {'error' : 'Not Authenticated'} <\/code><\/pre>\n<h3>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438<\/h3>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u043c OpenIG \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u043b \u0434\u043e\u0441\u0442\u0443\u043f \u0434\u043e\u0441\u0442\u0443\u043f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u0441 \u0440\u043e\u043b\u044c\u044e <code>manager<\/code> . \u0420\u043e\u043b\u044c \u0431\u0443\u0434\u0435\u043c \u0431\u0440\u0430\u0442\u044c claim JWT <code>role<\/code>. \u0415\u0441\u043b\u0438 \u0432 JWT \u0440\u043e\u043b\u044c \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0438\u043b\u0438 \u043e\u0442\u043b\u0438\u0447\u043d\u0430 \u043e\u0442 <code>manager<\/code>, \u0432\u0435\u0440\u043d\u0435\u043c HTTP \u0441\u0442\u0430\u0442\u0443\u0441 403 Forbidden.<\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u0432 \u0444\u0438\u043b\u044c\u0442\u0440 <code>ScriptableFilter<\/code> \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>allowedRole<\/code>, \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u0443\u044e \u0440\u043e\u043b\u044c \u0432 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0435, \u043d\u0435 \u043c\u0435\u043d\u044f\u044f \u0441\u043a\u0440\u0438\u043f\u0442.<\/p>\n<pre><code class=\"json\">... {   \"type\": \"ScriptableFilter\",   \"config\": {     \"type\": \"application\/x-groovy\",     \"file\": \"jwt.groovy\",     \"args\": {       \"iss\": {         \"sample-service\": \"${read('\/usr\/local\/openig-config\/keys\/public_key.pem')}\"                                     },       \"allowedRole\": \"manager\"     }   } } ... <\/code><\/pre>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432 <code>jwt.groovy<\/code> \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0440\u043e\u043b\u0438 \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441\u0440\u043e\u043a\u0430 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f:<\/p>\n<pre><code class=\"java\">\/\/check jwt expiration if ((sjwt.getClaimsSet().getExpirationTime()!=null &amp;&amp; sjwt.getClaimsSet().getExpirationTime().before(new Date()))) {     throw new Exception(\"signature expired \"+sjwt.getClaimsSet().getExpirationTime()) }  \/\/check role  if (!sjwt.getClaimsSet().keys().contains(\"role\")      || !allowedRole.equals(sjwt.getClaimsSet().getClaim(\"role\", String.class))) {      return getErrorResponse(Status.FORBIDDEN, \"Forbidden\")             } <\/code><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u0441 \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u043c JWT<\/p>\n<pre><code class=\"bash\">curl -v GET -H 'Content-Type: application\/json' -H 'Accept: application\/json' -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzYW1wbGUtc2VydmljZSIsInN1YiI6IjEyMzQ1Njc4OTAiLCJuYW1lIjoiSm9obiBEb2UiLCJyb2xlIjoibWFuYWdlciIsImlhdCI6MTUxNjIzOTAyMiwiZXhwIjoxNzI2MjM5MDIyfQ.bhzhwj2cY1iYbpx7Mzbukfi1jOCvWP-Pdd9dm3hf7lZDDuokNVDUXU3jvHial4QN-bOTSNCUKVy907hokcVeQaFwbiYoZs485Kr230Z0y9MU6zbDe8yQp68-71TDgJGIZ78YYOKvJTrzCWgWgE_Py1DskG_ViSxfGFlETpFQa056Rk2bty-9iuc_Cx5_Wr6RCcJTG6WYRrBtdWGIFxljEjxSAcJYmGPPA8dHHORDOnmka2OAjWURnsqbz50aI_SrWpnqp4i2eXVA1b5QD5rlsgc_QAqJptghrijBlRPhasTk1N-kXE8Ozboa0FwGfIRr7gNiG-3if7INZe2R5NUCmjlAlywcSfOunWuSzY8tLGTHV2swnQPP8lBXwVJcS5nJMqBNIbcLcFWHk3ryvvtf-LYty_jAY8v1zDe9-DwFPWI0rry8fmiZj7yhAnvX5EHZHvSQtp_zyPpVWvOXFPwasI0jdKoxhWvyJpbmw-D95J5CgJAMfkrWPDQKVt3ipebwnMJStA3xAPPyl28mTBYhJrT6gzIOS3DseoVKK4adn34ZrQi2Hm-wyUtbdulopK739MKM73NYgoFXSJeVUqcy4iw3-In5XmOhdRnUL50TSiaNBbkys8iK7r00HD3kI3CH0GfaPdrcgRgaFXKmVDhX-tEaPJYcuEUTHfQAxWwMdiw' http:\/\/localhost:8080\/secure * Could not resolve host: GET * Closing connection 0 curl: (6) Could not resolve host: GET *   Trying 127.0.0.1:8080... * Connected to localhost (127.0.0.1) port 8080 (#1) > GET \/secure HTTP\/1.1 > Host: localhost:8080 > User-Agent: curl\/8.1.2 > Content-Type: application\/json > Accept: application\/json > Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzYW1wbGUtc2VydmljZSIsInN1YiI6IjEyMzQ1Njc4OTAiLCJuYW1lIjoiSm9obiBEb2UiLCJyb2xlIjoibWFuYWdlciIsImlhdCI6MTUxNjIzOTAyMiwiZXhwIjoxNzI2MjM5MDIyfQ.bhzhwj2cY1iYbpx7Mzbukfi1jOCvWP-Pdd9dm3hf7lZDDuokNVDUXU3jvHial4QN-bOTSNCUKVy907hokcVeQaFwbiYoZs485Kr230Z0y9MU6zbDe8yQp68-71TDgJGIZ78YYOKvJTrzCWgWgE_Py1DskG_ViSxfGFlETpFQa056Rk2bty-9iuc_Cx5_Wr6RCcJTG6WYRrBtdWGIFxljEjxSAcJYmGPPA8dHHORDOnmka2OAjWURnsqbz50aI_SrWpnqp4i2eXVA1b5QD5rlsgc_QAqJptghrijBlRPhasTk1N-kXE8Ozboa0FwGfIRr7gNiG-3if7INZe2R5NUCmjlAlywcSfOunWuSzY8tLGTHV2swnQPP8lBXwVJcS5nJMqBNIbcLcFWHk3ryvvtf-LYty_jAY8v1zDe9-DwFPWI0rry8fmiZj7yhAnvX5EHZHvSQtp_zyPpVWvOXFPwasI0jdKoxhWvyJpbmw-D95J5CgJAMfkrWPDQKVt3ipebwnMJStA3xAPPyl28mTBYhJrT6gzIOS3DseoVKK4adn34ZrQi2Hm-wyUtbdulopK739MKM73NYgoFXSJeVUqcy4iw3-In5XmOhdRnUL50TSiaNBbkys8iK7r00HD3kI3CH0GfaPdrcgRgaFXKmVDhX-tEaPJYcuEUTHfQAxWwMdiw >  &lt; HTTP\/1.1 200  &lt; Date: Wed, 19 Jun 2024 09:05:31 GMT &lt; X-Content-Type-Options: nosniff &lt; X-Frame-Options: deny &lt; Content-Type: application\/json &lt; Transfer-Encoding: chunked &lt;  * Connection #1 to host localhost left intact {\"hello\":\"John Doe\"}%   <\/code><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u0441 JWT \u0441 \u0440\u043e\u043b\u044c\u044e, \u043e\u0442\u043b\u0438\u0447\u043d\u043e\u0439 \u043e\u0442 <code>manager<\/code><\/p>\n<pre><code class=\"bash\">curl -v -H 'Content-Type: application\/json' -H 'Accept: application\/json' -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzYW1wbGUtc2VydmljZSIsInN1YiI6IjEyMzQ1Njc4OTAiLCJuYW1lIjoiSm9obiBEb2UiLCJyb2xlIjoiYmFkIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3MjYyMzkwMjJ9.UezPgiGOcbp9CMM7hkrbvFsPmFIOnPnph5n60wF9jEWfGAIpS3dgBYvsprsVx0iZaUfhj2GTTLXhQUKrEM08n6jhUBSlwQ22LYBEHhBY57-AwtUhFZVJL8En00tc3HTGLV_El55PyvJvuLRbQ_fZB7rfp27OMPS0y2ciehz21_90TGKvUWUUGJgqDvRPchSKdO7LVa97oigGUp8vi7XiutMxopMLoms63f7FbasbIxMfgEFa48cuJTTcmk7genlPpMX8CBeBUjVriK0452uYdONvSFllqX2rdHwi7idKV-wB0qeUdNq2MDgcVqTrztxRQ8_ezoZVMnn3OLzuSABSpHKtPM3G3uVctY2X408zwOqe86BFvahT1eyBsEmrtszaIL-REy6vy-6P8JJ7iZdD720F1h3VyXj7PWNQiA-v3TumBLpRiML4Clb0SmqpB2iIvPhAz2-ob1w9BBxbvES6n95JEvFDlsv0JqOpvs-ZqQeR1pL7ML0RDR6ZR7xMWE6iVC4hlHEyX5Ufi6CBvkzVLVSnbIPyIBSBc4bzDzqdRkgt139bEdD-htrKWFmGkJKl_yvNcW_rYCkeMmb60km389XUtpiBoSc5CmKkcxrjsarvEMRh-AkIqB5R7Hz0KVKFdp1Hlzj4v1CQKK8eM4Poiq0NoO9IgHFJtgZKMosD7Qc ' http:\/\/localhost:8080\/secure *   Trying 127.0.0.1:8080... * Connected to localhost (127.0.0.1) port 8080 (#0) > GET \/secure HTTP\/1.1 > Host: localhost:8080 > User-Agent: curl\/8.1.2 > Content-Type: application\/json > Accept: application\/json > Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzYW1wbGUtc2VydmljZSIsInN1YiI6IjEyMzQ1Njc4OTAiLCJuYW1lIjoiSm9obiBEb2UiLCJyb2xlIjoiYmFkIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3MjYyMzkwMjJ9.UezPgiGOcbp9CMM7hkrbvFsPmFIOnPnph5n60wF9jEWfGAIpS3dgBYvsprsVx0iZaUfhj2GTTLXhQUKrEM08n6jhUBSlwQ22LYBEHhBY57-AwtUhFZVJL8En00tc3HTGLV_El55PyvJvuLRbQ_fZB7rfp27OMPS0y2ciehz21_90TGKvUWUUGJgqDvRPchSKdO7LVa97oigGUp8vi7XiutMxopMLoms63f7FbasbIxMfgEFa48cuJTTcmk7genlPpMX8CBeBUjVriK0452uYdONvSFllqX2rdHwi7idKV-wB0qeUdNq2MDgcVqTrztxRQ8_ezoZVMnn3OLzuSABSpHKtPM3G3uVctY2X408zwOqe86BFvahT1eyBsEmrtszaIL-REy6vy-6P8JJ7iZdD720F1h3VyXj7PWNQiA-v3TumBLpRiML4Clb0SmqpB2iIvPhAz2-ob1w9BBxbvES6n95JEvFDlsv0JqOpvs-ZqQeR1pL7ML0RDR6ZR7xMWE6iVC4hlHEyX5Ufi6CBvkzVLVSnbIPyIBSBc4bzDzqdRkgt139bEdD-htrKWFmGkJKl_yvNcW_rYCkeMmb60km389XUtpiBoSc5CmKkcxrjsarvEMRh-AkIqB5R7Hz0KVKFdp1Hlzj4v1CQKK8eM4Poiq0NoO9IgHFJtgZKMosD7Qc >  >  &lt; HTTP\/1.1 403  &lt; X-Content-Type-Options: nosniff &lt; X-Frame-Options: deny &lt; Content-Type: application\/json &lt; Content-Length: 23 &lt; Date: Wed, 19 Jun 2024 09:06:32 GMT &lt;  * Connection #0 to host localhost left intact {'error' : 'Forbidden'}%  <\/code><\/pre>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/823212\/\"> https:\/\/habr.com\/ru\/articles\/823212\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0435 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0432\u0435\u0431 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u2014 \u043e\u0434\u043d\u0430 \u0438\u0437 \u0432\u0430\u0436\u043d\u044b\u0445 \u0447\u0430\u0441\u0442\u0435\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u0415\u0441\u043b\u0438 \u0435\u0441\u043b\u0438 \u0432 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432, \u0442\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043d\u0438\u0445 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u043b\u0436\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0437\u0430\u0449\u0438\u0449\u0435\u043d. \u0415\u0441\u043b\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u043e\u043b\u0438\u0442\u0438\u043a \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0441\u0435\u0440\u0432\u0438\u0441\u0435, \u0442\u043e \u0437\u0430\u0442\u0440\u0430\u0442\u044b \u043d\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0442\u0430\u043a\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0430\u044e\u0442. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0435 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u0438 \u043e\u0448\u0438\u0431\u043e\u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u041f\u043e\u044d\u0442\u043e\u043c\u0443, \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u043c. \u0414\u0430\u043b\u0435\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u0437\u0430\u0449\u0438\u0442\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 API-\u0448\u043b\u044e\u0437\u0430 \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c <a href=\"https:\/\/github.com\/OpenIdentityPlatform\/OpenIG\" rel=\"noopener noreferrer nofollow\">OpenIG<\/a>, \u0430 \u0442\u0430\u043a \u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0441 JWT \u0442\u043e\u043a\u0435\u043d\u043e\u043c<\/p>\n<p>\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0434\u043b\u044f \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/github.com\/maximthomas\/openig-protect-ws\/\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/maximthomas\/openig-protect-ws\/<\/a><\/p>\n<h2>\u0414\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441<\/h2>\n<p>\u041f\u0443\u0441\u0442\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0441\u0435\u0440\u0432\u0438\u0441, \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0439 \u043d\u0430 Spring Boot, \u0441 \u0434\u0432\u0443\u043c\u044f endpoint <code>\/<\/code> \u2014 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0439 \u0438 <code>\/secure<\/code> \u2014 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0439, \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043c\u043e\u0433\u0443\u0442 \u0438\u043c\u0435\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438.<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0441\u0435\u0440\u0432\u0438\u0441\u0430:<\/p>\n<pre><code class=\"java\">package org.openidentityplatform.sampleservice;  import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;  import javax.servlet.http.HttpServletRequest; import java.util.Collections; import java.util.Map;  @SpringBootApplication public class SampleServiceApplication {     public static void main(String[] args) {         SpringApplication.run(SampleServiceApplication.class, args);     }      @RestController     public class IndexController {         @RequestMapping(\"\/\")         public Map&lt;String, String> index() {             return Collections.singletonMap(\"hello\", \"world\");         }          @RequestMapping(\"\/secure\")         public Map&lt;String, String> secure(HttpServletRequest request) {             return Collections.singletonMap(\"hello\", request.getHeader(\"X-Auth-Username\"));         }     } } <\/code><\/pre>\n<h3>\u0417\u0430\u043f\u0443\u0441\u043a \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430<\/h3>\n<p>\u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 <code>docker-compose.yaml<\/code> \u0444\u0430\u0439\u043b \u0438 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 \u043d\u0435\u0433\u043e \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441:<\/p>\n<pre><code class=\"yaml\">services:   sample-service: image: maximthomas\/sample-service     restart: always <\/code><\/pre>\n<p>\u0414\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0431\u0435\u0437 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u0438\u0437 \u0432\u043d\u0435\u0448\u043d\u0435\u0439 \u0441\u0435\u0442\u0438. \u0414\u0430\u043b\u0435\u0435 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043c Docker \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0441\u043e \u0448\u043b\u044e\u0437\u043e\u043c OpenIG, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u0430\u043b\u0438\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0438 \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0434\u043e \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430<\/p>\n<h2>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 OpenIG<\/h2>\n<p>\u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439 OpenIG &#8212; <code>openig-config<\/code> \u0432 \u044d\u0442\u043e\u0439 \u043f\u0430\u043f\u043a\u0435 \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u0435\u0449\u0435 \u043e\u0434\u043d\u0443 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>config<\/code> . \u0412 \u043f\u0430\u043f\u043a\u0435 <code>openig-config\/config<\/code> \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 2 \u0444\u0430\u0439\u043b\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438:<\/p>\n<p><code>admin.json<\/code><\/p>\n<pre><code class=\"json\">{   \"prefix\" : \"openig\",   \"mode\": \"PRODUCTION\" } <\/code><\/pre>\n<p>\u0438 <code>config.json<\/code><\/p>\n<pre><code class=\"json\">{   \"heap\": [   ],   \"handler\": {     \"type\": \"Chain\",     \"config\": {       \"filters\": [        ],       \"handler\": {         \"type\": \"Router\",         \"name\": \"_router\",         \"capture\": \"all\"       }     }   } } <\/code><\/pre>\n<p>\u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0441\u0435\u0440\u0432\u0438\u0441 OpenIG \u0432 \u0444\u0430\u0439\u043b <code>docker-compose.yaml<\/code> \u0421\u043c\u043e\u043d\u0442\u0438\u0440\u0443\u0439\u0442\u0435 \u043f\u0430\u043f\u043a\u0443 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 <code>openig-config<\/code> \u043a Docker \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0443 OpenIG. \u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0439 \u043e\u043f\u0446\u0438\u0438 \u00a0<code>-Dopenig.base<\/code> \u0434\u043e\u043b\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430 \u0441\u043c\u043e\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e.<\/p>\n<pre><code class=\"yaml\">services:   sample-service:     build:       context: .\/sample-service     restart: always    #OpenIG service   openig:     image: openidentityplatform\/openig:latest     restart: always     volumes:       - .\/openig-config:\/usr\/local\/openig-config     environment:       #OpenIG options       CATALINA_OPTS: -Dopenig.base=\/usr\/local\/openig-config     ports:       - \"8080:8080\" <\/code><\/pre>\n<h3>\u041f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a \u0441\u0435\u0440\u0432\u0438\u0441\u0443<\/h3>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 OpenIG \u043a \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u043c\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u0443. \u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u0443\u044e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 <code>-Dendpoint.api<\/code>. \u041e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430 URL \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0438 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u0432 OpenIG. \u0412\u044b, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0435 \u0442\u043e\u0447\u043a\u0438 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0435, \u043d\u043e, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0445 \u043e\u043f\u0446\u0438\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u043c\u044b\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u043c.<\/p>\n<p><code>docker-compose.yaml<\/code>:<\/p>\n<pre><code class=\"yaml\">...   openig:     image: openidentityplatform\/openig:latest     restart: always     volumes:       - .\/openig-config:\/usr\/local\/openig-config     environment:       #OpenIG options       CATALINA_OPTS: -Dopenig.base=\/usr\/local\/openig-config -Dendpoint.api=http:\/\/sample-service:8080\/     ports:       - \"8080:808 <\/code><\/pre>\n<p>\u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043c\u0430\u0440\u0448\u0440\u0443\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u0441\u0435\u0440\u0432\u0438\u0441. \u0421\u043e\u0437\u0434\u0430\u0439\u0442\u0435 \u043f\u0430\u043f\u043a\u0443 <code>routes<\/code> \u0441 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430\u043c\u0438 \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438  <code>openig-config\/config\/<\/code>. \u0418 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 \u043d\u0435\u0435 \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430<\/p>\n<p><code>10-api.json<\/code><\/p>\n<pre><code class=\"json\">{   \"name\": \"${matches(request.uri.path, '^\/')}\",   \"condition\": \"${matches(request.uri.path, '^\/')}\",   \"monitor\": true,   \"timer\": true,   \"handler\": {     \"type\": \"Chain\",     \"config\": {       \"filters\": [        ],       \"handler\": \"EndpointHandler\"     }   },   \"heap\": [     {       \"name\": \"EndpointHandler\",       \"type\": \"DispatchHandler\",       \"config\": {         \"bindings\": [           {             \"handler\": \"ClientHandler\",             \"capture\": \"all\",             \"baseURI\": \"${system['endpoint.api']}\"           }         ]       }     }   ] } <\/code><\/pre>\n<p>\u0422\u0430\u043a\u043e\u0439 \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u0443\u0435\u0442 \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043d\u0430 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u0438\u0437 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0442\u0432\u0435\u0442\u044b \u0431\u0435\u0437 \u043a\u0430\u043a\u0438\u0445 \u043b\u0438\u0431\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a.<\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c 404 \u0441\u0442\u0430\u0442\u0443\u0441 \u043d\u0430 \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b<\/p>\n<p><code>99-default.json<\/code>:<\/p>\n<pre><code class=\"json\">{   \"name\": \"99-default\",   \"handler\": {     \"type\": \"StaticResponseHandler\",     \"config\": {       \"status\": 404,       \"reason\": \"Not Found\",       \"headers\": {         \"Content-Type\": [ \"application\/json\" ]       },       \"entity\": \"{ \\\"error\\\": \\\"Not Found\\\"}\"     }   },   \"audit\": \"\/404\" } <\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0434\u0435\u043c\u043e \u0441\u0435\u0440\u0432\u0438\u0441 \u0438 OpenIG \u0432 Docker \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u0445:<\/p>\n<pre><code class=\"bash\">docker-compose up <\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c<\/p>\n<pre><code class=\"bash\">curl -v -X GET http:\/\/localhost:8080\/ Note: Unnecessary use of -X or --request, GET is already inferred. *   Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8080 (#0) > GET \/ HTTP\/1.1 > Host: localhost:8080 > User-Agent: curl\/7.58.0 > Accept: *\/* > &lt; HTTP\/1.1 200 OK &lt; Server: Apache-Coyote\/1.1 &lt; Date: Wed, 24 Apr 2019 15:06:17 GMT &lt; Content-Type: application\/json;charset=UTF-8 &lt; Transfer-Encoding: chunked &lt; * Connection #0 to host localhost left intact {\"hello\":\"world\"}  curl -v -X GET http:\/\/localhost:8080\/secure Note: Unnecessary use of -X or --request, GET is already inferred. *   Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8080 (#0) > GET \/secure HTTP\/1.1 > Host: localhost:8080 > User-Agent: curl\/7.58.0 > Accept: *\/* > &lt; HTTP\/1.1 200 OK &lt; Server: Apache-Coyote\/1.1 &lt; Date: Wed, 24 Apr 2019 15:04:49 GMT &lt; Content-Type: application\/json;charset=UTF-8 &lt; Transfer-Encoding: chunked &lt; * Connection #0 to host localhost left intact {\"name\":null} <\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0440\u043e\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u043c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430<\/p>\n<h2>\u0417\u0430\u0449\u0438\u0442\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430<\/h2>\n<p>\u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0432\u043e\u0437\u044c\u043c\u0435\u043c <a href=\"https:\/\/github.com\/OWASP\/CheatSheetSeries\/blob\/master\/cheatsheets\/REST_Security_Cheat_Sheet.md\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0430\u0446\u0438\u0438 OWASP<\/a> \u043f\u043e \u0437\u0430\u0449\u0438\u0442\u0435 REST \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432.<\/p>\n<h3>\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 HTTP<\/h3>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043a \u0441\u0435\u0440\u0432\u0438\u0441\u0443 \u0442\u043e\u043b\u044c\u043a\u043e GET \u0438 POST \u0437\u0430\u043f\u0440\u043e\u0441\u044b. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043c\u0430\u0440\u0448\u0440\u0443\u0442 <code>10-api.json<\/code> \u0444\u0438\u043b\u044c\u0442\u0440 <code>SwitchFilter<\/code><\/p>\n<pre><code class=\"json\">{   \"name\": \"${matches(request.uri.path, '^\/')}\",   \"condition\": \"${matches(request.uri.path, '^\/')}\",   \"monitor\": true,   \"timer\": true,   \"handler\": {     \"type\": \"Chain\",     \"config\": {       \"filters\": [         {           \"type\": \"SwitchFilter\",           \"config\": {             \"onRequest\": [               {                 \"condition\": \"${request.method != 'POST' and request.method != 'GET'}\",                 \"handler\": {                   \"type\": \"StaticResponseHandler\",                   \"config\": {                     \"status\": 405,                     \"reason\": \"Method not allowed\",                     \"headers\": {                       \"Content-Type\": [                         \"application\/json\"                       ]                     },                     \"entity\": \"{ \\\"error\\\": \\\"Method not allowed\\\"}\"                   }                 }               }             ]           }         }       ],        \"handler\": \"EndpointHandler\"     }   },   \"heap\": [     {       \"name\": \"EndpointHandler\",       \"type\": \"DispatchHandler\",       \"config\": {         \"bindings\": [           {             \"handler\": \"ClientHandler\",             \"capture\": \"all\",             \"baseURI\": \"${system['endpoint.api']}\"           }         ]       }     }   ] } <\/code><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u043c, \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0435 GET \u0438 \u043d\u0435 POST \u0448\u043b\u044e\u0437 \u0432\u0435\u0440\u043d\u0435\u0442 \u0441\u0442\u0430\u0442\u0443\u0441 405:<\/p>\n<pre><code class=\"bash\">$ curl -v -X PUT http:\/\/localhost:8080\/ *   Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8080 (#0) > PUT \/ HTTP\/1.1 > Host: localhost:8080 > User-Agent: curl\/7.58.0 > Accept: *\/* > &lt; HTTP\/1.1 405 Method Not Allowed &lt; Server: Apache-Coyote\/1.1 &lt; Content-Type: application\/json &lt; Content-Length: 32 &lt; Date: Wed, 24 Apr 2019 15:13:04 GMT &lt; * Connection #0 to host localhost left intact { \"error\": \"Method not allowed\"}  <\/code><\/pre>\n<h3>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 Content-Type<\/h3>\n<p>\u041f\u0443\u0441\u0442\u044c \u0434\u043b\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b <code>POST<\/code> \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0441 <code>Content-Type: application\/json<\/code> . \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0432 <code>SwitchFilter<\/code> \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 <code>Content-Type<\/code><\/p>\n<p><code>10-api.json<\/code>:<\/p>\n<pre><code class=\"json\">...       {           \"type\": \"SwitchFilter\",           \"config\": {             \"onRequest\": [               {                 \"condition\": \"${request.method != 'POST' and request.method != 'GET'}\",                 \"handler\": {                   \"type\": \"StaticResponseHandler\",                   \"config\": {                     \"status\": 405,                     \"reason\": \"Method not allowed\",                     \"headers\": {                       \"Content-Type\": [                         \"application\/json\"                       ]                     },                     \"entity\": \"{ \\\"error\\\": \\\"Method not allowed\\\"}\"                   }                 }               },               {                 \"condition\": \"${request.method == 'POST' and request.headers['Content-Type'][0].split(';')[0] != 'application\/json'}\",                 \"handler\": {                   \"type\": \"StaticResponseHandler\",                   \"config\": {                     \"status\": 415,                     \"reason\": \"Unsupported Media Type\",                     \"headers\": {                       \"Content-Type\": [<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-379296","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/379296","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=379296"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/379296\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=379296"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=379296"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=379296"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}