Reputation: 882
Alright, Flutter has the WebSocket recipe in the cookbook (here). And that works great against the websocket.org test server.
The thing is I want to connect with my own WebSocket server. So I first used this tutorial from SpringBoot.
Trying to make a request from the app (I am using the emulator here) to the spring boot backend did not work. I then started tinkering and removed STOMP from the spring boot backend and left it with a simple WebSocket passing strings. It works when using postman or even a webpage but it doesn't work from the app
The current state is present at this GitHub (both the spring boot and flutter projects): https://github.com/Flavsditz/websocket_sandbox
Does anyone have any tips here?
I appreciate it!
Upvotes: 4
Views: 6116
Reputation: 559
For those using
stomp_dart_client: ^0.3.7
with sockjs, Remember to pass the token to the header
initClient() async {
try {
if (_stompClient != null && _stompClient.connected) {
return;
}
SharedPreferences _prefs = await SharedPreferences.getInstance();
String token = _prefs.getString('access_token');
User currentUser = User.fromPrefJson(jsonDecode(_prefs.get('current_user')));
phone = currentUser.phone;
if (token != null) {
String requestUrl = '$baseUrl/websocket/tracker?access_token=$token'; // please note <<<<<
StompClient stompClient = StompClient(
config: StompConfig.SockJS(
url: requestUrl,
stompConnectHeaders: {
'Authorization' : 'Bearer $token', // please note <<<<<
},
webSocketConnectHeaders: {
'Authorization' : 'Bearer $token', // please note <<<<<
},
onStompError: (StompFrame frame) {
print('A stomp error occurred in web socket connection :: ${frame.body}');
},
onWebSocketError: (dynamic frame) {
print('A Web socket error occurred in web socket connection :: ${frame.toString()}');
},
onDebugMessage: (dynamic frame) {
print('A debug error occurred in web socket connection :: ${frame.toString()}');
},
onConnect: (StompClient client, StompFrame connectFrame) {
print('${client.toString()} connected with the following frames ${connectFrame.body}');
_stompClient = client;
clientUnSubscribeFn = _stompClient.subscribe(
destination: '/topic/client', headers: {},
callback: (frame) {
// Received a frame for this subscription
print(frame.body);
clientController.add(frame.body);
}
);
}
)
);
stompClient.activate();
}
} catch(e) {
print('An error occurred ${e.toString()}');
}
}
sendClientMessage(String msg) async {
if (_stompClient != null && _stompClient.connected) {
_stompClient.send(
destination: '/topic/client',
body: msg,
headers: {}
);
}
}
Also do not forget to update the Spring security configurations and web socket configurations
@Configuration
public class WebsocketSecurityConfiguration extends AbstractSecurityWebSocketMessageBrokerConfigurer {
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.nullDestMatcher().authenticated()
.simpDestMatchers("/topic/tracker").hasAuthority(AuthoritiesConstants.ADMIN)
.simpSubscribeDestMatchers("/topic/**").authenticated()
.simpDestMatchers("/topic/**").authenticated()
// message types other than MESSAGE and SUBSCRIBE
.simpTypeMatchers(SimpMessageType.MESSAGE, SimpMessageType.SUBSCRIBE).denyAll()
// catch all
.anyMessage().denyAll();
}
/**
* Disables CSRF for Websockets.
*/
@Override
protected boolean sameOriginDisabled() {
return true;
}
}
// spring security configs for http
@Override
public void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.csrf()
.disable()
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(problemSupport)
.accessDeniedHandler(problemSupport)
.and()
.headers()
.contentSecurityPolicy("default-src 'self'; frame-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://storage.googleapis.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:")
.and()
.referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)
.and()
.featurePolicy("geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope 'none'; speaker 'none'; fullscreen 'self'; payment 'none'")
.and()
.frameOptions()
.deny()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.antMatchers("/websocket/tracker").hasAnyAuthority(
AuthoritiesConstants.ADMIN, AuthoritiesConstants.MANAGER, AuthoritiesConstants.STAFF,
AuthoritiesConstants.CLIENT, AuthoritiesConstants.DRIVER
)
.antMatchers("/websocket/**").permitAll()
.httpBasic()
.and()
.apply(securityConfigurerAdapter());
// @formatter:on
}
Cheers
Upvotes: 0
Reputation: 2994
Thanks for the solution, For the side note if you want to test in real device than,
Both real device and pc has to in same network.
(In my case I am using hotspot from my phone to pc)
Get IP from your pc with cmd, type ipconfig to get IP.
(In my case its IPv4 Address. . . . . . . . . . . : 192.168.43.423
)
Now paste your IP instead of localhost
Eg.
IOWebSocketChannel.connect(Uri(scheme: "ws",host: "192.168.43.423",port: 8080,path: "/socket"))
Thanks
Upvotes: 0
Reputation: 882
After a bit of consideration, I found the issue:
The problem is that my spring-boot server was on localhost
, but the flutter (which is also the android emulator) has its own loopback service.
So calling localhost
inside the Flutter program is referring to another place instead of the one I wanted.
I've substituted the localhost
for the ip 10.0.2.2
which is an alias to the host PC which is set up to help in development.
For more infos check this answer: here
Of course if you wanted to test from a real device than one would need to publish the backend for the outside, so this answer might be better: here
Upvotes: 3
Reputation: 1
In flutter-websocket_test/lib/message_page.dart
you have the following on line 6-7:
final WebSocketChannel channel = IOWebSocketChannel.connect(
Uri(scheme: "ws", host: "locahost", port: 8080, path: "/socket"),
You have locahost
instead of localhost
, so try changing this and see if it works.
Upvotes: 0