我有一個帶有 Angular 13 后端的 .net 6 后端,它使用 JWT 令牌進行身份驗證。出于某種原因,SignalR 總是回退到長輪詢,無論是在產品還是在開發機器上,它似乎呼叫了協商?negotiateVersion=1 是成功的,它選擇了 WebSockets,但之后它呼叫了 localhost:PORT/hubs/myhub? id=[ID]&access_token=[JWTTOKEN] 回傳 401。
Angular部分是使用NGRX獲取JWT令牌,5分鐘后JWT令牌過期。當它在連接建立后收到 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 }))
);
}
services.AddSignalR();
在 .net下的 Startup 我ConfigureServices
有
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<NotificationHub>("/hubs/notificationhub");
});
在Configure
我的 Hub 有一個[Authorize]
屬性。
uj5u.com熱心網友回復:
您可能沒有處理 access_token 查詢字串引數。這在使用 WebSocket 時是必需的,因為 WebSocket 的瀏覽器 API 不支持設定標頭。
檔案解釋了如何處理查詢字串 https://learn.microsoft.com/aspnet/core/signalr/authn-and-authz?view=aspnetcore-7.0#built-in-jwt-authentication
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/530938.html
上一篇:OracleSQL-將列的資料默認值更改為NULL-NULL和(null)之間有什么區別嗎?
下一篇:GithubActions無法將AspDotNetCoreMVC6.0部署到AzureAppServiceLinux但顯示部署成功