diff --git a/demo-client-app/.gitignore b/demo-client-app/.gitignore index 4d29575..83f2e99 100644 --- a/demo-client-app/.gitignore +++ b/demo-client-app/.gitignore @@ -1,5 +1,7 @@ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. +/.eslintcache + # dependencies /node_modules /.pnp diff --git a/demo-client-app/package.json b/demo-client-app/package.json index d1e5af6..b13f3ef 100644 --- a/demo-client-app/package.json +++ b/demo-client-app/package.json @@ -2,6 +2,7 @@ "name": "demo-client-app", "version": "0.1.0", "private": true, + "proxy": "http://localhost:8081", "dependencies": { "@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^11.1.0", @@ -11,7 +12,9 @@ "react": "^17.0.1", "react-dom": "^17.0.1", "react-scripts": "4.0.1", - "web-vitals": "^0.2.4" + "sockjs-client": "^1.5.0", + "web-vitals": "^0.2.4", + "webstomp-client": "^1.2.6" }, "scripts": { "start": "react-scripts start", @@ -36,5 +39,9 @@ "last 1 firefox version", "last 1 safari version" ] + }, + "devDependencies": { + "express": "^4.17.1", + "http-proxy-middleware": "^1.0.6" } } diff --git a/demo-client-app/runProxy.js b/demo-client-app/runProxy.js new file mode 100644 index 0000000..f8e3e2a --- /dev/null +++ b/demo-client-app/runProxy.js @@ -0,0 +1,13 @@ +const { createProxyMiddleware } = require("http-proxy-middleware"); +const express = require('express'); + +const PORT = 8080; + +console.log(`Starting Proxy on port ${PORT}`); + +const app = express(); + +app.use(createProxyMiddleware({ target: "http://localhost:8081", changeOrigin: true, ws: true })); +app.listen(PORT, () => { + console.log(`Started on http://localhost:${PORT}`); +}); diff --git a/demo-client-app/src/App.js b/demo-client-app/src/App.js index a9c868e..31bf123 100644 --- a/demo-client-app/src/App.js +++ b/demo-client-app/src/App.js @@ -1,7 +1,28 @@ -import { useCallback } from "react"; +import { useCallback, useEffect } from "react"; +import Stomp from "webstomp-client"; +import SockJS from "sockjs-client"; import logo from "./logo.svg"; import "./App.css"; +let stomp + +const connect = async () => { + if (stomp != null) return; + console.info("Connect to Websocket"); + const sock = new SockJS("/api/ws"); + stomp = Stomp.over(sock); + + stomp.connect( + {}, + () => { + console.log("Connected"); + }, + error => { + console.error("Disconnected"); + } + ); +} + function App({ keycloak }) { const fetchFromApi = useCallback(async (url) => { const response = await fetch(url, { @@ -16,6 +37,10 @@ function App({ keycloak }) { } }, [keycloak.token]); + useEffect(() => { + connect(); + }, []); + return (
@@ -27,7 +52,7 @@ function App({ keycloak }) { className="App-link" onClick={(e) => { e.preventDefault(); - fetchFromApi("http://localhost:8081/api/userinfo"); + fetchFromApi("/api/userinfo"); }} > Get user email @@ -37,7 +62,7 @@ function App({ keycloak }) { className="App-link" onClick={(e) => { e.preventDefault(); - fetchFromApi("http://localhost:8081/api/users"); + fetchFromApi("/api/users"); }} > Get all users diff --git a/demo-client-app/src/index.js b/demo-client-app/src/index.js index b5ff0fb..805db8f 100644 --- a/demo-client-app/src/index.js +++ b/demo-client-app/src/index.js @@ -36,8 +36,8 @@ keycloak.init({ onLoad: initOptions.onLoad }).then((auth) => { if (refreshed) { console.info('Token refreshed' + refreshed); } else { - console.warn('Token not refreshed, valid for ' - + Math.round(keycloak.tokenParsed.exp + keycloak.timeSkew - new Date().getTime() / 1000) + ' seconds'); + // console.warn('Token not refreshed, valid for ' + // + Math.round(keycloak.tokenParsed.exp + keycloak.timeSkew - new Date().getTime() / 1000) + ' seconds'); } }).catch(() => { console.error('Failed to refresh token'); diff --git a/demo-client-app/yarn.lock b/demo-client-app/yarn.lock index 03ebb60..f40a98d 100644 --- a/demo-client-app/yarn.lock +++ b/demo-client-app/yarn.lock @@ -1687,6 +1687,13 @@ resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#3c9ee980f1a10d6021ae6632ca3e79ca2ec4fb50" integrity sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA== +"@types/http-proxy@^1.17.4": + version "1.17.5" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.5.tgz#c203c5e6e9dc6820d27a40eb1e511c70a220423d" + integrity sha512-GNkDE7bTv6Sf8JbV2GksknKOsk7OznNYHSdrtvPJXO0qJ9odZig6IZKUi5RFGi6d1bf6dgIAe4uXi3DBc7069Q== + dependencies: + "@types/node" "*" + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" @@ -3840,7 +3847,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: dependencies: ms "2.0.0" -debug@^3.1.1, debug@^3.2.5: +debug@^3.1.1, debug@^3.2.5, debug@^3.2.6: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== @@ -4840,7 +4847,7 @@ faye-websocket@^0.10.0: dependencies: websocket-driver ">=0.5.1" -faye-websocket@~0.11.1: +faye-websocket@^0.11.3, faye-websocket@~0.11.1: version "0.11.3" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e" integrity sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA== @@ -5534,7 +5541,18 @@ http-proxy-middleware@0.19.1: lodash "^4.17.11" micromatch "^3.1.10" -http-proxy@^1.17.0: +http-proxy-middleware@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-1.0.6.tgz#0618557722f450375d3796d701a8ac5407b3b94e" + integrity sha512-NyL6ZB6cVni7pl+/IT2W0ni5ME00xR0sN27AQZZrpKn1b+qRh+mLbBxIq9Cq1oGfmTc7BUq4HB77mxwCaxAYNg== + dependencies: + "@types/http-proxy" "^1.17.4" + http-proxy "^1.18.1" + is-glob "^4.0.1" + lodash "^4.17.20" + micromatch "^4.0.2" + +http-proxy@^1.17.0, http-proxy@^1.18.1: version "1.18.1" resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== @@ -6667,7 +6685,7 @@ json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= -json3@^3.3.2: +json3@^3.3.2, json3@^3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== @@ -9832,6 +9850,18 @@ sockjs-client@1.4.0: json3 "^3.3.2" url-parse "^1.4.3" +sockjs-client@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.5.0.tgz#2f8ff5d4b659e0d092f7aba0b7c386bd2aa20add" + integrity sha512-8Dt3BDi4FYNrCFGTL/HtwVzkARrENdwOUf1ZoW/9p3M8lZdFT35jVdrHza+qgxuG9H3/shR4cuX/X9umUrjP8Q== + dependencies: + debug "^3.2.6" + eventsource "^1.0.7" + faye-websocket "^0.11.3" + inherits "^2.0.4" + json3 "^3.3.3" + url-parse "^1.4.7" + sockjs@0.3.20: version "0.3.20" resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.20.tgz#b26a283ec562ef8b2687b44033a4eeceac75d855" @@ -10752,6 +10782,14 @@ url-parse@^1.4.3: querystringify "^2.1.1" requires-port "^1.0.0" +url-parse@^1.4.7: + version "1.5.0" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.0.tgz#90aba6c902aeb2d80eac17b91131c27665d5d828" + integrity sha512-9iT6N4s93SMfzunOyDPe4vo4nLcSu1yq0IQK1gURmjm8tQNlM6loiuCRrKG1hHGXfB2EWd6H4cGi7tGdaygMFw== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" @@ -11055,6 +11093,11 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== +webstomp-client@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/webstomp-client/-/webstomp-client-1.2.6.tgz#57e8a044bac0a08bfc3d0e54d43760c2aeefadab" + integrity sha512-9HajO6Ki2ViEGIusLZtjM2lcO2VaQUvtXhLQQ4Cm543RLjfTCEgI3sFaiXts3TvfZgrtY/vI/+qUkm2qWD/NVg== + whatwg-encoding@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" diff --git a/demo-resource-server/build.gradle b/demo-resource-server/build.gradle index b8373ef..e128b90 100644 --- a/demo-resource-server/build.gradle +++ b/demo-resource-server/build.gradle @@ -22,6 +22,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-websocket' runtimeOnly 'org.postgresql:postgresql' developmentOnly 'org.springframework.boot:spring-boot-devtools' testImplementation 'org.springframework.boot:spring-boot-starter-test' diff --git a/demo-resource-server/lombok.config b/demo-resource-server/lombok.config new file mode 100644 index 0000000..6aa51d7 --- /dev/null +++ b/demo-resource-server/lombok.config @@ -0,0 +1,2 @@ +# This file is generated by the 'io.freefair.lombok' Gradle plugin +config.stopBubbling = true diff --git a/demo-resource-server/src/main/java/ru/digitalbanana/demoresourceserver/config/WebSecurityConfig.java b/demo-resource-server/src/main/java/ru/digitalbanana/demoresourceserver/config/WebSecurityConfig.java index 4498530..95ef275 100644 --- a/demo-resource-server/src/main/java/ru/digitalbanana/demoresourceserver/config/WebSecurityConfig.java +++ b/demo-resource-server/src/main/java/ru/digitalbanana/demoresourceserver/config/WebSecurityConfig.java @@ -12,12 +12,13 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { protected void configure(HttpSecurity http) throws Exception { http.cors() .and() + .csrf().disable() .authorizeRequests() .antMatchers(HttpMethod.GET, "/userinfo", "/user/**") .authenticated() // .hasAuthority("SCOPE_web-api") .anyRequest() - .authenticated() + .permitAll() .and() .oauth2ResourceServer() .jwt(); diff --git a/demo-resource-server/src/main/java/ru/digitalbanana/demoresourceserver/config/WebSocketConfig.java b/demo-resource-server/src/main/java/ru/digitalbanana/demoresourceserver/config/WebSocketConfig.java new file mode 100644 index 0000000..ce6fa3f --- /dev/null +++ b/demo-resource-server/src/main/java/ru/digitalbanana/demoresourceserver/config/WebSocketConfig.java @@ -0,0 +1,36 @@ +package ru.digitalbanana.demoresourceserver.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.simp.config.MessageBrokerRegistry; +import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; +import org.springframework.web.socket.config.annotation.StompEndpointRegistry; +import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; +import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration; + +/** + * Web Socket configuration + * Created by dima on 8/12/16. + */ +@Configuration +@EnableWebSocketMessageBroker +public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { + + @Override + public void configureMessageBroker(MessageBrokerRegistry registry) { + registry.setApplicationDestinationPrefixes("/app"); + } + + @Override + public void registerStompEndpoints(StompEndpointRegistry registry) { + registry + .addEndpoint("/ws") + .setAllowedOriginPatterns("*") + .withSockJS(); + } + + @Override + public void configureWebSocketTransport(WebSocketTransportRegistration registration) { + registration.setSendBufferSizeLimit(1024 * 512 * 1024); // default : 512 * 1024 + + } +} diff --git a/demo-resource-server/src/main/java/ru/digitalbanana/demoresourceserver/service/UserService.java b/demo-resource-server/src/main/java/ru/digitalbanana/demoresourceserver/service/UserService.java index ac88a83..e9c739a 100644 --- a/demo-resource-server/src/main/java/ru/digitalbanana/demoresourceserver/service/UserService.java +++ b/demo-resource-server/src/main/java/ru/digitalbanana/demoresourceserver/service/UserService.java @@ -1,7 +1,5 @@ package ru.digitalbanana.demoresourceserver.service; -import java.util.List; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; diff --git a/demo-resource-server/src/main/java/ru/digitalbanana/demoresourceserver/web/controller/UserInfoController.java b/demo-resource-server/src/main/java/ru/digitalbanana/demoresourceserver/web/controller/UserInfoController.java index 9930d11..15dc9b8 100644 --- a/demo-resource-server/src/main/java/ru/digitalbanana/demoresourceserver/web/controller/UserInfoController.java +++ b/demo-resource-server/src/main/java/ru/digitalbanana/demoresourceserver/web/controller/UserInfoController.java @@ -7,7 +7,6 @@ import java.util.stream.StreamSupport; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.oauth2.jwt.Jwt; -import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @@ -16,7 +15,6 @@ import ru.digitalbanana.demoresourceserver.persistence.model.UserEntity; import ru.digitalbanana.demoresourceserver.service.UserService; @Slf4j -@CrossOrigin(origins = "*") @RestController public class UserInfoController {