Question

Comment puis-je créer un abonnement personnalisé pour ASP.NET MVC 2 basé sur le fournisseur d'appartenances ASP.NET?

Était-ce utile?

La solution

J'ai créé un nouveau projet contenant un fournisseur d'appartenances personnalisé et la méthode de l'emportait sur ValidateUser de la MembershipProvider classe abstraite:

public class MyMembershipProvider : MembershipProvider
{ 
    public override bool ValidateUser(string username, string password)
    {    
        // this is where you should validate your user credentials against your database.
        // I've made an extra class so i can send more parameters 
        // (in this case it's the CurrentTerritoryID parameter which I used as 
        // one of the MyMembershipProvider class properties). 

        var oUserProvider = new MyUserProvider();  
        return oUserProvider.ValidateUser(username,password,CurrentTerritoryID);
    }
}

Alors je connecté ce fournisseur à mon ASP.NET MVC 2 projet en y ajoutant une référence et indiquant de mon web.config:

<membership defaultProvider="MyMembershipProvider">
    <providers>
        <clear />
        <add name="MyMembershipProvider"
            applicationName="MyApp"
            Description="My Membership Provider"
            passwordFormat="Clear"
            connectionStringName="MyMembershipConnection"
            type="MyApp.MyMembershipProvider" />
    </providers>
</membership>

J'ai besoin de créer une classe personnalisée qui hérite de la classe abstraite RoleProvider et redéfinit la méthode GetRolesForUser. Le ASP.NET MVC utilise cette méthode Ordonnateur pour savoir quels rôles sont attribués au courant utilisateur connecté et veille à ce que l'utilisateur est autorisé à accéder l'action du contrôleur.

Voici les mesures que nous devons prendre:

1) Créer une classe personnalisée qui hérite de la classe abstraite RoleProvider et redéfinit la méthode GetRolesForUser:

public override string[] GetRolesForUser(string username)
{
    SpHelper db = new SpHelper();
    DataTable roleNames = null;
    try
    {
        // get roles for this user from DB...

        roleNames = db.ExecuteDataset(ConnectionManager.ConStr,
                    "sp_GetUserRoles",
                    new MySqlParameter("_userName", username)).Tables[0];
    }
    catch (Exception ex)
    {
        throw ex;
    }
    string[] roles = new string[roleNames.Rows.Count];
    int counter = 0;
    foreach (DataRow row in roleNames.Rows)
    {
        roles[counter] = row["Role_Name"].ToString();
        counter++;
    }
    return roles;
}

2) Branchez le fournisseur de rôle avec l'application ASP.NET MVC 2 via notre web.config:

<system.web>
...

<roleManager enabled="true" defaultProvider="MyRoleProvider">
    <providers>
        <clear />
        <add name="MyRoleProvider"
            applicationName="MyApp"
            type="MyApp.MyRoleProvider"
            connectionStringName="MyMembershipConnection" />
    </providers>
</roleManager>

...
</system.web>

3) Réglez le Authorize (rôles = "xxx, yyy") au-dessus du contrôleur voulait / Action:

[Authorization(Roles = "Customer Manager,Content Editor")]
public class MyController : Controller
{
    ...... 
}

Ca y est! Maintenant, ça marche!

4) En option: définir un attribut Authorize personnalisé afin que nous puissions rediriger un rôle indésirable à un AccessDenied Page:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class MyAuthorizationAttribute : AuthorizeAttribute
{
    /// <summary>
    /// The name of the master page or view to use when rendering the view on authorization failure.  Default
    /// is null, indicating to use the master page of the specified view.
    /// </summary>
    public virtual string MasterName { get; set; }

    /// <summary>
    /// The name of the view to render on authorization failure.  Default is "Error".
    /// </summary>
    public virtual string ViewName { get; set; }

    public MyAuthorizationAttribute ()
        : base()
    {
        this.ViewName = "Error";
    }

    protected void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)
    {
        validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));
    }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException("filterContext");
        }

        if (AuthorizeCore(filterContext.HttpContext))
        {
            SetCachePolicy(filterContext);
        }
        else if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            // auth failed, redirect to login page
            filterContext.Result = new HttpUnauthorizedResult();
        }
        else if (filterContext.HttpContext.User.IsInRole("SuperUser"))
        {
            // is authenticated and is in the SuperUser role
            SetCachePolicy(filterContext);
        }
        else
        {
            ViewDataDictionary viewData = new ViewDataDictionary();
            viewData.Add("Message", "You do not have sufficient privileges for this operation.");
            filterContext.Result = new ViewResult { MasterName = this.MasterName, ViewName = this.ViewName, ViewData = viewData };
        }
    }

    protected void SetCachePolicy(AuthorizationContext filterContext)
    {
        // ** IMPORTANT **
        // Since we're performing authorization at the action level, the authorization code runs
        // after the output caching module. In the worst case this could allow an authorized user
        // to cause the page to be cached, then an unauthorized user would later be served the
        // cached page. We work around this by telling proxies not to cache the sensitive page,
        // then we hook our custom authorization code into the caching mechanism so that we have
        // the final say on whether a page should be served from the cache.
        HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
        cachePolicy.SetProxyMaxAge(new TimeSpan(0));
        cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);
    }
}

