2010-11-21 12 views
22

Jak mogę zapisać coś za pomocą FormsAuthentication? Nie chcę przechowywać UserId za pośrednictwem adresów URL.ASP.NET MVC 3 przy użyciu uwierzytelniania

Na przykład, teraz mam ten kod:

//UserController class: 
[HttpPost] 
public ActionResult LogOn(LogOnModel model, string returnUrl) 
{ 
if (ModelState.IsValid) 
{ 
    if (repository.ValidateUser(model.Login, model.Password)) 
    { 
    FormsAuthentication.SetAuthCookie(model.Login, model.RememberMe); 
    if (Url.IsLocalUrl(returnUrl)) 
    { 
     return Redirect(returnUrl); 
    } 
    else 
    { 
     return RedirectToAction("Project", "Index"); 
    } 
    } 
    else 
    { 
    ModelState.AddModelError("", "Incorrect name or password."); 
    } 
} 

return View(model); 
} 

ProjectController klasa:

public ViewResult Index() 
{ 
    return View(repository.GetUserProjects(
     this.ControllerContext.HttpContext.User.Identity.Name)); 
} 

ProjectRepository:

ProjectsContext context = new ProjectsContext(); 
UsersContext uCnt = new UsersContext(); 

public IEnumerable<Project> GetUserProjects(String username) 
{ 
    if (String.IsNullOrEmpty(username)) 
     throw new ArgumentNullException("username", "Login is empty"); 
    return this.uCnt.Users 
       .FirstOrDefault(u => u.Login == username) 
       .Projects 
       .ToList(); 
} 

ProjectController i ProjectRepository nie wygląda dobrego kodu. .. Może ktoś może doradzić, jak przechowywać identyfikator użytkownika bez używania UR L's? Najlepszym sposobem, aby to zrobić, jest zapisywanie identyfikatorów podczas autoryzacji. Nie znaleziono żadnych obiektów w User.Identity to zrobić ...

UPD

błagam o ułaskawienie, ale zapomniałem powiedzieć, że używam MVC-3 z widokiem maszynki. I ten ID użytkownika nie jest ciągiem znaków (User.Identity.Name to ciąg znaków) może to być identyfikator GUID lub może mój własny obiekt ...

Odpowiedz

38

Zapisz UserID w nieruchomości UserData biletu FormsAuthentication w cookie autoryzacji, gdy użytkownik loguje się:

string userData = userID.ToString(); 

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, user.Email, 
    DateTime.Now, DateTime.Now.AddMinutes(FormsAuthentication.Timeout.TotalMinutes), 
    createPersistentCookie, userData); 
string hashedTicket = FormsAuthentication.Encrypt(ticket); 

HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hashedTicket); 
HttpContext.Current.Response.Cookies.Add(cookie); 

Można go odczytać z powrotem w metodzie PostAuthenticateRequest w Global.asax:

HttpCookie formsCookie = Request.Cookies[FormsAuthentication.FormsCookieName]; 

if (formsCookie != null) 
{ 
    FormsAuthenticationTicket auth = FormsAuthentication.Decrypt(formsCookie.Value); 

    Guid userID = new Guid(auth.UserData); 

    var principal = new CustomPrincipal(Roles.Provider.Name, new GenericIdentity(auth.Name), userID); 

    Context.User = Thread.CurrentPrincipal = principal; 
} 

Należy zauważyć, że w tym przypadku, CustomPrincipal wywodzi RolePrincipal (chociaż, jeśli nie używasz ról, myślę, że trzeba czerpać z GenericPrincipal), a po prostu dodaje własność UserID i przeciążeń konstruktora.

Teraz, gdzie potrzebny jest identyfikator użytkownika w aplikacji, można to zrobić:

if(HttpContext.Current.Request.IsAuthenticated) 
    Guid userID = ((CustomPrincipal)HttpContext.Current.User).UserID; 
+2

To robi centy ... Spróbuję to pojutrze. – RAMe0

+0

Pierwsza część, w której zapisano UserId w UserData, wydaje się niekompletna. Czy ktoś może wyjaśnić lub zawinąć ten kod we właściwej klasie, dzięki czemu mogę zobaczyć, gdzie ten kod się znajduje? Dzięki. –

1

