2017-03-06 150 views
0

我使用弹簧安全来验证我的spring websocket服务器。它适用于Basic authentication,但当我更改为Digest authentication时出错。我不知道该把什么放入标题。有人知道任何解决方案吗?具有摘要式身份验证的弹簧websocket

这是WebSocket的客户端代码片段:

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()); 
...... 

更新:

它与消化休息效果很好,下面的代码可以配置RestTempalte使用摘要:

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; 
    } 
} 

获取休息模板:

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; 
    } 
} 

使用REST模板:

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()); 
+1

你对Digest算法有什么了解?这不仅仅是设置标题。 – holmis83

+0

当客户端向服务器发送请求时,它将首次收到401错误。然后,客户端可以从响应头获得领域和随机数以发送后续请求。我认为如果我发送正确的标题可能没有问题,但很难得到随机数。但是,用摘要验证websocket的正确方法是什么? –

回答

0

我已经找到了解决方案。在服务器端配置digest authenticationspring security,然后更改客户端实现这一点:

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()); 

摘要在rest template配置,我们需要做的是将其添加到Transport list。您应该先添加rest template,然后websocket,因为在创建sockJs网址时它很重要。更多细节请参考this link