NOTE: This Project has been archived and will no longer get updates.
Check out the official docs: RSocket Docs
Most interesting:
Network communication is asynchronous. The RSocket protocol embraces this and models all communication as multiplexed streams of messages over a single network connection, and never synchronously blocks while waiting for a response
In this example I am using a SpringCloud Gateway to demonstrate how RSocket communication works over WebSocket with an rsocket-js client and VueJS frontend.
We'd like to use a single websocket endpoint/broker for multiple services. The normal spring integration with STOMP over WebSocket cannot be used on the reactive stack. Therefore, I had to take a deeper look into RSocket.
The server is creating scheduled order events which are added to a stream, those can be retrieved using a HTTP GET or RSocket Request Stream.
There are two kind of order, LOTR (Lord of the Rings) order and GOT (Game of Thrones) order, to demonstrate how routes & security can be handled. The order event is a order with random kind (either GOT or LOTR).
For now this example is just using the REQUEST_STREAM frame, but could be easily extended.
The decision about who retrieves which data is made based on the users authorities.
This example can be used with two different Identity Providers:
- SpringSecurity
- KeyCloak
Those can be easily switched trough using profiles.
Username | Password | Role | Can access/retrieve orders |
---|---|---|---|
admin | admin | ADMIN | ALL |
frodo | frodo | MIDDLEEARTH | LOTR |
john | john | WESTEROS | GOT |
To administrate the KeyCloak use username: kcadmin and password: kcadmin.
Routes and endpoints requested via basic auth.
Routes are requested via bearer auth (where the JWT is obtained before the request is made) and endpoints are handled by the SpringCloudGateway which holds the authentication (OAuth2 client).
Either use the checked in IntelliJ run-configuration in .run or launch it manually.
$ mvn clean package
$ cd target/
$ java -jar gateway-rsocket-websocket.jar
Run the KeyCloak using docker-compose up
and start the server afterwards:
$ mvn clean package
$ cd target/
$ java -jar -Dspring.profiles.active=keycloak gateway-rsocket-websocket.jar
$ cd frontend/
$ npm install
$ npm run dev
Now head over to the frontend served under http://localhost:8070/ (routed by the gateway).
Server: 8070
Client: 8080
KeyCloak: 8060 (optional)
All values in doubled curly brackets ({{}) must be replaced with the actual value, including the brackets!
For RSocket development I used RSC installed using:
brew install making/tap/rsc
Note: When using this tool whole frames sent are visible and also check out the server logs.
# Basic
$ rsc --stream --route=orders.all --sm simple:{{user}}:{{password}} --smmt MESSAGE_RSOCKET_AUTHENTICATION --debug ws://localhost:8070/server/rsocket
$ rsc --stream --route=orders.lotr --sm simple:{{user}}:{{password}} --smmt MESSAGE_RSOCKET_AUTHENTICATION --debug ws://localhost:8070/server/rsocket
$ rsc --stream --route=orders.got --sm simple:{{user}}:{{password}} --smmt MESSAGE_RSOCKET_AUTHENTICATION --debug ws://localhost:8070/server/rsocket
# With data (payload)
$ rsc --stream --route=orders.all --sm simple:{{user}}:{{password}} --smmt MESSAGE_RSOCKET_AUTHENTICATION --debug --data='{"rscclient":"request"}' ws://localhost:8070/server/rsocket
# With metadata
$ rsc --stream --route=orders.all --sm simple:{{user}}:{{password}} --smmt MESSAGE_RSOCKET_AUTHENTICATION --debug --metadata='{"data":"custom metadata value from rsc"}' ws://localhost:8070/server/rsocket
First we need to get an access_token for bearer auth, see this
# Basic
$ rsc --stream --route=orders.all --sm "bearer:{{access_token}}" --smmt MESSAGE_RSOCKET_AUTHENTICATION --debug ws://localhost:8070/server/rsocket
$ rsc --stream --route=orders.lotr --sm "bearer:{{access_token}}" --smmt MESSAGE_RSOCKET_AUTHENTICATION --debug ws://localhost:8070/server/rsocket
$ rsc --stream --route=orders.got --sm "bearer:{{access_token}}" --smmt MESSAGE_RSOCKET_AUTHENTICATION --debug ws://localhost:8070/server/rsocket
# With data (payload)
$ rsc --stream --route=orders.all --sm "bearer:{{access_token}}" --smmt MESSAGE_RSOCKET_AUTHENTICATION --debug --data='{"rscclient":"request"}' ws://localhost:8070/server/rsocket
# With metadata
$ rsc --stream --route=orders.all --sm "bearer:{{access_token}}" --smmt MESSAGE_RSOCKET_AUTHENTICATION --debug --metadata='{"data":"custom metadata value from rsc"}' ws://localhost:8070/server/rsocket
To retrieve the stream using HTTP I used HTTPIE using:
Retrieve orders:
http --stream :8070/server/orders --auth "{{user}}:{{password}}"
Create orders:
# Random
http :8070/server/orders/new --auth "{{user}}:{{password}}"
# Specific
http :8070/server/orders/new kind==lotr --auth "{{user}}:{{password}}"
http :8070/server/orders/new kind==got --auth "{{user}}:{{password}}"
http --stream :8070/server/orders Authorization:"Bearer {{access_token}}"
First we need to get an access_token for bearer auth, see this
http --stream :8070/server/orders Authorization:"Bearer {{access_token}}"
Create orders:
# Random
http :8070/server/orders/new Authorization:"Bearer {{access_token}}"
# Specific
http :8070/server/orders/new kind==lotr Authorization:"Bearer {{access_token}}"
http :8070/server/orders/new kind==got Authorization:"Bearer {{access_token}}"
To directly extract the token from the JSON response JQ is used.
http -f :8060/auth/realms/RSOCKET/protocol/openid-connect/token client_id=gateway username={{user}} password={{password}} grant_type=password client_secret=059fa1a6-b94f-42a1-81c8-210acfe6f299 | jq .access_token
Now this token can be used for bearer auth.
- Payload integration
- Custom metadata
- Route with variable
- SpringSecurity
- Multiple routes
We are pretty new to WebFlux and the whole reactor project, so this code might not be optimized for being non-blocking, suggestions are welcome.
Each contribution, no matter in what, is highly appreciated!