403 Запрещено, используя веб -питания с пружинной загрузкойJAVA

Программисты JAVA общаются здесь
Anonymous
403 Запрещено, используя веб -питания с пружинной загрузкой

Сообщение Anonymous »

У меня есть Spring Security с JWT, реализованным в моем приложении, и пытался настроить соединение WebSocket. Первоначально я отправлял токен в заголовках подключения к WebSocket с клиентом Stomp, однако я понял, что безопасность Spring, похоже, обрабатывает аутентификацию по -разному по сравнению с HTTP -запросами. Затем я попытался проверить, чтобы увидеть, смог ли я поднять соединение И работая по мере того, как я устанавливаю разрешение на конечную точку подключения WebSocket в цепочке фильтров, сделав это, я все еще получаю запретную ошибку 403. В настоящее время, если моя цепочка фильтра Spring Security позволяет подключению рукопожатия, соединение должно быть успешным, учитывая, что я уже настроил конфигурацию Spring Security Cors, чтобы принять моего клиента в качестве происхождения. Если бы я обеспечил разрешение подключений к WebSocket для пользователей, но отправка сообщений требует аутентификации, это означает, что мне нужно реализовать пользовательский интерцептор сообщений для проверки моего токена для каждого сообщения или я могу просто расширить конфигуратор AbstractSecurity WebSocketCocketCocecessmessageroker и обеспечить все конечные точки. с /приложением ** аутентифицированы. < /p>
Как бы я провел подлинность последующих запросов по протоколу Stomp? Учитывая, что первоначальное соединение WebSocket отправляется по протоколу HTTP, даже если я должен был включить заголовок авторизации, то не следует автоматически использовать мой фильтр JWT? < /P>
из маленькой документации Там, что я собрал, так это то, что если вы включите токен во время рукопожатия WebSocket, потому что он под протоколом HTTP, ваш сервер сможет проверить токен. Затем это настроило бы принцип, так что теперь вы можете настроить последующие сообщения, которые будут аутентифицированы, внедрив метод configureInbound. Однако, если я позволю рукопожатию не требовать аутентификации, мне нужно будет реализовать пользовательский интерцептор сообщений, который извлекает токен из функции отправки на стороне клиента. Что -то вроде
this.stompclient.send("/app/chat/send ", {" Authorization ":" носитель " + this.token}, json.stringify (сообщение)) < /p>
ниже все код < /p>


import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

/// this method initiates the web socket connection, when a client wants to upgrade their
/// protocol from HTTP to WebSocket
/// . we also define the servers that can make initiate a websocket connection
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {

registry.addEndpoint("/ws")
.setAllowedOriginPatterns("http://localhost:49322")
.withSockJS();
}

/// we define the prefix of the placeholder in the url as 'app' in which this will be binded to the
/// MessageMapping annotation methods, similar to how requestMapping routed the endpoint to the specific method
/// the message broker is used to define the endpoint in which a user will be subscribed to
/// we set the user as the prefix
///
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/user");
registry.setApplicationDestinationPrefixes("/app");
}
}

< /code>

package com.example.Dormly.websocket;

import lombok.RequiredArgsConstructor;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;

@org.springframework.stereotype.Controller
@RequiredArgsConstructor
public class Controller {

private final SimpMessagingTemplate simpMessagingTemplate;
///
/// The @MessageMapping is used to route all /app/placeholder destinations to their specific methods
/// we use the principal to define the user who is the sender, and via a UI action
/// we also include recipient to define who the end user is
/// we create an output message object which contains a sender and the content
/// we then send this output message to the user
/// The message object just has the recipient(to whom we send to) and the content, the sender is fetched from the principal
@MessageMapping("/chat/send")
public void sendMessage(@Payload Message message , @AuthenticationPrincipal UserDetails user){
OutputMessage outputMessage = new OutputMessage(
message.getContent(),
user.getUsername() /// user who sent the message - the recipient will see this
);
/// the server will send back something like '/user/james/queue/chat'
simpMessagingTemplate.convertAndSendToUser(message.getRecipient(),"/queue/chat", outputMessage);

}
}
< /code>

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfiguration {

private final AuthenticationProvider authenticationProvider;
private final JwtAuthFilter jwtAuthFilter;

/**
* Configuration annotation tells spring that there is more than one bean that needs to be instantiated as a singleton
* SecurityFilterChain applies a set of filters to our HTTP requests.
*/

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity.
cors(Customizer.withDefaults())
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(http->http.
requestMatchers("/api/v1/Sign-up").permitAll()
.requestMatchers("/api/v1/login").permitAll()
.requestMatchers("/ws**").permitAll()
.anyRequest()
.authenticated()
)
/**
* ensure our session management remains stateless, as we authenticate once per request
*/

.sessionManagement(session-> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)

)
/**
* when spring security intercepts the login request, the usernamepasswordfilter delegates
* this to the auth manager in which that uses the provider manager impl to find the auth provider.
* The auth provider is called to validate the credentials as it receives an auth object
* Also ensure the jwt filter gets called before the usernamepass filter
* as we always need to check if a JWT is present, if not the request is passed to other filters
* This way we handle requests for unauthenticated and authenticated users
* not authenticated(meaning no jwt) -> UsernamePassFilter gets used
* authenticated(has Jwt) -> jwtAuthFilter
*/

