Spring websocket ssl和摘要认证
来源:互联网 发布:太极拳威力知乎 编辑:程序博客网 时间:2024/05/20 04:13
前段时间公司的项目要给websocket连接加ssl和digest认证,我们用的是spring websocket的实现。网上介绍了两种给websocket加ssl的方法,一种是websocketClient.setWebsocketFactory(websocketFactory),另一种是websocketClient.getUserProperties().put("org.apache.tomcat.websocket.SSL_CONTEXT", sslContext)。但是这两种方法是针对纯websocket的,而不是spring websocket。前一种方法在spring websocket中没有对应的实现,后一种方法我试过但是没有奏效。后来通过阅读源码发现一个简单有效的办法,在这里分享大家以供参考。
SSL
websocket协议是从http upgrade上来的,websocket的安全和认证也是基于http。给websocket加ssl,实际是把http转变成https,只要让tomcat运行在8443端口(我配的是8443)即可。server的代码如下:
import org.apache.coyote.http11.Http11NioProtocol;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.EnableAutoConfiguration;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Profile;import org.springframework.core.io.Resource;import org.springframework.scheduling.annotation.EnableScheduling;@Configuration@EnableAutoConfiguration@EnableScheduling@ComponentScan@SpringBootApplicationpublic class WssBrokerApplication {public static void main(String[] args) {SpringApplication.run(WssBrokerApplication.class, args);}@Profile("ssl")@BeanEmbeddedServletContainerCustomizer containerCustomizer(@Value("${keystore.file}") Resource keystoreFile,@Value("${keystore.pass}") String keystorePass) throws Exception {String absoluteKeystoreFile = keystoreFile.getFile().getAbsolutePath();return (ConfigurableEmbeddedServletContainer container) -> {if (container instanceof TomcatEmbeddedServletContainerFactory) {TomcatEmbeddedServletContainerFactory tomcat = (TomcatEmbeddedServletContainerFactory) container;tomcat.addConnectorCustomizers((connector) -> {connector.setPort(8443);connector.setSecure(true);connector.setScheme("https");Http11NioProtocol proto = (Http11NioProtocol) connector.getProtocolHandler();proto.setSSLEnabled(true);proto.setKeystoreFile(absoluteKeystoreFile);proto.setKeystorePass(keystorePass);proto.setKeystoreType("PKCS12");proto.setKeyAlias("tomcat");});}};}}配置文件application.porperties放在resources目录下:
spring.profiles.active: sslkeystore.file: demo.keystorekeystore.pass: changeit
Digest
给websocket配置digest认证:
spring security的配置参照上一篇博文digest认证:http://blog.csdn.net/xiaoyaoyulinger/article/details/60881279,然后给websocket加digest支持。
import com.fasterxml.jackson.databind.ObjectMapper;import com.fasterxml.jackson.databind.SerializationFeature;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;import org.springframework.messaging.simp.config.MessageBrokerRegistry;import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry;import org.springframework.security.config.annotation.web.socket.AbstractSecurityWebSocketMessageBrokerConfigurer;import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;import org.springframework.web.socket.config.annotation.StompEndpointRegistry;@Configuration@EnableWebSocketMessageBrokerpublic class WssBrokerConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {@Override protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {messages .nullDestMatcher().authenticated() .simpSubscribeDestMatchers("/topic/notification").permitAll() .simpDestMatchers("/**").authenticated() .anyMessage().denyAll(); } @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic"); config.setApplicationDestinationPrefixes("/ws"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/hpdm-ws").setAllowedOrigins("*").withSockJS(); } @Bean public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() { ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(mapper); return converter; } @Override protected boolean sameOriginDisabled() {return true;}}
Client
server配置完后,websocket client也要支持ssl和digest。在rest template中配置ssl和digest信息,然后把rest template加到sockJs client中。下面是client的代码:
1. 给rest template配置ssl和digest信息:
import java.security.KeyStore;import javax.net.ssl.SSLContext;import org.apache.http.auth.AuthScope;import org.apache.http.auth.UsernamePasswordCredentials;import org.apache.http.client.CredentialsProvider;import org.apache.http.client.HttpClient;import org.apache.http.conn.ssl.SSLConnectionSocketFactory;import org.apache.http.conn.ssl.TrustSelfSignedStrategy;import org.apache.http.impl.client.BasicCredentialsProvider;import org.apache.http.impl.client.HttpClients;import org.apache.http.ssl.SSLContexts;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;import org.springframework.core.io.ClassPathResource;import org.springframework.core.io.Resource;import org.springframework.http.client.ClientHttpRequestFactory;import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;import org.springframework.web.client.RestOperations;import org.springframework.web.client.RestTemplate;import com.hpi.hpdm.rest.digest.HttpComponentsClientHttpRequestFactoryDigestAuth;/** * SSL and digest config for rest template */@Configurationpublic class SSLAndDigestConfig { @Bean public RestOperations restOperations(ClientHttpRequestFactory clientHttpRequestFactory) throws Exception { return new RestTemplate(clientHttpRequestFactory); } @Bean public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory(HttpClient httpClient) { return new HttpComponentsClientHttpRequestFactoryDigestAuth(httpClient); } @Bean public HttpClient httpClient(@Value("${keystore.file}") String file, @Value("${keystore.pass}") String password) throws Exception {KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());Resource resource = new ClassPathResource(file);trustStore.load(resource.getInputStream(), password.toCharArray()); SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build(); @SuppressWarnings("deprecation")SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1.2"}, null, null); return HttpClients.custom().setDefaultCredentialsProvider(provider()).setSSLSocketFactory(sslsf).useSystemProperties().build(); } @Bean public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } private CredentialsProvider provider() {CredentialsProvider provider = new BasicCredentialsProvider();UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("admin", "admin");provider.setCredentials(AuthScope.ANY, credentials);return provider;}}
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; }}
client这边也要有配置文件application.properties,指定keystore和password,配置同上。
2. 把rest template加到sockJs client中:
@Autowiredprivate RestOperations rest;SockJsClient sockJsClient;WebSocketStompClient stompClient;List<Transport> transports = new ArrayList<>();final WebSocketHttpHeaders headers = new WebSocketHttpHeaders(); StandardWebSocketClient websocketClient = new StandardWebSocketClient();transports.add(new RestTemplateXhrTransport(rest));transports.add(new WebSocketTransport(websocketClient));sockJsClient = new SockJsClient(transports);stompClient = new WebSocketStompClient(sockJsClient);stompClient.setMessageConverter(new MappingJackson2MessageConverter());
注意,要先加RestTemplateXhrTransport,然后加WebsocketTransport,因为sockJs client会按如下规则去构造URL:http://host:port/myApp/myEndpoint/{server-id}/{session-id}/{transport}。
详情参考http://stackoverflow.com/questions/30413380/websocketstompclient-wont-connect-to-sockjs-endpoint
- Spring websocket ssl和摘要认证
- websocket 和SSL浅析
- HTTP的基本认证和摘要认证
- HTTP基本认证和摘要认证
- Rest API: 基本认证和摘要认证
- 配置JAVA SSL/TLS 之websocket wss交互式认证
- Spring WebSocket使用token认证连接
- ssl双向认证和单向认证原理
- ssl双向认证和单向认证原理
- SSL单向认证和双向认证
- ssl双向认证和单向认证原理
- ssl双向认证和单向认证原理
- ssl双向认证和单向认证原理
- ssl双向认证和单向认证原理
- SSL的单向认证和双向认证
- ssl双向认证和单向认证原理
- SSL双向认证和单向认证原理
- ssl双向认证和单向认证原理
- 科锐课堂笔记:2017/3/15 数组指针与指针数组
- MySQL错误ERROR 2003 (HY000): Can't connect to MySQL server on 'localhost' (10061)的解决
- 获取mac地址和IP地址方式
- 拦截器
- 什么是WEB
- Spring websocket ssl和摘要认证
- HDU1016
- 剑指Offer系列-面试题34:丑数
- One python demo to analysis the decoding time and update texture and swapbuffer time
- 负载均衡的四层和七层区别
- 3、编辑器--动作编辑器需求
- 国际化
- 同一进程下的线程可以共享哪些资源
- 史上最全的Maven Pom文件标签详解