12. juli 2006 - 10:41Der er
26 kommentarer og 2 løsninger
Membership og RoleProvider ?
Hejsa,
Jeg sidder og kigger på de nye providers i .net 2.0 MembershipProviderog RoleProvider. Der har jeg et par spørgsmål til nogle ting i forbindelse med en custom provider jeg vil lave.
1. Kan jeg uden yderligere problemer tilføje felter i min database og gemme ekstra oplysninger som navn, adresse, post nr. osv. ?
2. Set i lyset af ovenstående ville det så være bedre med en ekstra tabel i databasen til disse oplysninger frem for at gemme dem i samme tabel som login oplysninger ?
3. Forud defineret har jeg 4 roles :
Admin : denne kan foretage sig alt på admin siderne. SemiAdmin : denne kan foretage ændringer på admin siderne for et bestemt sprog, men kan ikke slette data. Superbruger : denne kan foretage ændringer på f.eks. et forum, men ikke slette. Bruger : denne kan foretage ændringer for de data denne selv har tilføjet, men ikke slette.
Hvordan styrre jeg når flere roles har adgang til de samme sider men med forskellige rettigheder, nogle kan ændre og slette andre kan ikke. Kan det styrres på link nievau ?
4. Som admin på siden skal der ydermere være mulighed for at kunne oprette roles til en række forskellige forhandlere. disse vil alle sammen få adgang til en bestemt mappe, men igen skal de forskellige roles kunne se forskellige ting ud fra hvilke sider der er tildelt adgang til ved oprettelse af sider ?
Der kommer sikkert flere spørgsmål men disse var blot et par af dem jeg sidder med lige nu, håber der nogen der har den fornøden erfaring med dette og kan hjælpe mig ;o)
3. Forskellige muligheder her.... Dels er der kontroller hvor du vha. templates kan definere hvad der skal vises - baseret på roller. Det kan være anvendeligt hvis du laver dine sider deklerativt. Dels er der et api du kan bruge hvis du vil undersøge noget omkring den aktuelle bruger, hvilket jo så er praktisk hvis du bygger dine sider op dynamisk.
4. Du kan pr. konfiguration give adgang til pr. rolle, så ingen problemer der... Der var så også lidt af svaret under 3.
Spm til 1. Jeg vil kigge nærmere på det med profiles men umiddelbart skal jeg stadigt lave noget kode der opretter, redigere og sletter oplysninger i databasen ikke ?
Spm til 3. Jeg er med på den med at nogle kontroller kan styrres på roles men forklar lige det med templates ? Hvad mener du med at siderne laves deklerativt ? Skal jeg forstå at jeg kan gøre noget i stil med dette :
If Roles.IsUserInRole("bruger") Then '--- laver noget kode der henter links fra database og viser dem '--- der er tildelt bruger role ElseIf Roles.IsUserInRole("admin") Then '--- laver noget kode der henter links fra database og viser dem '--- der er tildelt admin role End If
Spm til 4. Men når dette skal laves fra mine adminsider og ikke direkte i web.config hvordan bære jeg mig så ad der ?
dr_chaos >> Jeg er helt med på at admin rollen skal have adgang til alt/alle sider på hele systemet. Men det er mere set i lyset af jeg laver mine sider dynamisk og ikke fysisk ;o)
I min customroleprovider har jeg en funktion som henter roller til en bruger. Du behøver ikke at have det custom, du skal bare sørger for at en bruger bliver tilknyttet de enkelte roller. Så kan du bruge If Roles.IsUserInRole("bruger") Then osv.
1. Nej - det behøver du ikke... Det du ønsker at have som properties på din profil, angiver du konfigurativt (i web.config). Det dukker op i intellisence når du har gjort det.
3. Du har f.eks. et LogInView, som giver muligheder for at rendere forskelligt afhængigt af brugerens rolle (baseret på templates) - f.eks. sådan her:
<asp:LoginView ID="LoginView1" runat="server"> <RoleGroups> <asp:RoleGroup Roles="Admin"> <ContentTemplate> Admin startside:<br /> </ContentTemplate> </asp:RoleGroup> <asp:RoleGroup Roles="User"> <ContentTemplate> User startside:<br /> </ContentTemplate> </asp:RoleGroup> </RoleGroups> <LoggedInTemplate> Velkommen min ven! </LoggedInTemplate> <AnonymousTemplate> Du er ikke logget ind... Så du får ikke noget at se! </AnonymousTemplate> </asp:LoginView>
Med at siderne laves deklerativt mener jeg, at du skriver det i din markup (altså i din aspx-fil) med <asp:Button ... etc.
Dit eksempel representerer så en dynamisk generering af indhold.
Ok så kommer der lige et par spørgsmål ;o) Når nu jeg normalt benytter mig af at lave en info klasse til fields og properties, en business klasse til at håndtere alt imellem interface og data klasse, en data klasse der håndtere alt trafik frem og tilbage til database, kan jeg så umiddelbart lave en custom membership provider, role provider og profile provider der bygges op på samme måde ?
Det kræver selvfølgelig mere arbejde, men kan jeg have properties i en klasse, business i en anden og data i en tredje ?
Lige umiddelbart ligger måden det er lavet på i frameworket op til at man har det i en og samme klasse.
Du skal override en masse metoder. bla initialize. Her er den sidste custommembership provider jeg brugte: using System.Web.Security; using System.Configuration.Provider; using System.Collections.Specialized; using System; using System.Data; using System.Configuration; using System.Diagnostics; using System.Web; using System.Globalization; using System.Security.Cryptography; using System.Text; using System.Web.Configuration;
/// <summary> /// Summary description for TIMemberShipProvider /// </summary> public sealed class CustomMemberShipProvider : MembershipProvider { private int newPasswordLength = 2; private string eventSource = "CustomMemberShipProvider"; private string eventLog = "Application"; private string exceptionMessage = "An exception occurred. Please check the Event Log."; private string connectionString;
// // Bruges til at bestemme enkryption værdier //
private MachineKeySection machineKey;
// // hvis false vises exceptionsmeddelelsen til brugeren ellers skrives den til //eventlog //
private bool pWriteExceptionsToEventLog;
public bool WriteExceptionsToEventLog { get { return pWriteExceptionsToEventLog; } set { pWriteExceptionsToEventLog = value; } } public override void Initialize(string name, NameValueCollection config) { if (config == null) throw new ArgumentNullException("config"); if (name == null || name.Length == 0) name = "CustomMemberShipProvider";
if (String.IsNullOrEmpty(config["description"])) { config.Remove("description"); config.Add("description", "CustomMemberShipProvider"); } // Initialize the abstract base class. base.Initialize(name, config);
switch (temp_format) { case "Hashed": pPasswordFormat = MembershipPasswordFormat.Hashed; break; case "Encrypted": pPasswordFormat = MembershipPasswordFormat.Encrypted; break; case "Clear": pPasswordFormat = MembershipPasswordFormat.Clear; break; default: throw new ProviderException("Password format not supported."); }
// Get encryption and decryption key information from the configuration. Configuration cfg = WebConfigurationManager.OpenWebConfiguration(System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath); machineKey = (MachineKeySection)cfg.GetSection("system.web/machineKey"); }
// // A helper function to retrieve config values from the configuration file. //
public override bool ChangePassword(string username, string oldPwd, string newPwd) { ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, newPwd, true);
OnValidatingPassword(args);
if (args.Cancel) if (args.FailureInformation != null) throw args.FailureInformation; else throw new MembershipPasswordException("Change password canceled due to new password validation failure.");
/* if (Bruger.SkiftPassword(username, newPwd)) return true; else*/ return false; }
public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer) { throw new Exception("The method or operation is not implemented."); } public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status) { throw new Exception("The method or operation is not implemented."); } public override bool DeleteUser(string username, bool deleteAllRelatedData) { throw new Exception("The method or operation is not implemented."); } // // MembershipProvider.GetAllUsers //
public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords) { throw new Exception("The method or operation is not implemented."); } // // MembershipProvider.GetNumberOfUsersOnline //
public override int GetNumberOfUsersOnline() { throw new Exception("The method or operation is not implemented."); } // // MembershipProvider.GetUser(string, bool) //
public override MembershipUser GetUser(string username, bool userIsOnline) { using (DataSet ds = Bruger.GetBruger().FindBrugerInfoMedBrugerNavn(username)) { try { DataRow dr = ds.Tables[0].Rows[0]; MembershipUser u = new MembershipUser(this.Name, username, dr["BrugerID"], dr["Email"].ToString(), "", "", true, false, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now, DateTime.Now); return u; } catch (Exception e) { WriteToEventLog(e, "GetUser"); return null; } }
} public override MembershipUser GetUser(object providerUserKey, bool userIsOnline) { throw new Exception("The method or operation is not implemented."); } // // MembershipProvider.UnlockUser //
public override bool UnlockUser(string username) { throw new Exception("The method or operation is not implemented."); } // // MembershipProvider.GetUserNameByEmail //
public override string GetUserNameByEmail(string email) { throw new Exception("The method or operation is not implemented."); } // // MembershipProvider.ResetPassword //
public override string ResetPassword(string username, string answer) { throw new Exception("The method or operation is not implemented."); } // // MembershipProvider.UpdateUser //
public override void UpdateUser(MembershipUser user) { throw new Exception("The method or operation is not implemented."); }
public override bool ValidateUser(string username, string password) { Bruger b = Bruger.GetBruger();
public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords) { throw new Exception("The method or operation is not implemented."); } public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords) { throw new Exception("The method or operation is not implemented."); } public override string GetPassword(string username, string answer) { throw new Exception("The method or operation is not implemented."); } // // WriteToEventLog // A helper function that writes exception detail to the event log. Exceptions // are written to the event log as a security measure to avoid private database // details from being returned to the browser. If a method does not return a status // or boolean indicating the action succeeded or failed, a generic exception is also // thrown by the caller. //
private void WriteToEventLog(Exception e, string action) { EventLog log = new EventLog(); log.Source = eventSource; log.Log = eventLog;
string message = "An exception occurred communicating with the data source.\n\n"; message += "Action: " + action + "\n\n"; message += "Exception: " + e.ToString();
For øvrigt kan jeg godt oprette brugeren og logge ind efterfølgende. Problemet ligger i at jeg vil angive et minimum karaktere på 8 som tilsyneladende ikke hentes i min config fil.
Hvis du selv har skrevet provideren (og baseret den på den generelle MemberShipProvider) - er det jo også dig selv der skriver koden til at sikre at adgangskoden overholdet det du har angivet i konfigurationsfilen. Har du noget kode vi kan kigge på hvor du forholder til parameteren? Mvh
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.