2011-09-02 21 views
10

Ok, quindi questo sembra un bisogno comune. Un po 'googling trova molti modi per farlo. Sono interessato al modo più "mvc corretto" per farlo.Come inizializzare le informazioni sull'autorizzazione

Ho, nell'angolo in alto a destra della mia app, un saluto che dice Hello FirstName LastName. Ora, è abbastanza facile ottenere il nome utente dell'utente che ha effettuato l'accesso, tramite lo IPrincipal (ovvero User.Identity.Name). Tuttavia, questo non mi darà il nome e il cognome dell'utente. Devo colpire l'API Membership per ottenere quello.

Il colpire l'API Membership ha i suoi svantaggi. Colpisce il database ogni volta, aggiungendo un ulteriore accesso db a ogni pagina servita. È abbastanza facile impostare alcune variabili di sessione all'accesso, ma questo funziona solo per quella sessione. Se l'utente fa clic su "Ricordami", non verrà eseguito il login la volta successiva e devo ancora caricare questi valori.

  1. Potrei creare il mio provider di appartenenza per fare un po 'di cache, ma questo è un sacco di lavoro per uno scopo più o meno singolo.
  2. Potrei usare Application_AuthenticateRequest e premere l'API di appartenenza e memorizzare i valori nelle variabili di sessione, o qualcosa di simile. Questo è ok, ma sembra una piccola forza bruta.
  3. Potrei registrare un filtro globale e gestire OnAuthenticate, essenzialmente facendo la stessa cosa. Questo sembra un po 'meglio, ma qui sono insolito delle ramificazioni.
  4. Potrei derivare un controller di base e aggiungere similmente le proprietà per fornire queste informazioni. Sembra un po '"vecchia scuola", e odio dover fare una lezione base per un unico scopo.
  5. Potrei creare un metodo statico di cache che otterrebbe le informazioni al primo accesso. Questo non è molto meglio di un singleton.
  6. Potrei anche creare il mio IPrincipal, ma questo significa lanciarlo ogni volta per ottenere i dati, e questo sembra goffo. Potrei avvolgerlo in un'altra classe per semplificarlo, ma comunque ...
  7. Potrei memorizzare i dati nel cookie di autenticazione dei moduli e ottenerli da lì. Ci sono alcuni strumenti disponibili per renderlo più facile.

Ci sono metodi che non ho pensato? E qual è il modo più "corretto in mvc" per farlo?

+0

domanda molto importante anche per me. –

risposta

5

Penso che il modo migliore sia utilizzare i cookie.Ecco la soluzione che ho usato in my project:

Creare una classe per salvare i dati in esso

[DataContract] 
[Serializable()] 
public class AuthData { 

    [DataMember] 
    public String UserName { get; set; } 

    [DataMember] 
    public String FirstName { get; set; } 

    [DataMember] 
    public String LastName { get; set; } 

    [DataMember] 
    public String Email { get; set; } 

    // any other property you need to a light-store for each user 

    public override string ToString() { 
     string result = ""; 
     try { 
      using (MemoryStream stream = new MemoryStream()) { 
       BinaryFormatter formatter = new BinaryFormatter(); 
       formatter.Serialize(stream, this); 
       result = Convert.ToBase64String(stream.ToArray()); 
      } 
     } catch (Exception ex) { 
      throw new HttpException(ex.Message); 
     } 
     return result; 
    } 

    static public AuthData FromString(String data) { 
     AuthData result = null; 
     try { 
      byte[] array = Convert.FromBase64String(data); 
      using (MemoryStream stream = new MemoryStream(array)) { 
       stream.Seek(0, 0); 
       BinaryFormatter formatter = new BinaryFormatter(); 
       result = (AuthData)formatter.Deserialize(stream, null); 
      } 
     } catch (Exception ex) { 
      throw new HttpException(ex.Message); 
     } 
     return result; 
    } 
} 

Signin metodo:

public static bool SignIn(string userName, string password, bool persistent){ 
    if (Membership.ValidateUser(userName, password)) { 
     SetAuthCookie(userName, persistent); 
     return true; 
    } 
    return false; 
} 

Impostazione authCookie:

public static void SetAuthCookie(string userName, bool persistent) { 
    AuthData data = GetAuthDataFromDB(); // implement this method to retrieve data from database as an AuthData object 
    var ticket = new FormsAuthenticationTicket(
     1, 
     userName, 
     DateTime.Now, 
     DateTime.Now.Add(FormsAuthentication.Timeout), 
     persistent, 
     data.ToString(), 
     FormsAuthentication.FormsCookiePath 
     ); 
    string hash = FormsAuthentication.Encrypt(ticket); 
    HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hash); 
    cookie.Expires = DateTime.Now.Add(FormsAuthentication.Timeout); 
    cookie.HttpOnly = false; 
    cookie.Path = FormsAuthentication.FormsCookiePath; 
    HttpContext.Current.Response.Cookies.Add(cookie); 
} 

Ottenere authCookie:

public static AuthData GetAuthCookie() { 
    if (HttpContext.Current.User != null && HttpContext.Current.User.Identity.IsAuthenticated && HttpContext.Current.User.Identity is FormsIdentity) { 
     FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity; 
     FormsAuthenticationTicket ticket = id.Ticket; 
     var data = AuthData.FromString(ticket.UserData); 
     HttpContext.Current.Items["AuthDataContext"] = data; 
     return data; 
    } 
    return null; 
} 

In ControllerBase:

private AuthData _authData; 
private bool _authDataIsChecked; 
public AuthData AuthData { 
    get { 
     _authData = System.Web.HttpContext.Current.Items["AuthDataContext"] as AuthData; 
     if (!_authDataIsChecked && _authData == null) { 
      SignService.GetAuthCookie(); 
      _authData = System.Web.HttpContext.Current.Items["AuthDataContext"] as AuthData; 
      _authDataIsChecked = true; 
     } 
     return _authData; 
    } 
} 
1

Il progetto FormsAuthenticationExtensions risolve questo problema memorizzando le informazioni aggiuntive nel cookie auth stesso. http://formsauthext.codeplex.com/

Questo risparmia il colpo di database e dura fino a quando il cookie di autenticazione, quindi funziona se gli utenti chiedono di "ricordami". Può essere utilizzato allo stesso modo (anche in MVC) come autenticazione standard dei moduli.

Alla tua domanda, qual è il modo più MVCisch: vorrei prima decidere dove voglio mantenere le informazioni. Questa parte della domanda è piuttosto indipendente dal framework MVC in quanto i concetti (sessione, dati post, cookie, ecc.) Sono forniti con o senza di esso.

+0

Sì, mi riferivo all'utilizzo di formsauthext quando ho menzionato gli strumenti per rendere più semplice l'archiviazione nel cookie. –

1

io implementare ed estendere la IPrincipal e IIdentity, in modo che quando si accede User.Identity troverete Nome + Cognome. Questo modo è meglio imo.

Per i miei progetti ho esteso IIdentity e IPrincipal con le mie classi aggiungendo le proprietà di cui ho sempre bisogno "essere lì". Per me non è questo grande lavoro, voglio dire, ci sono solo un sacco di metodi che devono essere implementati.

Per IIdentity i requisiti di interfaccia sono solo AuthenticationType (string), IsAuthenticated (bool) e Name (string).

Mentre in IPrincipal Identity (IIDentity) e IsInRole (boolean)