Maintenant, nous pouvons utiliser notre propre attribut fait pour rediriger nos utilisateurs d'accéder vue refusée:

[MyAuthorization(Roles = "Portal Manager,Content Editor", ViewName = "AccessDenied")]
public class DropboxController : Controller
{ 
    .......
}

Ca y est! Super Duper!

Voici quelques-unes des liens que je l'ai utilisé pour obtenir toutes ces informations:

fournisseur de rôle sur mesure: http://davidhayden.com/blog/dave/archive/2007 /10/17/CreateCustomRoleProviderASPNETRolePermissionsSecurity.aspx

J'espère que cette information aide!

Autres conseils

Il est aussi possible d'utiliser ce avec une quantité beaucoup plus faible de code, je ne suis pas entièrement sûr si cette méthode est aussi sûr, mais fonctionne très bien avec une base de données que vous utilisez.

dans le global.asax

protected void Application_AuthenticateRequest(object sender, EventArgs e)
    {
        if (HttpContext.Current.User != null)
        {
            if (HttpContext.Current.User.Identity.IsAuthenticated)
            {
                if (HttpContext.Current.User.Identity is FormsIdentity)
                {
                    FormsIdentity id =
                        (FormsIdentity)HttpContext.Current.User.Identity;
                    FormsAuthenticationTicket ticket = id.Ticket;

                    // Get the stored user-data, in this case, our roles
                    string userData = ticket.UserData;
                    string[] roles = userData.Split(',');
                    HttpContext.Current.User = new GenericPrincipal(id, roles);
                }
            }
        }
    }

ce que cela fait est qu'il lit les rôles du authcookie qui a été faite à partir FormsAuthenticationTicket

et l'aspect logique d'ouverture de session comme ceci

public class dbService
{
    private databaseDataContext db = new databaseDataContext();

    public IQueryable<vwPostsInfo> AllPostsAndDetails()
    {
        return db.vwPostsInfos;
    }

    public IQueryable<role> GetUserRoles(int userID)
    {
        return (from r in db.roles
                    join ur in db.UsersRoles on r.rolesID equals ur.rolesID
                    where ur.userID == userID
                    select r);
    }

    public IEnumerable<user> GetUserId(string userName)
    {
        return db.users.Where(u => u.username.ToLower() == userName.ToLower());
    }

    public bool logOn(string username, string password)
    {
        try
        {
            var userID = GetUserId(username);
            var rolesIQueryable = GetUserRoles(Convert.ToInt32(userID.Select(x => x.userID).Single()));
            string roles = "";
            foreach (var role in rolesIQueryable)
            {
                roles += role.rolesName + ",";
            }

            roles.Substring(0, roles.Length - 2);
            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
                       1, // Ticket version
                       username, // Username associated with ticket
                       DateTime.Now, // Date/time issued
                       DateTime.Now.AddMinutes(30), // Date/time to expire
                       true, // "true" for a persistent user cookie
                       roles, // User-data, in this case the roles
                       FormsAuthentication.FormsCookiePath);// Path cookie valid for

            // Encrypt the cookie using the machine key for secure transport
            string hash = FormsAuthentication.Encrypt(ticket);
            HttpCookie cookie = new HttpCookie(
               FormsAuthentication.FormsCookieName, // Name of auth cookie
               hash); // Hashed ticket

            // Set the cookie's expiration time to the tickets expiration time
            if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;

            // Add the cookie to the list for outgoing response
            HttpContext.Current.Response.Cookies.Add(cookie);

            return true;
        }
        catch
        {
            return (false);
        }
    }
}

i stocker les rôles dans ma base de données avec deux tables: table: rôle qui a les colonnes: RoleId et roleName et la table: UsersRoles Wich a les colonnes: userID et RoleId, ce qui permet de multiples rôles pour plusieurs utilisateurs et il est facile de faire votre propre logique pour ajouter / supprimer des rôles des utilisateurs et ainsi de suite. Cela vous permet d'utiliser [(Rôles = Authorize « Super administrateur »)] par exemple. espérons que cette aide.

edit: oublié de faire le chèque de mot de passe, mais vous ajoutez juste un si la méthode LOGON qui vérifie si les contrôles prévus nom d'utilisateur et mot de passe et sinon elle retourne false

J'ai utilisé le code source du fournisseur NauckIt.PostgreSQL comme base, et modifié pour l'adapter à mes besoins.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top