.authenticationProvider(authenticationProvider)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);

return httpSecurity.build();

}
< /code>

import { Injectable } from '@angular/core';
import { TokenService } from '../auth/token/token.service';
import SockJS from 'sockjs-client';
import { Stomp } from '@stomp/stompjs';
import { Message } from '../models/Message';
import { MessagesComponent } from '../messages/messages.component';
import { BehaviorSubject } from 'rxjs';

@Injectable({
providedIn: 'root'
})
export class WebSocketApiService {
//create a subject to communicate the responses back to the messages component
private subject = new BehaviorSubject(null)
messageSubscription$ = this.subject.asObservable()

destination:string = "/user/queue/chat"
brokerURL:string = "http://localhost:8099/ws"
stompClient:any
token!:string

constructor(private tokenService:TokenService) {
this.token = this.tokenService.token as string
}
connect(){
console.log("connecting to websocket...")
const headers = { "Authorization": "Bearer " + this.token };
console.log("WebSocket headers:", headers); // Log the headers

let ws = new SockJS(this.brokerURL)
this.stompClient = Stomp.over(ws)
this.stompClient.connect({"Authorization" : `Bearer ${this.token}`}, () =>{
console.log("WebSocket connected");

///the stompclient takes 3 parameters which includes the headers and 2 callback functions,
///the frames defined the handshake agreement of protocol switches, and once the event occurs we can now subscribe to the destination

this.stompClient.subscribe(this.destination, (message:any)=>{
//the subscribe also triggers a callback which means when a user subscribes to a destination, an event of a message could be returned
this.onMessageRecieved(message)

})

},
///error callback
(error:Error | any)=>{
this.errorCallBack(error)
}
)

}
errorCallBack(error:Error):void{
console.log(error.message)

}

disconnect(){
if(this.stompClient!==null){
this.stompClient.disconnect()
console.log("disconnected")
}
setTimeout(()=>{
this.connect()
},
5000) //reconnect after 5 seconds

}

onMessageRecieved(message:any) {
if(message){
///manual deserialization with websockets. using Json.parse() to convert the json into a javascript objecy
console.log("message recieved ", message)
this.subject.next(JSON.parse(message))
console.log("added message to the subject")
}

}

send(message:Message):void{
///when the user sends a message, our in memory message broker in spring will automatically forward it to the destination the user is subscribed to
///the user will recieve the message immediatley assuming the connection is still live - if not we persist the chat to the db
///all messages are sent with the /app prefix and users are able to send messages
///the message object includes the recieptent and the message itself.
///websocket does not serialize the object into a json like HTTP does, hence we do it manually
this.stompClient.send("/app/chat/send", {"Authorization" : "Bearer " + this.token}, JSON.stringify(message))
}

}
< /code>
Это то, что отображается в консоли в порядке < /p>
[log] Вызов класса службы для подключения к Websocket (main.js, строка 2372) < /p>
[log] подключение к Websocket ... (main.js, строка 2275)
[Warning] Stomp.Over не получила фабрику, Auto Reconnect не будет работать. Пожалуйста, см. > [Log] Открытие веб -сокета ... (@stomp_stompjs.js, строка 1286)
[Debug] [VITE] подключен. (Клиент, строка 859) < /p>
[ошибка] Не удалось загрузить ресурс: сервер ответил статусом 403 () (информация, строка 0) < /p>
[log] соединение закрыто с http: // localhost: 8099/ws (@stomp_stompjs.js, строка 1286)


Подробнее здесь: https://stackoverflow.com/questions/794 ... pring-boot

Вернуться в «JAVA»