I use Spring security to authenticate my spring websocket
server. It works fine with the Basic authentication
, but it went wrong when I changed to Digest authentication
. I don't know what to put into the headers. Does someone know any solutions?
This is the websocket client code snippet:
SockJsClient sockJsClient;
WebSocketStompClient stompClient;
List<Transport> transports = new ArrayList<>();
final WebSocketHttpHeaders headers = new WebSocketHttpHeaders();
headers.add("Authorization", "Basic YWRtaW46YWRtaW4=");
transports.add(new WebSocketTransport(new StandardWebSocketClient()));
sockJsClient = new SockJsClient(transports);
stompClient = new WebSocketStompClient(sockJsClient);
stompClient.setMessageConverter(new MappingJackson2MessageConverter());
......
Update:
It works well with digest for rest, the following codes can configure RestTempalte
to use digest:
import java.net.URI;
import org.apache.http.HttpHost;
import org.apache.http.client.AuthCache;
import org.apache.http.client.HttpClient;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.auth.DigestScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
public class HttpComponentsClientHttpRequestFactoryDigestAuth extends HttpComponentsClientHttpRequestFactory {
public HttpComponentsClientHttpRequestFactoryDigestAuth(HttpClient client) {
super(client);
}
@Override
protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {
return createHttpContext(uri);
}
private HttpContext createHttpContext(URI uri) {
// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();
// Generate DIGEST scheme object, initialize it and add it to the local auth cache
DigestScheme digestAuth = new DigestScheme();
// If we already know the realm name
digestAuth.overrideParamter("realm", "myrealm");
HttpHost targetHost = new HttpHost(uri.getHost(), uri.getPort());
authCache.put(targetHost, digestAuth);
// Add AuthCache to the execution context
BasicHttpContext localcontext = new BasicHttpContext();
localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);
return localcontext;
}
}
Get a rest template:
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
public class RestTempleteConfig {
public RestTemplate getRestTemplate() {
CloseableHttpClient client = HttpClientBuilder.create().setDefaultCredentialsProvider(provider())
.useSystemProperties().build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactoryDigestAuth(
client);
return new RestTemplate(requestFactory);
}
private CredentialsProvider provider() {
CredentialsProvider provider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("admin", "admin");
provider.setCredentials(AuthScope.ANY, credentials);
return provider;
}
}
Use rest template:
RestTemplate restTemplate = new RestTempleteConfig().getRestTemplate();
String uri = "http://localhost:8080/login";
ResponseEntity<String> entity = restTemplate.exchange(uri, HttpMethod.GET, null, String.class);
System.out.println(entity.getBody());
I have figured out the solution. Configure digest authentication
with spring security
at the sever side, then change client implementation to this:
RestTemplate restTemplate = new RestTempleteConfig().getRestTemplate();
SockJsClient sockJsClient;
WebSocketStompClient stompClient;
List<Transport> transports = new ArrayList<>();
final WebSocketHttpHeaders headers = new WebSocketHttpHeaders();
StandardWebSocketClient websocketClient = new StandardWebSocketClient();
// add restTemplate first
transports.add(new RestTemplateXhrTransport(restTemplate));
transports.add(new WebSocketTransport(websocketClient));
sockJsClient = new SockJsClient(transports);
stompClient = new WebSocketStompClient(sockJsClient);
stompClient.setMessageConverter(new MappingJackson2MessageConverter());
The digest is configured in the rest template
, what we need to do is to add it to Transport list
. And you should add rest template
first, then websocket
, for it matters when creating the sockJs
url. More details refer to this link.