2 Stimmen

ASP.NET: Wo kann ich eine schnelle benutzerdefinierte Mitgliedschaft Anbieter finden

Gibt es irgendwelche benutzerdefinierten asp.net-Mitgliedschaft Anbieter, die jemand bereits online erstellt hat. Ich möchte einen benutzerdefinierten Anbieter verwenden, weil ihr Rollenanbieter sehr träge ist und ich Ganzzahlen anstelle von Guids für Benutzer-IDs verwenden möchte

4voto

Morten Mertner Punkte 9284

Es kann keine alternativen Implementierungen der Standard-API für Mitgliedschaftsanbieter geben, da sie auf nicht-generischen Schnittstellen basiert.

In der Praxis bringt die gesamte Mitgliedschafts-API jedoch nur einen sehr geringen Mehrwert, und es ist recht einfach, eine eigene Lösung zu entwickeln.

Um Ihnen den Einstieg zu erleichtern, sind hier einige der Hilfsklassen aufgeführt, die ich normalerweise verwende.

Zunächst etwas Code zum Umgang mit Cookies und Forms-Authentifizierung:

public interface ISecurityPersistenceProvider
{
    void SetAuthCookie( int version, string name, DateTime expireDate, bool persistent, string cookieData );
    HttpCookie GetAuthCookie();
    string GetAuthCookieValue( out string name );
    void RemoveAuthCookie();
}

public class FormsPersistenceProvider : ISecurityPersistenceProvider
{
    public void SetAuthCookie( int version, string name, DateTime expireDate, bool persistent, string cookieData )
    {
        var ticket = new FormsAuthenticationTicket( version, name, DateTime.Now, expireDate, persistent, cookieData );
        string secureTicket = FormsAuthentication.Encrypt( ticket );
        var cookie = new HttpCookie( FormsAuthentication.FormsCookieName, secureTicket );
        cookie.Expires = ticket.Expiration;
        HttpContext.Current.Response.Cookies.Add( cookie );
    }

    public HttpCookie GetAuthCookie()
    {
        HttpCookie cookie = HttpContext.Current.Request.Cookies[ FormsAuthentication.FormsCookieName ];
        return cookie;
    }

    public string GetAuthCookieValue( out string name )
    {
        HttpCookie cookie = GetAuthCookie();
        FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt( cookie.Value );
        name = ticket.Name;
        return ticket.UserData;
    }

    public void RemoveAuthCookie()
    {
        FormsAuthentication.SignOut();
    }
}

Zweitens, etwas Code zur Überprüfung von Benutzern anhand eines Datenspeichers. Sie müssen Ihre eigene Implementierung für diese Schnittstelle bereitstellen (und/oder sie an Ihre Bedürfnisse anpassen).

public interface ISecurityUserProvider<T> where T : class
{
    T AuthenticateUser( string customer, string userName, string passwordHash );
    T GetUser( string customer, string userName );
    string[] GetRoles( T user );
}

Drittens eine Klasse, mit der wir zusätzliche Informationen an den Aufrufer zurückgeben können (diese wird von der Klasse SecurityManager weiter unten verwendet):

public class AuthenticationResult
{
    #region Fields/Properties
    public bool Success { get; internal set; }
    public string Message { get; internal set; }
    public IDictionary<string,string> Errors { get; internal set; }
    #endregion

    #region Constructors
    public AuthenticationResult( bool success, string message ) : this( success, message, null )
    {
    }
    public AuthenticationResult( bool success, string message, IDictionary<string, string> errors )
    {
        Success = success;
        Message = message;
        Errors = errors ?? new Dictionary<string, string>();
    }
    #endregion
}

Ich verwende auch eine benutzerdefinierte Principal-Klasse, die es mir ermöglicht, ein benutzerdefiniertes Objekt mit der grundlegenden IPrincipal-Implementierung zu verknüpfen. Dies ist nur ein kurzer Auszug, um Ihnen die Idee zu vermitteln:

public class CodeworksPrincipal<TUserData> : IPrincipal where TUserData : class
{
    private string name;
    private string[] roles;
    private string allRoles;
    private TUserData userData;

    public CodeworksPrincipal( string name, string[] roles, TUserData userData )
    {
        // init fields, etc.
    }
}

Und schließlich die Klasse SecurityManager, die den Großteil der Logik enthält:

