2 Stimmen

Wie implementiert man ein testbares benutzerdefiniertes ID-basiertes Benutzersystem in ASP.NET MVC unter Verwendung von Forms Authentication?

Ich habe ein Problem, das mich schon seit geraumer Zeit beschäftigt (ich habe es für eine Weile ruhen lassen, aber jetzt, wo ich zurück bin, finde ich immer noch keine Lösung).

Die Einstellung ist wie folgt: Ich verwende nicht die Standardanbieter für Mitgliedschaft, Rollen oder Profile. Vielmehr verwendet meine Anwendung nur OpenID-Login, sie implementiert keine Passwörter. Außerdem verwendet meine Benutzertabelle die ID als Primärschlüssel anstelle des Benutzernamens.

Was die Authentifizierung angeht, so ist die Forms-Authentifizierung großartig, aber für einige Aktionen muss ich die ID des aktuell angemeldeten Benutzers kennen. Dies stellt ein Problem dar, da die Forms-Authentifizierung nur den Namen in der Eigenschaft "User" festlegt (zugänglich innerhalb der Eigenschaft "User" des Controllers, insbesondere in "User.Identity.Name").

Ich würde idealerweise wie etwas wie User.Identity.ID, so dass es innerhalb des Cookies enthalten sein könnte (wenn ich nicht falsch bin), da dies der Primärschlüssel meiner Benutzertabelle ist.

Was ich in der Login-Methode meines AccountControllers verwendet habe, war das folgende hässliche und unordentliche Ding

user = _userRepository.GetByOpenId(identifier);
FormsAuthenticationTicket ticket = 
    new FormsAuthenticationTicket(1, user.DisplayName,
                                  DateTime.Now, 
                                  DateTime.Now.AddDays(10),
                                  false /*rememberMe*/,
                                  user.UserID.ToString());

Und später, als ich die Benutzer-ID abrufen musste:

int loggedUserID = Convert.ToInt32(((FormsIdentity)User.Identity).Ticket.UserData);

Ich im Grunde verschlüsselt die ID in der Forms-Cookie, aber abgesehen davon, dass ich mich schmutzig fühlen, sehe ich nicht, wie diese Einheit zu testen (wie man einen gefälschten Benutzer liefern, wo benötigt, einschließlich andere Controller).

Zusammengefasst habe ich hier also zwei Probleme:

  1. Wie kann man dies einfacher und weniger umständlich gestalten (z. B. indem man etwas als User.Identity.ID oder ähnliches einstellt)?
  2. Wie man es testbar macht (insbesondere, wie man bei Bedarf einen gefälschten Benutzer bereitstellt)

Bitte helfen Sie mir, danke!

EDIT: Gibt es eine Möglichkeit, die Eigenschaft "User.Identity.Name" in "User.Identity.ID" zu ändern oder eine neue Eigenschaft hinzuzufügen, so dass es semantisch Sinn macht?

1voto

David Glenn Punkte 23872

Sie sollten die Taste User.Identity.Name Eigenschaft, um den eindeutigen Bezeichner Ihres Benutzers zu speichern, der in Ihrem Fall die Benutzer-ID und nicht der tatsächliche Name ist.

Sie können die User.Identity durch Erstellung eines neuen GenericPrincipal

var principal = new GenericPrincipal(new GenericIdentity(user.ID.ToString()), user.Roles.ToArray());

1voto

Kenji Kina Punkte 2340

EDIT: Keine Notwendigkeit mehr für dieses Ding nach MVC3's DI-fähigen Controllern und InitializeController des Testhelfers


Ich habe eine Möglichkeit gefunden, eine Aktion zu testen, die von User abhängt, wie in Scott Hanselman's Beitrag .

Zusammenfassend lässt sich sagen, dass Sie einen IPrincipal-Modellbinder wie folgt erstellen:

public class IPrincipalModelBinder : IModelBinder{    
     public object BindModel(ControllerContext controllerContext, 
                             ModelBindingContext bindingContext) {        
          if (controllerContext == null) {            
               throw new ArgumentNullException("controllerContext");        
          }        
          if (bindingContext == null) {            
               throw new ArgumentNullException("bindingContext");        
          }        
          IPrincipal p = controllerContext.HttpContext.User;        
          return p;    
     }
} 

Registrieren Sie dann das Bindemittel in global.asax:

void Application_Start() {    
     RegisterRoutes(RouteTable.Routes); //unrelated, don't sweat this line.             
     ModelBinders.Binders[typeof(IPrincipal)] = new IPrincipalModelBinder();
} 

Jetzt ist es möglich, eine Aktion zu erstellen, die einen IPrincipal als Parameter annimmt:

public ActionResult Edit(int id, IPrincipal user) 

Und geben Sie beim Testen einen gefälschten Benutzer an, so wie hier:

[TestMethod]
public void EditAllowsUsersToEditDinnersTheyOwn()
{
    // Arrange
    DinnersController controller = new DinnersController(new TestDinnerRespository());

    // Act
    IPrincipal FakeUser = new GenericPrincipal(new GenericIdentity("Scott","Forms"),null);
    ViewResult result = controller.Edit(4, FakeUser) as ViewResult;

    // Yada yada yada assert etc etc etc
    Assert.IsTrue(result.ViewName != "InvalidOwner");
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X