我有一个在Asp.Net MVC 5 Framework顶部使用c#编写的应用程序。
我使用SignalR 2.2.2在浏览器和服务器之间创建WebSocket通信,将消息从服务器推送到浏览器。
但是,我需要能够为登录用户访问我的ClaimsIdentity
对象,以便我可以确定要播客的消息。
通常,我会像这样访问身份声明
IPrincipal user = System.Web.HttpContext.Current.User
IIdentity identity = user.Identity;
var claims = (IEnumerable<Claim>)identity.Claims;
但是,此行System.Web.HttpContext.Current
返回null;阻止我获取当前登录的用户。
我猜测SignalR会创建一个同步连接,这就是System.Web.HttpContext.Current
为空的原因。
我也尝试使用此SO Question建议的HubCallerContex
,但Context
对象也为空。
System.Web.HttpContextBase httpContext = Context.Request.GetHttpContext();
如何在我的集线器中正确访问用户声明?
我在Web.config中添加了以下密钥到我的appSettings
,因为我正在使用Framework 4.5.1
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
答案 0 :(得分:0)
如果使用SignalR集线器并想在同一集线器下授权方法,则必须使用集线器上的 Authorize 属性。即
[Authorize]
public class MessagingHub: Hub
{
public Task Send(string data)
{
return Clients.Caller.SendAsync("Send", "Data To Send");
}
}
要通过集线器方法(例如上述发送)访问声明或用户身份,则必须具有以下内容:
[Authorize]
public class MessagingHub: Hub
{
public Task Send(string data)
{
var identity = (ClaimsIdentity)Context.User.Identity;
//one can access all member functions or properties of identity e.g, Claims, Name, IsAuthenticated...
return Clients.Caller.SendAsync("Send", "Data To Send");
}
}
如果像我这样使用Json Web令牌(JWT)或仅使用令牌身份验证,那么在客户端,这可以用来调用集线器的Send方法。
注意:就我而言,客户端是Angular 6应用。
import { HubConnection } from "@aspnet/signalr";
import * as signalR from '@aspnet/signalr';
...
private _messagingHubConnection: HubConnection | undefined;
public async: any;
...
constructor(){}
...
SendMessg(): void {
if (this._messagingHubConnection) {
this._messagingHubConnection.invoke('Send');
}
}
...
ngOnInit(){
this._messagingHubConnection= new signalR.HubConnectionBuilder()
.withUrl("messaging", { accessTokenFactory: () => "jwt_token" }) //have a logic that gets the current user's authentication token from the browser
.build();
this._messagingHubConnection.start().then(() => {
this.SendMessg();
}).catch(err => console.error(err.toString()));
if (this._messagingHubConnection) {
this._messagingHubConnection.on('Send', (data: any) => {
//data represents response/message received from Hub method'd return value.
});
}
}
注意:我使用的是.Net Core 2.1,因此请务必注册Hub。 也是假设signalR已经设置
对于.Net Core,请确保您在StartUp.cs中拥有;
services.AddSignalR(); // under ConfigureServices
和
app.UseWebSockets();
app.UseAuthentication();
app.UseSignalR(routes => {
routes.MapHub<LoopyHub>("/messaging");
});
注意:从issues on GitHub for SignalR起,我意识到上述顺序很重要,以防万一任何人遇到任何问题。即根据我的理解,以上顺序是正确的。
从技术上讲,我已经回答了上述问题,但来自.NET Core和Angular上下文;我想大多数(如果不是全部)实现都采用相同的方法。
答案 1 :(得分:0)
你们所有人都会错过一件重要的事情。
与控制器不同,您将无法在Hub内的构造函数中访问声明。连接后即可访问声明。如下所示。
[Authorize]
public class YourHub: Microsoft.AspNetCore.SignalR.Hub
{
public override async Task OnConnectedAsync()
{
...
var identity = (ClaimsIdentity)Context.User.Identity;
}
}