我有一个带有角13后端的.net 6后端,它使用JWT令牌作为auth。出于某种原因,localhost:PORT/hubs/myhub?id=ID&access_token=JWTTOKEN总是回到长轮询,无论是在prod上还是在dev机器上,对negotiate?negotiateVersion=1的调用似乎都是成功的,它选择了WebSockets,但之后对negotiate?negotiateVersion=1的调用返回了401。
角度部分使用NGRX获取JWT令牌,JWT令牌在5分钟后过期。当它在连接建立后接收到401时,它断开连接,进行正常的更新调用,并再次与新的JWT令牌连接。然而,即使使用有效的令牌,上面描述的请求也总是返回401。
我的SignalR服务:
export class NotificationSignalrService {
private connection: signalR.HubConnection;
connectionClosedRefreshTokenSubscription: Subscription | undefined;
startConnectionRefreshTokenSubscription: Subscription | undefined;
constructor(@Inject(APP_CONFIG) private appConfig: any, private store: Store) {
this.connection = new signalR.HubConnectionBuilder()
.withUrl(`${this.appConfig.SIGNALR}/hubs/notificationhub`, this.hubConnectionOptions)
.configureLogging(signalR.LogLevel.Debug)
//.withAutomaticReconnect()
.build();
this.connection.onclose(error => {
console.log(`Forbindelse lukket pga: ${error}`);
this.store.dispatch(AuthActions.renewNoLoading());
this.connectionClosedRefreshTokenSubscription = this.store.select(AuthSelectors.selectTokenRefreshed).subscribe({
next: tokenRefreshed => {
if (tokenRefreshed) {
this.connectionClosedRefreshTokenSubscription?.unsubscribe();
this.startSignalRConnection();
}
}
})
});
this.startSignalRConnection();
this.startListening();
}
startSignalRConnection() {
this.connection.start().catch(error => {
console.log(`Der skete en fejl ved start af signalR ${error}`);
this.startConnectionRefreshTokenSubscription = this.store.select(AuthSelectors.selectTokenRefreshed).subscribe({
next: tokenRefreshed => {
if (tokenRefreshed) {
this.startConnectionRefreshTokenSubscription?.unsubscribe();
this.connection.start().catch(error => console.log(`Kunne ikke starte forbindelsen efter renew ${error}`));
}
}
})
});
}
@HostListener('window:beforeunload', ['$event'])
beforeunloadHandler() {
this.connection.stop();
}
protected get hubConnectionOptions(): IHttpConnectionOptions {
// NOTE: The auth token must be updated for each request. So using headers option is not true.
// Also for websockets and some other protocols signalr cannot set auth headers.
// See https://docs.microsoft.com/en-us/aspnet/core/signalr/authn-and-authz?view=aspnetcore-5.0#bearer-token-authentication
return {
/*headers,*/
accessTokenFactory: () => {
return this.store.select(AuthSelectors.getLoggedInToken)
.pipe(take(1), filter(x => x !== null), map(x => x === null ? "" : x)).toPromise();
// this.authService.refreshLogin()
// .pipe(map(_ => this.authService.accessToken)).toPromise();
}
};
// NOTE:
// The access token function you provide is called before every HTTP request made by SignalR. If you need to renew the token in order to keep the connection active (because it may expire during the connection), do so from within this function and return the updated token.
// In standard web APIs, bearer tokens are sent in an HTTP header. However, SignalR is unable to set these headers in browsers when using some transports. When using WebSockets and Server - Sent Events, the token is transmitted as a query string parameter.
}
getAuthToken() {
let token = '';
this.store.select(AuthSelectors.getLoggedInToken).pipe(take(1))
.subscribe(authToken => token = authToken ?? "");
return {
Authorization: `Bearer ${token}`
};
}
startListening() {
this.connection.on("NewNotificationForUser", (notification: NotificationsEntity) =>
this.store.dispatch(NotificationsState.NotificationsActions.newNotification({ notification }))
);
}
在“启动时的.net”中,services.AddSignalR();
在ConfigureServices
下,
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<NotificationHub>("/hubs/notificationhub");
});
在Configure
中
我的集线器有一个[Authorize]
属性。
发布于 2022-11-09 23:40:16
您可能没有处理access_token查询字符串参数。这在使用WebSockets时是必需的,因为WebSockets的浏览器API不支持设置标头。
文档解释了如何处理查询字符串https://learn.microsoft.com/aspnet/core/signalr/authn-and-authz?view=aspnetcore-7.0#built-in-jwt-authentication。
https://stackoverflow.com/questions/74376767
复制相似问题