2016-06-01 17 views
2

Ich verwende SignalR, um Nachrichten von einem WebAPI-Server-Back-End an eine JavaScript-Webseite weiterzuleiten. Diese Nachrichten werden nur an bestimmte Benutzer weitergeleitet, sodass ich die SignalR ConnectionId mit der benutzerdefinierten ID des Benutzers der Webseite verknüpfen muss.SignalR: Benutzerdefinierte ID bei jedem Anruf empfangen, einschließlich OnConnected

Derzeit verwendet die WebAPI FormsAuthentication und die benutzerdefinierte ID, die ich brauche, befindet sich im Cookie.

Zunächst erbte ich die IUserIdProvider den Wert off des Cookies zu ziehen:

public class CustomIdProvider : IUserIdProvider 
{ 
    public string GetUserId(IRequest request) 
    { 
     Cookie formsAuthCookie = request.Cookies[FormsAuthentication.FormsCookieName]; 

     try 
     { 
      FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(formsAuthCookie.Value); 

      var obj = JsonConvert.DeserializeObject(ticket.Name) as JObject; 

      return (string)obj.GetValue("UserId"); 
     } 
     catch (Exception) 
     { 
      return null; 
     } 
    } 
} 

, die korrekt als immer die individuelle ID, so weit gearbeitet. Aber dieser Wert wurde nie so weit festgelegt, wie ich es beurteilen konnte. Ich konnte auch keine der Identity-Werte aufgrund von Context.User.Identity.Name bearbeiten, die alle nur gelesen wurden.

Bearbeiten: Wenn ich erneut den CustomIdProvider versuche, erhalte ich den Wert korrekt aus dem Cookie, aber OnConnected wird nie aufgerufen, wenn ich von der GetUserId-Methode zurückkomme.

Meine nächste Annäherung basierte auf Shaun Xus Blogpost Set Context User Principal For Customized Authentication In SignalR. Hier ist meine Umsetzung:

public class CustomAuthorizeAttribute : AuthorizeAttribute 
{ 
    private const string CUSTOM_IDENTITY_KEY = "server.User"; 

    public override bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request) 
    { 
     string customId; 

     // This gets the custom id from the cookie. 
     TryGetCustomId(request, out customId); 

     // The CustomIdentity class just sets the customId to the name.  
     request.Environment.Add(CUSTOM_IDENTITY_KEY, new ClaimsPrincipal(new CustomIdentity(customId, true))); 

     return true; 
    } 

    public override bool AuthorizeHubMethodInvocation(IHubIncomingInvokerContext hubIncomingInvokerContext, bool appliesToMethod) 
    { 
     string connectionId = hubIncomingInvokerContext.Hub.Context.ConnectionId; 

     IDictionary<string, object> environment = hubIncomingInvokerContext.Hub.Context.Request.Environment; 

     object obj; 

     environment.TryGetValue(CUSTOM_IDENTITY_KEY, out obj); 

     var principal = obj as ClaimsPrincipal; 

     if (principal?.Identity == null || !principal.Identity.IsAuthenticated) 
     { 
      return false; 
     } 

     hubIncomingInvokerContext.Hub.Context = new HubCallerContext(new ServerRequest(environment), connectionId); 

     return true; 
    } 

und das funktioniert eigentlich die Context.User.Identity richtig eingestellt, wenn beide Methoden aufgerufen werden.

Mein Problem ist jedoch, dass, wenn der Benutzer erstmals verbindet und OnConnected aufgerufen wird, ruft er nicht die AuthorizeHubMethodInvocation und daher die Context.User.Identity nicht in OnConnected.

Ich möchte in allen Phasen des SignalR-Hubs auf die richtige Identität zugreifen können, die meine benutzerdefinierte ID enthält: OnConnected, OnDisconnected und aufgerufene Methoden.

Hat jemand eine gute Lösung dafür?

+0

Wie wäre es statt Speichern von Dingen in der Sitzung speichern Sie sie an anderer Stelle (z. B. Cache oder db) und verwenden Sie die Verbindungs-ID als Sitzungs-ID? Sie können dann den Benutzer vor der Authentifizierung verfolgen und anschließend Metadaten für die Sitzung hinzufügen, sobald Sie diesen Benutzer authentifiziert haben – tommed

Antwort

1

Ich habe einige Kommentare:

1) Sie sollten nicht versuchen, Ihre individuelle Identität in der Berechtigungsstufe zu schaffen. Es sollte das Anliegen der Authentifizierungsstufe sein. Die Implementierung

2) individuelle IUserIdProvider und Festlegung individuelle Identität ID Ihres Context.User.Identity sind getrennten Bedenken. Die benutzerdefinierte IUserIdProvider ist nur Karte eine der Eigenschaften Ihres Context.User.Identity als die Kennung des Benutzers in signalR.

So, um Ihr Problem zu beheben. Versuchen Sie, Ihre benutzerdefinierte ID bei der Authentifizierung einzurichten. Je nachdem, wie Sie Ihre Anwendung einrichten, gibt es viele Möglichkeiten.Zum Beispiel:

1) Aufbau Ihrer benutzerdefinierten Identität id in Application_PostAuthenticateRequest:

protected void Application_PostAuthenticateRequest(Object sender, EventArgs e) 
{ 
    //Provide custom identity id to your HttpContext.Current.User 
    //In your case, you may extract that information from your authentication ticket. 
} 

Sie in diesem Beitrag aussehen könnte, wenn Sie detaillierte Informationen benötigen: ASP.NET MVC - Set custom IIdentity or IPrincipal

2) Unter Verwendung Ansprüche Identität, können Sie zurück Die benutzerdefinierte ID als Anspruch. Jedes Mal, wenn der Browser eine Anfrage an Ihren Server sendet, wird Ihre Anspruchsidentität wiederhergestellt. Im folgenden Beispiel verwende ich die Owin-Cookie-Authentifizierung.

var claims = new List<Claim>(); 
    claims.Add(new Claim(ClaimTypes.Name, user.Id.ToString())); 

    var id = new ClaimsIdentity(claims, "Cookies"); 
    var ctx = Request.GetOwinContext(); 
    var authenticationManager = ctx.Authentication; 
    authenticationManager.SignIn(id); 

Dann in Ihrer IUserIdProvider Implementierung können Sie die entsprechenden Informationen in Ihrer Identität extrahieren (Name Eigenschaft, Anspruch, ...) als Benutzerkennung in Ihrer signalR Anwendung zu verwenden.

Verwandte Themen