I’ve created a custom MembershipProvider that uses the DotNetNuke.Security.Membership.MembershipProvider as a base. In our implementation, a CRM system stores all contact data for users able to connect to any of our websites, and therefore such functionality as CreateUser and DeleteUser are not implemented. The MembershpProvider only handles authentication, membership and returning a UserInfo object with the CRM system’s data.
This works fine.
The problem I’m running into is with the PersonalizationController. Our CRM system stores information regarding the user/contact, but not regarding the user’s personalization settings. I would like for DNN to continue to store the personalization settings as defined in the PersonalizationController / PersonalizationModule (e.g., in the Profile table). The problem is, when the LoadProfile() stored procedure is called by the DataProvider it fails on an update because the Profile table has a constraint associated with it requiring the UserId to have already been added to the User table. I could modify this Foreign Key relationship but that wouldn’t be good architecture.
So, the question is: What would be a good architecture choice in this situation?
The MembershipProvider and DataProvider follow the Provider Model, so they can be replaced, but I don’t want to replace the DataProvider. The PersonalizationController doesn’t follow the Provider Model and therefore cannot be so easily replaced. Updating the Stored Procedure or the Foreign Key would potentially cause upgrade issues (or at least make debugging years later hard / require good documentation). Likewise with changing the source code (I could simply update the PersonalizationController, line DataProvider.Instance().AddProfile(userId, portalId); with a call to first add the user to the Users table (which should be unnecessary – yes, I understand the difference between the Users and aspnet_Users tables, so theoretically, adding a User record should be OK, albeit superfluous simply because of a Foreign Key. I could also update the MembershipProvider with an insert into the Users table -- this is the direction I'm currently thinking about (although I don't really want to).
Any ideas how I can replace the PersonalizationController using a Provider Model? Or how else I can minimize upgrade or management issues down the line? I’m really trying to build a system where we can at any time install DNN fresh and simply install all our Modules / Providers / Skins on it and replicate the existing system (without content, of course).
What would be the recommended way / recommended architecture in this situation?
Thanks in advance.
Greg
Would it make sense to keep the UserID in the DNN database, so that you can utilize all of those keys that many different modules may have on the Users table. If you don't have userids, it is very likely that you will run into module issues down the line.
The AD provider for DNN creates DNN users, and matches those up to AD users, to get around this issue.
Related
I have a solution with two MVC projects. The first is a management system, the second is a portal for contractors. I want to manage the contractor login of the portal via the main application.
The membership database for both projects is identical in schema (the default). My thought was to hijack the main system's Register action, swap out the connection string, register the contractor user in its' own database, then swap the connection string back to the main one.
I'm guessing this won't work, namely based on the fact that WebSecurity.InitializeDatabaseConnection() can only be called once.
Thus my question: if I want to call the WebSecurity.CreateUserAndAccount() method but point it to a different database than what it was originally initialized for, how would I do so?
I looked at the built-in InitializeSimpleMembership filter for clues, but am not seeing the path I'm looking for.
Is this even a feasible approach?
Alternatively, if I can get the password hashed per the same way it's done by default, it looks like I can enter the required data to the db manually.
It appears I can manually work this out. According to the msdn docs for WebSecurity.CreateUserAndAccount():
This method creates a new entry in the user profile table and then a corresponding entry in the membership table. The ID of the membership entry is based on the ID of the user profile entry. (The IDs of the entries in the two tables match.)
(https://msdn.microsoft.com/en-us/library/webmatrix.webdata.websecurity.createuserandaccount(v=vs.111).aspx)
Inspecting the database schema shows that I only need two tables for this, and the fields are straigtforward.
To hash the password according to the same way the SimpleMembershipProvider does, I can use the System.Web.Helpers.Crypo.HashPassword() method.
This simplifies the basic account creation considerably as I don't have to piggyback off the AccountController and can just write these directly to the db and call it good (for my purposes, anyway, not requiring verification tokens and having seperately handled email notifications). On the portal side, the built-in SimpleMembershipProvider should be able to handle everything as usual.
I am using the latest MVC6 and Entity Framework 7, however I am sure many techniques used in MVC5 and Entity Framework 6 could help answer my question also.
Almost all of the tables in my database have the following 4 fields for auditing: CreatedDate, CreatedBy, ModifiedDate, ModifiedBy.
I am trying to figure out which field from the built in IdentityUser (AspNetUsers table) I should be storing in the CreatedBy field when saving items to the database.
I started by trying to use 'Username' since it is easily accessible by calling User.Identity.Name and passing it down to the repository when saving. Here is how I configured EF using Fluent API to help with retrieving the User who created an item along with all of their fields:
builder.Entity<BlogPost>()
.Property(bp => bp.CreatedBy)
.HasMaxLength(256);
builder.Entity<BlogPost>()
.HasOne(bp => bp.CreatedByUser)
.WithMany()
.HasForeignKey(bp => bp.CreatedBy)
.HasPrincipalKey(u => u.UserName);
But then I noticed that Entity Framework yells when trying to add migrations and create the database because Username needs to be set as a primary key or it can't be used as a foreign key in another table.
Then I got to the point where I figured I would just use the actual Id which is a GUID. The problem with this technique is that the Id of the current logged in user isn't easily available when trying to save: 'User.Identity.Name' is all that is there.
Here are a couple of questions that I would like someone with EF and Auditing experience to try and answer for me:
Do people even use Audit fields in all of their tables anymore? I don't see many others asking questions about this and Microsoft definitely doesn't make it easy to work with their new Identity system and custom audit fields.
Should I be storing Username or Id in my CreatedBy field. Some say this might be preference but I really want to know what direction Microsoft might be pushing with the new Identity. The problem with storing Id is that it is hard to get it when saving and the problem with storing Username is that it isn't a primary key in AspNetUsers table.
I really would just like to know of a good pattern in general when using EF that handles auditing when saving, and retrieving the User and setting it as a Navigation property on my entities that need it when pulling records from the database.
I am trying to figure out which field from the built in IdentityUser
(AspNetUsers table) I should be storing in the CreatedBy field when
saving items to the database.
The user name of the person using the site (on Thread.CurrentPrincipal, accessed in ASP.Net via User.Identity.Name). Who else?
That is the identity of the current authenticated user using your site, and it is what you should be putting in the audit tables.
Do people even use Audit fields in all of their tables anymore? I
don't see many others asking questions about this and Microsoft
definitely doesn't make it easy to work with their new Identity system
and custom audit fields.
Yes, people do! All the time! If you are storing data that can be edited in any way by an end user (whether they are in your company or not), audit it. Always. I was going to say that all enterprises audit stuff to the extreme (and they do), but I even do that on my own personal projects. Metrics are extremely important!
And one important thing to remember is that just because people aren't asking about it on StackOverflow or some other site doesn't mean that it isn't prevalent and critical in our industry.
Should I be storing Username or Id in my CreatedBy field. Some say
this might be preference but I really want to know what direction
Microsoft might be pushing with the new Identity
Microsoft (and the team behind their Identity framework) are doing a great job with providing us a secure and robust security framework. Maybe they would recommend their approach to this problem, but their framework isn't really meant to address those nuances (which can and will differ from system to system). At the end of the day, pick whichever suits the schema of your database. I think most of the time that the Username would be appropriate to store (if it is unique within your system). After all, they both represent the same information (unless your usernames are not unique, which begs further questions).
I really would just like to know of a good pattern in general when
using EF that handles auditing when saving, and retrieving the User
and setting it as a navigation property on my entities that need it
when pulling records from the database.
It is not, and most likely never will be EF's concern to help you with something like this. Sorry, that's just the way it is. Each application is unique, and EF (or any other ORM) can't be expected to meet everyone's needs.
I realize all of this doesn't really provide you with concrete answers, but I had to drop some advice.
I need some advice. I'm currently using MVC 4 & SimpleMemberhip with LDAP to authenticate users. The issue is, I don't want to store their usernames and passwords in the
webpages_Membership table due to security concerns. The second issue is I want to provide user-editable profiles.
Here's what works so far:
User logs for the first time and a new entry is created in webpages_Membership
An individualized link to edit the user profile is displayed on the homepage
Username is added to the UserProfiles table when profile is accessed for the first time
Certain user details are fetched from LDAP server and written to profile
Users can then customize their profiles
I'm currently using SimpleMembership with an override to the ValidateUser method. Everything works as it should but I don't need to store the LDAP usernames & passwords. Can this be done?
p.s. I know there is a better way to create new users & profiles besides on first time log in but I'm still working on it.
If you don't want to store the passwords (which SimpleMembership would do by default), you are better off deriving your own custom provider from ExtendedMembershipProvider (or maybe from SimpleMembership, but that would get complex) and write the LDAP implementation, or using one of the ones on NuGet. There's no built-in LDAP support in SimpleMembership, so any approach you do would be a nasty hack which will probably bite you later on.
As for the UserProfile, it doesn't sound like your requirement is that different to the usual UserProfile use case - create custom properties on the UserProfile model, update the database accordingly, and build a UI to allow the user to edit whichever of those properties they should be able to directly edit.
(edit)
Footnote. In my answer to "How do I use my own database with SimpleMembership and WebSecurity? What is MVC4 security all about?" I examine the history of membership, how ExtendedMembershipProvider fits into this, and how the new classes such as WebSecurity work on the basis of a provider being a concrete implementation of ExtendedMembershipProvider (which SimpleMembershipProvider is, for example). For anyone looking to derive their own provider to use with WebSecurity, that answer is worth reading.
I've managed to bypass storing user details in the Membership provider by creating the required tables with Code First. I'm now able to create new users and store them in the UserProfile table.
After I was learning about ASP .NET Membership built-in framework I have decided that this stuff is almost suitable for me. But there are couple features and edits I would like to have:
Two step registration: after user have typed all account information, verification letter should be send to typed email. Before email address is verified it impossible to log in (some message should appear, telling user that email verification is needed before it's allowed to use account).
Membership DB Scheme:
There is no need to store user question for restoring password.
Illegal attempts to login is uneccessary.
Default aspnet_ prefix is likely to be changed.
... and so on
For the first item I know that I could use own class derived from SqlMembershipProvider. Am I right about this? Could you point me at some good post where I could get learned.
For the second improvement it's seems like a trouble. In this book I have read that isn't so easy:
• The built-in SQL storage providers need direct access to your database, which
feels a bit dirty if you have a strong concept of a domain model or use a particular
ORM technology elsewhere.
• The built-in SQL storage providers demand a specific data schema
that isn’t easy to share with the rest of your application’s data
schema.
The biggest problem I've encountered with subclassing SqlMembershipProvider is it doesn't give you the connection string to work with. You have to hack the class to pieces to get anything useful for the way most modern login systems work.
I'm not sure about the database tables names - I don't think that's controlled by the SqlMembershipProvider but is actually inside an ASP.NET installer class.
My advice would be to create your own from scratch, and use the built in FormsAuthentication helpers. It's really not a big task compared to hours of annoyance having to conform to the providers. I did this with Roadkill after going down the Membership Provider route, and discovering it a cul-de-sac particularly for Active Directory support.
You can completely control your membership DB schema by Implementing Custom Membership User (of course you also need to implement Membership Provider for the User).
Customize user creation steps by configuring CreateUserWizard control. You will change its' template and handle events, I don't think you need to override it.
I'm creating a new middle tier where all of our client calls will go through a WCF service. We're using ASP.NET membership with the service in order to authenticate users. The middle tier will be hitting an existing database in which we already have an InetUsers table containing usernames and passwords.
This is where it starts to get messy. This new middle tier will be used by our web application, but not by our existing desktop application, which will - until we rewrite it at some point in the future - be using the old COM+ middle tier. Administration of the users for the web application takes place in the desktop application. In other words, users will be created and passwords set and changed from within the desktop application, which in turn hits the already existing InetUsers table.
Ideally, what will happen is when we deploy the new middle tier, we'll take all of the users from the InetUsers table and create records for them in aspnet_Users and aspnet_Membership. Then we'll set a trigger on the InetUsers table to keep aspnet_Users and aspnet_Membership up-to-date.
There's a whole bunch of questions wrapped up in this, so I'll try and list them all out here:
Is this the right approach? Obviously having this data in two places isn't ideal, but bear in mind here that I'm not the final decision maker here and we're kinda stuck with some legacy stuff here, at least for now. Still - maybe there's a better way.
In the same vein - would we be better off coding our own membership provider rather than using the SqlMembershipProvider? How difficult/easy is it to do so?
If we use this approach, I plan on using the aspnet_Membership_XXXX stored procedures for the initial population of the tables as well as in the triggers. Having done some research into this, it appears that if I want to call aspnet_Membership_CreateUser directly from SQL (ie in a trigger...) rather than using the API, I have to store clear text passwords since I can't get the salt and the hash right otherwise. Is this true?
Does any of this even make sense or am I going about this the wrong way to begin with?
Much appreciation for any help offered.
If you already have a database structure, I would write a custom membership provider and skip the existing membership structure. That way you are using one database structure that the developers are already used to, whether for data access, reporting, or other purposes. Create a class that inherits from MembershipProvider. Check this out: http://msdn.microsoft.com/en-us/library/f1kyba5e.aspx or http://www.devx.com/asp/Article/29256/0/page/3.
You only need to implement the features you actually need.
It isn't "difficult" to code your own membership provider. If you're planning on living with the hybrid solution for a while, it would probably be cleaner to roll your own provider than maintain the data in two places.
Then, when you're ready to move to the new, standard, membership provider, it should just be a matter of transfering the users over once and re-pointing to the new provider for both the desktop and web interfaces.