Nie jestem pewien, czy poprawnie rozumiem pytanie, ale jeśli masz na myśli do sposobu pobrania tego, kto jest bieżącym użytkownikiem, bez przekazywania go przez URL (np. http://localhost/controller/action?username=RAMe0), możesz sprawdzić, czy w Thread.CurrentPrincipal.Identity.Name lub HttpContext.Current.User

Istnieją subtelne różnice między tymi dwoma jednak. Aby uzyskać więcej informacji, patrz here.

+0

Hmm ... nie mam 'członek Current' w' HttpContext' ... I jeszcze jedno: skąd się wziął 'Current', czy przeładuję stronę? Ale stal nie mam 'Current' w' HttpContext' :( – RAMe0

+0

Upewnij się, że masz odniesienie do System.Web.dll i że góry plików kodu "używa System.Web;" – CRice

+0

Tak, mam to :( – RAMe0

1

Za pomocą FormsAuthentication można zapisać nazwę użytkownika w usłudze User.Identity.Name. Oto prosty przykład tego, czego prawdopodobnie szukasz. (Używając tej samej SetAuth używasz już)

public ViewResult Index() { 
    return View(repository.GetUserProjects(this.User.Identity.Name)); 
} 

ten nie wymaga, aby przejść przez użytkownika w parametrze kwerendy.

+0

Dokładnie to, co robię ... Chcę przechowywać UserID i być może leter som inne informacje, używając SetAuthCookie ... – RAMe0

+0

Używane oryginalne zapisywanie używane metody interfejsu, dlatego też powtórzyłem metodę logowania, przepisałem ją po tym, jak zdałem sobie sprawę, że jesteś FormsService, ale chciałem naprawdę skupić się na drugim bloku, który używa 'ten.User.Identity.Name'. – Buildstarted

+0

Zawsze można przechowywać więcej informacji w 'User.Identity.Name' (jak json, jeśli twoje dane są krótkie) .Możesz także zaimplementować swój własny obiekt' IIdentity' .Chcesz zasadniczo przechowywać wszystkie informacje o użytkowniku w 'User.Identity' ? Trudno jest o powiedz ze swojego pytania. – Buildstarted

5

Po co wykonywać wszystkie połączenia autoryzacyjne za pośrednictwem interfejsu. W ten sposób cały swój kod, który używa uwierzytelniania nie musi się martwić o tym, jak logowanie jest wykonywana, lub w jaki sposób identyfikujący jest przechowywana, itd

public interface IAuthorization 
{ 
    bool ValidateUser(LoginUser u, string password); 
    LoginUser GetCurrentUser(); 
    void LogIn(LoginUser user); 
    void LogOut(); 
    IIdentity GetCurrentUserIdentity(); 
} 

implementacja dla IIdentity GetCurrentUserIdentity może być w dowolny sposób, ale jest powszechnie postrzegane jako wezwanie do „HttpContext.Current.User.Identity”

public class Authorization : IAuthorization 
{ 
    /// <summary> 
    /// Get the IIdentity for the current logged in user 
    /// </summary> 
    /// <returns>IIdentity</returns> 
    public virtual IIdentity GetCurrentUserIdentity() 
    { 
     return HttpContext.Current.User.Identity; 
    } 

    /// <summary> 
    /// Log the user in 
    /// </summary> 
    /// <param name="user">User details</param> 
    public void LogIn(LoginUser user) 
    { 
     InvalidCredentialsOnNullUser(user); 
     FormsAuthentication.SetAuthCookie(user.Name, false); 
    } 

    /// <summary> 
    /// Log the user out 
    /// </summary> 
    public void LogOut() 
    { 
     FormsAuthentication.SignOut(); 
    } 

    private static void InvalidCredentialsOnNullUser(LoginUser user) 
    { 
     if (user == null) 
     { 
      throw new InvalidCredentialException("That user doesn't exist or is not valid."); 
     } 
    } 

    // other methods.... 

} 

Klasa LoginUser widać to informacje, które są pobierane o użytkowniku członkostwa. Zwykle odbywa się to za pośrednictwem MembershipProvider, ale oczywiście można to zrobić na inne sposoby.

public class LoginUser 
{ 
    public string Name; 
    public Guid Key; 
    public string EmailAddress; 
    public bool IsApproved; 
    public bool IsLockedOut; 
    public DateTime CreationDate; 
    public DateTime? LastLoginDate; 
    public DateTime? LastPasswordChangedDate; 
} 
+4

Nie mam pojęcia, dlaczego ktoś chciałby nadal korzystać z dostawcy członkostwa, to jest i było koszmarne odkąd wyszło. Rola własnego auth. – PositiveGuy

+2

To jest dokładnie to, co to jest – CRice

Powiązane problemy