- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
首先让我说,对于我的场景,访问应该被拒绝。内置 Spring Boot 和 Spring Security 4。我允许任何人连接到 websocket 并订阅一个主题,但我确保能够使用以下 web 套接字安全配置向该主题发送消息:
@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.simpSubscribeDestMatchers("/main-page-feed/thought-queue/**").permitAll()
.simpDestMatchers("/thought-bubble/push-to-queue/**").authenticated();
}
@Override
protected boolean sameOriginDisabled() {
return true;
}
}
因此,当您尝试在未经身份验证的情况下向 /thought-bubble/push-to-queue
发送消息时,它会拒绝您(这是正确的,我想强调这一点,因为我能找到的唯一其他问题是错误抛出异常时)并抛出 AccessDeniedException
。我不明白的是,与 websocket 安全性相反,Spring HTTP 安全性会锁定某些内容并拒绝访问,它不会抛出异常,它只是发送 HTTP 状态。我试过使用 @ExceptionHandler
、AccessDenied 处理程序,但我尝试过的任何方法都无法捕获和处理此异常。下面是堆栈跟踪和其他相关文件,任何想法都会受到赞赏,因为我很困惑。我已尝试在调试中单步执行源代码,但我并没有真正看出问题所在。
堆栈跟踪:
org.springframework.messaging.MessageDeliveryException: Failed to send message to ExecutorSubscribableChannel[clientInboundChannel]; nested exception is org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:127) ~[spring-messaging-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:104) ~[spring-messaging-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.messaging.StompSubProtocolHandler.handleMessageFromClient(StompSubProtocolHandler.java:298) ~[spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.messaging.SubProtocolWebSocketHandler.handleMessage(SubProtocolWebSocketHandler.java:307) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.handler.WebSocketHandlerDecorator.handleMessage(WebSocketHandlerDecorator.java:75) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.handler.LoggingWebSocketHandlerDecorator.handleMessage(LoggingWebSocketHandlerDecorator.java:56) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.handler.ExceptionWebSocketHandlerDecorator.handleMessage(ExceptionWebSocketHandlerDecorator.java:58) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.delegateMessages(AbstractSockJsSession.java:382) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.sockjs.transport.session.WebSocketServerSockJsSession.handleMessage(WebSocketServerSockJsSession.java:193) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.sockjs.transport.handler.SockJsWebSocketHandler.handleTextMessage(SockJsWebSocketHandler.java:92) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.handler.AbstractWebSocketHandler.handleMessage(AbstractWebSocketHandler.java:43) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.handleTextMessage(StandardWebSocketHandlerAdapter.java:110) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.access$000(StandardWebSocketHandlerAdapter.java:42) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$3.onMessage(StandardWebSocketHandlerAdapter.java:81) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$3.onMessage(StandardWebSocketHandlerAdapter.java:78) [spring-websocket-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:399) [tomcat-embed-websocket-8.5.6.jar:8.5.6]
at org.apache.tomcat.websocket.server.WsFrameServer.sendMessageText(WsFrameServer.java:106) [tomcat-embed-websocket-8.5.6.jar:8.5.6]
at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:500) [tomcat-embed-websocket-8.5.6.jar:8.5.6]
at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:295) [tomcat-embed-websocket-8.5.6.jar:8.5.6]
at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:131) [tomcat-embed-websocket-8.5.6.jar:8.5.6]
at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:69) [tomcat-embed-websocket-8.5.6.jar:8.5.6]
at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.upgradeDispatch(WsHttpUpgradeHandler.java:148) [tomcat-embed-websocket-8.5.6.jar:8.5.6]
at org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:54) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:53) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:802) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1410) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.6.jar:8.5.6]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_101]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_101]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.6.jar:8.5.6]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_101]
Caused by: org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233) ~[spring-security-core-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor.preSend(ChannelSecurityInterceptor.java:71) ~[spring-security-messaging-4.0.2.RELEASE.jar:4.0.2.RELEASE]
at org.springframework.messaging.support.AbstractMessageChannel$ChannelInterceptorChain.applyPreSend(AbstractMessageChannel.java:158) ~[spring-messaging-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:113) ~[spring-messaging-4.3.5.RELEASE.jar:4.3.5.RELEASE]
... 30 common frames omitted
安全配置:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserProfileService userProfileService;
@Autowired
private CustomAccessDeniedHandler accessDeniedHandler;
@Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userProfileService);
auth.authenticationProvider(authenticationProvider());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userProfileService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**", "/javascript/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http .httpBasic()
.and()
.authorizeRequests()
.antMatchers("/", "/index.html", "/home.html", "/getLatestPost", "/application-socket-conn/**").permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler).and()
.csrf().disable();
}
}
网络套接字配置:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
//Javascript connection subscribes to this URI
config.enableSimpleBroker("/main-page-feed");
//STOMP messages are sent to this URI + suffix
config.setApplicationDestinationPrefixes("/thought-bubble");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
//URI used for SockJS connection
registry.addEndpoint("/application-socket-conn").withSockJS();
}
}
自定义 AccessDenied 处理程序(未捕获它):
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Autowired
@Qualifier("clientOutboundChannel")
private MessageChannel clientOutboundChannel;
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
Message<String> message = new Message<String>() {
@Override
public String getPayload() {
return "Access denied.";
}
@Override
public MessageHeaders getHeaders() {
return null;
}
};
clientOutboundChannel.send(message);
}
}
网络套接字 Controller
@RestController
public class WebSocketController {
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/push-to-queue")
public void pushThoughtToQueue(@Payload ThoughtEntity entity) throws Exception {
Date today = new Date(Calendar.getInstance().getTimeInMillis());
entity.setPostDate(today);
entity.setFavoriteCount(0);
this.simpMessagingTemplate.convertAndSend("/main-page-feed/thought-queue", entity);
}
}
我认为 AffirmativeBased
是被抛出的类,但我不确定为什么,或者为什么普通(非网络套接字)spring security 在拒绝访问时不这样做到某事。就像我说的,它拒绝访问是正确的,但它会抛出运行时异常并通过 websocket 将丑陋的堆栈跟踪发送回客户端。
更新:
我已经意识到无论用户是否登录都会抛出异常,所以我认为这是一个不同的问题。就像我说的,我没有为这个应用程序使用 ROLE
,我认为这与它有关。我目前正在研究匿名角色,因为我认为这与正在发生的事情有关。
最佳答案
您的 websocket 客户端代码似乎没有发送授权信息。通常默认情况下不会处理它,您应该创建自己的方式来连接安全性。
在我的例子中,我使用的是 oauth 授权,并且必须指定特定的 header Authorization : Bearer _uuid_token_
,这是在 stompClient 连接期间指定的。
查看此代码段以获得总体思路。 (我正在使用 AngularJS)
(function() {
'use strict';
/* globals SockJS, Stomp */
angular
.module('myApp')
.factory('global_WebSocket', GlobalWebSocketClient);
GlobalWebSocketClient.$inject = ['$window', 'localStorageService', '$q'];
function GlobalWebSocketClient($window, localStorageService, $q) {
var connected = $q.defer();
var established = {established: false} ;
var loc = $window.location;
var url = loc.protocol + '//' + loc.host + loc.pathname + 'websocket';
var token = localStorageService.get('token');
if (token && token.expires_at && token.expires_at > new Date().getTime()) {
url += '?access_token=' + token.access_token;
} else {
url += '?access_token=no token';
}
/*jshint camelcase: false */
var socket = new SockJS(url);
/*jshint camelcase: false */
var stompClient = Stomp.over(socket);
var headers = {
Authorization : 'Bearer ' + token.access_token,
};
stompClient.debug = null;
var establishConnection = function() {
stompClient.connect(headers, function() {
established.established = true;
connected.resolve('success');
}, function(error) {
console.log("ERROR CONNECTNG!");
console.log(error.headers);
establishConnection();
});
};
establishConnection();
return {
connected: connected,
client: stompClient,
established: established
};
}
})();
如你所见,这段代码在构造url时添加了access_token,并指定了Authorization headers,这些Authorization headers是之前建立的,已经存储在localStorageService
中。我猜您假设您的客户端默认发送 header ,但使用 sockjs 时并非如此。
然后我可以创建这样的客户端服务
(function() {
'use strict';
/* globals SockJS, Stomp */
angular
.module('myApp')
.factory('synchronization_Status', SynchronizationFileTrackerService);
SynchronizationFileTrackerService.$inject = ['global_WebSocket'];
function SynchronizationFileTrackerService (global_WebSocket) {
var stompClient = global_WebSocket;
var subscriber = {} ;
return {
subscribe: subscribe,
unsubscribe: unsubscribe
};
function unsubscribe(target) {
if (subscriber[target]) {
subscriber[target].unsubscribe();
}
};
function subscribe(forTarget, handler) {
if (stompClient.established.established) {
subscriber[forTarget] = stompClient.client.subscribe('/synchronization/status/' + forTarget, function(data) {
data = angular.fromJson(data.body);
handler(angular.fromJson(data));
});
} else {
stompClient.connected.promise.then(
function() {
subscriber[forTarget] = stompClient.client.subscribe('/synchronization/status/' + forTarget, function(data) {
data = angular.fromJson(data.body);
handler(angular.fromJson(data));
});
}, null, null);
}
}
}
})();
并在我的 UI 代码中重用此类服务,就像这样简单:
synchronization_Status.subscribe(ctrl.id, funciton(response){ctrl.currentStatus = response} );
关于java - Spring Websocket 安全抛出 AccessDeniedException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41924104/
来自 java docs 公共(public) FileWriter(String fileName) 抛出 IOException 抛出: IOException - 如果指定的文件存在但它是目录而
我使用以下代码将我的 .net 客户端(基于 CQL)连接到 3 节点 Cassandra 集群。我以 30 条记录/秒的速度(从 RabbitMQ)获取数据,并且它们顺利地存储在 cassandra
如果在读取文件时缺少字段,我应该捕获 NoSuchElementException。如果缺少一个字段,我只需要跳到文件的下一行。我的问题是,我在哪里实现我的 try/catch 代码来做到这一点?这是
我正在尝试使用 ASP.NET MVC 实现 OpeinID 登录。我正在尝试按照 http://blog.nerdbank.net/2008/04/add-openid-login-support-
学习使用 Java 进行 xml 解析,并且正在编写一个测试程序来尝试各种东西。所有测试 System.out.println() 都是我在控制台中所期望的,除了 childElement 返回 [n
我正在尝试使用 SwingUtilities 创建 JFrame Thread tt = new Thread(new Runnable() { public void run
关闭。这个问题是not reproducible or was caused by typos .它目前不接受答案。 这个问题是由于错别字或无法再重现的问题引起的。虽然类似的问题可能是on-topi
我写了这段代码: MethodInfo method2 = typeof(IntPtr).GetMethod( "op_Explicit", Bind
我开始学习 Java,并且正在根据书本做一些练习。在执行此操作时,我遇到了以下错误:线程“main”java.util.InputMismatchException 中出现异常。我正在编写一个简单的程
我有一个文本文件,其中前两行是整数 m 和 n,然后有 m 行,每行都有 n 管道分隔值。我编写了一个程序,读取文件并使用文件中的值创建 m*n 数组,它工作了无数次,然后突然,使用相同的代码,使用相
所以我尝试使用在另一个类中生成的 bean 以在主应用程序中使用 package com.simon.spring.basics.properties; import org.spri
我还没有完成这个应用程序,但我希望在我的手机上看到它的样子。但是,它会强制关闭并引发 InstantiationException。 logcat 异常: 09-19 20:13:47.987: D/
我想从 UIViewController 加载一个基于 SwiftUI 的 View ,该 View 读取包本地的 json。仅 swiftUI 项目中的代码和绑定(bind)工作正常,当我利用 UI
'java.net.SocketTimeoutException:连接超时' 循环一段时间后我收到此错误。为什么我会收到 SocketTimeoutException?我该如何修复这个错误? @Ove
当有 null 值时抛出 ArgumentNullException() 是个好主意吗? This thread 没有提到在 null 上抛出的最明显的异常。 谢谢 最佳答案 ArgumentNull
我得到这个异常: NullReferenceException Object reference not set to an instance of an object at Namespace
所以其中一个方法的描述如下: public BasicLinkedList addToFront(T data) This operation is invalid for a sorted list
我正在使用 Intellij Idea,当我去生成 JavaDocs(通过工具 -> 生成 JavaDoc)时,我抛出了一个 IllegealArgumentException,没有关于发生了什么问题
我正在学习 C++ 中的互斥锁,但以下代码(摘自 N. Josuttis 的“C++ 标准库”)有问题。 我不明白为什么它会阻塞/抛出除非我在主线程中添加this_thread::sleep_for(
我正在试验 JavaFX 标签和组,通过鼠标拖动将它们移动到屏幕上。新节点从一些线程添加到动画组。但是,有时我会突然看到以下异常 - 我假设,当某些节点重叠时。但是不知道是什么问题……因为不涉及我的代
我是一名优秀的程序员,十分优秀!