public class SecurityManager<T,TPersistenceProvider,TUserProvider> 
    where T : class
    where TPersistenceProvider : ISecurityPersistenceProvider
    where TUserProvider : ISecurityUserProvider<T>
{
    private readonly ISecurityPersistenceProvider persistenceProvider;
    private readonly ISecurityUserProvider<T> userProvider;
    // NOTE this constant is used to validate the validity of the cookie (see below)
    private const int CookieParameterCount = 3;

    public SecurityManager( ISecurityPersistenceProvider persistenceProvider, ISecurityUserProvider<T> userProvider )
    {
         this.persistenceProvider = persistenceProvider;
         this.userProvider = userProvider;
    }

    #region Properties
    protected ISecurityPersistenceProvider PersistenceProvider
    {
        get { return persistenceProvider; }
    }
    protected ISecurityUserProvider<T> UserProvider
    {
        get { return userProvider; }
    }
    public IIdentity CurrentIdentity
    {
        get { return Thread.CurrentPrincipal.Identity; }
    }
    public bool IsAuthenticated
    {
        get
        {
            IPrincipal principal = Thread.CurrentPrincipal;
            return principal != null && principal.Identity != null && principal.Identity.IsAuthenticated;
        }
    }
    public bool IsInRole( string roleName )
    {
        IPrincipal principal = Thread.CurrentPrincipal;
        return IsAuthenticated && principal.IsInRole( roleName );
    }
    public string UserName
    {
        get { return IsAuthenticated ? CurrentIdentity.Name : ""; }
    }
    #endregion

    #region Authentication
    public AuthenticationResult Authenticate( string userName, string password, bool persistent, string visitorAddress )
    {
        return Authenticate( null, userName, password, persistent, visitorAddress );
    }
    public AuthenticationResult Authenticate( string customer, string userName, string password, bool persistent, string visitorAddress )
    {
        AuthenticationResult result = ValidateInput( userName, password );
        if( ! result.Success )
            return result;
        string passwordHash = GetCryptographicHash( password );
        T user = userProvider.AuthenticateUser( customer, userName, passwordHash );
        if( user == null )
            return new AuthenticationResult( false, "Unable to login using the specified credentials.", null );
        if( ! IsAuthorizedVisitor( user, visitorAddress ) )
            return new AuthenticationResult( false, "Credentials do not allow login from your current IP address.", null );
        CurrentPrincipal = new CodeworksPrincipal<T>( userName, userProvider.GetRoles( user ), user );
        // remember to change CookieParameterCount if you change parameter count here
        string cookieData = String.Format( "{0}|{1}|{2}", CurrentIdentity.Name, customer, CurrentPrincipal.AllRoles );
        persistenceProvider.SetAuthCookie( 1, userName, DateTime.Now.AddMonths( 1 ), persistent, cookieData );
        // TODO create an audit log entry for the current request
        return new AuthenticationResult( true, null, null );
    }
    private AuthenticationResult ValidateInput( string login, string password )
    {
        var result = new AuthenticationResult( true, "Invalid or missing credentials." );
        if( String.IsNullOrEmpty( login ) )
        {
            result.Success = false;
            result.Errors.Add( "login", "You must specify an alias or email address." );
        }
        if( String.IsNullOrEmpty( password ) )
        {
            result.Success = false;
            result.Errors.Add( "password", "You must specify a password." );
        }
        // TODO add message to inform users of other requirements.
        return result;            
    }
    #endregion

    #region Cookie Authentication
    public void CookieAuthenticate( string visitorAddress )
    {
        HttpCookie cookie = persistenceProvider.GetAuthCookie();
        if( cookie != null )
        {
            string userName;
            string userData = persistenceProvider.GetAuthCookieValue( out userName );
            string[] cookieData = userData.Split( '|' );
            // extract data from cookie
            bool isValid = cookieData.Length == CookieParameterCount && 
                           ! string.IsNullOrEmpty( cookieData[ 0 ] ) &&
                           cookieData[ 0 ] == userName &&
                           IsAuthorizedVisitor( cookieData[ 1 ], cookieData[ 0 ], visitorAddress );
            if( isValid )
            {
                string customer = cookieData[ 1 ];
                string[] roles = cookieData[ 2 ].Split( ',' );
                T user = userProvider.GetUser( customer, userName );

                CurrentPrincipal = new CodeworksPrincipal<T>( userName, roles, user );
            }
        }
    }
    #endregion

    #region Logout
    public void Logout()
    {
        // logout the current user
        if( HttpContext.Current.Request.IsAuthenticated || CurrentPrincipal != null )
        {
            long address = GetAddressFromString( HttpContext.Request.UserHostAddress );
            // TODO add audit log entry
            // sign out current user
            persistenceProvider.RemoveAuthCookie();
            CurrentPrincipal = null;
        }
    }
    #endregion

    #region VisitorAddress Checks
    public long GetAddressFromString( string address )
    {
        IPAddress ipAddress;
        if( IPAddress.TryParse( address, out ipAddress ) )
        {
            byte[] segments = ipAddress.GetAddressBytes();
            long result = 0;
            for( int i = 0; i < segments.Length; i++ )
            {
                result += segments[ i ] << (i * 8);
            }
            return result;
        }
        return long.MaxValue;
    }

    public bool IsAuthorizedVisitor( string customer, string userName, string visitorAddress )
    {
        return IsAuthorizedVisitor( customer, userName, GetAddressFromString( visitorAddress ) );
    }

    public bool IsAuthorizedVisitor( string customer, string userName, long visitorAddress )
    {
        T user = userProvider.GetUser( customer, userName );
        return IsAuthorizedVisitor( user, visitorAddress );
    }

    public bool IsAuthorizedVisitor( T user, string visitorAddress )
    {
        return IsAuthorizedVisitor( user, GetAddressFromString( visitorAddress ) );
    }

    public bool IsAuthorizedVisitor( T user, long visitorAddress )
    {
        if( user == null || visitorAddress == 0 )
            return false;
        if( user.Hosts.Count == 0 )
            return true;
        foreach( Host host in user.Hosts )
        {
            if( IsAuthorizedVisitor( host.HostAddress, host.HostMask, visitorAddress ) )
                return true;
        }
        return true;
    }

    public bool IsAuthorizedVisitor( long allowedAddress, long allowedMask, long visitorAddress )
    {
        long requireMask = allowedAddress & allowedMask;
        return (visitorAddress & requireMask) == requireMask;
    }
    #endregion

    #region Cryptographic Helpers
    public static string GetCryptographicHash( string password )
    {
        SHA256 hash = SHA256.Create();
        byte[] input = Encoding.UTF8.GetBytes( password );
        byte[] output = hash.ComputeHash( input );
        return Convert.ToBase64String( output );
    }
    #endregion
}

Sie können die Bits zur Überprüfung der Host-Adresse des Besuchers entfernen, wenn Sie sie nicht benötigen.

Ich hoffe, das hilft, auch wenn es sich nicht um einen Mitgliedschaftsanbieter per se handelt ;-)

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