Should I use the username, or the user's ID to reference authenticated users in ASP.NET

StackOverflow https://stackoverflow.com/questions/4911

  •  08-06-2019
  •  | 
  •  

Question

So in my simple learning website, I use the built in ASP.NET authentication system.

I am adding now a user table to save stuff like his zip, DOB etc. My question is:

  1. In the new table, should the key be the user name (the string) or the user ID which is that GUID looking number they use in the asp_ tables.
  2. If the best practice is to use that ugly guid, does anyone know how to get it? it seems to not be accessible as easily as the name (System.Web.HttpContext.Current.User.Identity.Name)
  3. If you suggest I use neither (not the guid nor the userName fields provided by ASP.NET authentication) then how do I do it with ASP.NET authentication? One option I like is to use the email address of the user as login, but how to I make ASP.NET authentication system use an email address instead of a user name? (or there is nothing to do there, it is just me deciding I "know" userName is actually an email address?

Please note:

  • I am not asking on how get a GUID in .NET, I am just referring to the userID column in the asp_ tables as guid.
  • The user name is unique in ASP.NET authentication.
Was it helpful?

Solution

I would suggest using the username as the primary key in the table if the username is going to be unique, there are a few good reasons to do this:

  1. The primary key will be a clustered index and thus search for a users details via their username will be very quick.
  2. It will stop duplicate usernames from appearing
  3. You don't have to worry about using two different peices of information (username or guid)
  4. It will make writing code much easier because of not having to lookup two bits of information.

OTHER TIPS

You should use some unique ID, either the GUID you mention or some other auto generated key. However, this number should never be visible to the user.

A huge benefit of this is that all your code can work on the user ID, but the user's name is not really tied to it. Then, the user can change their name (which I've found useful on sites). This is especially useful if you use email address as the user's login... which is very convenient for users (then they don't have to remember 20 IDs in case their common user ID is a popular one).

You should use the UserID. It's the ProviderUserKey property of MembershipUser.

Guid UserID = new Guid(Membership.GetUser(User.Identity.Name).ProviderUserKey.ToString());

I would use a userid. If you want to use an user name, you are going to make the "change the username" feature very expensive.

I agree with Palmsey, Though there seems to be a little error in his code:

Guid UserID = new Guid(Membership.GetUser(User.Identity.Name)).ProviderUserKey.ToString());

should be

Guid UserID = new Guid(Membership.GetUser(User.Identity.Name).ProviderUserKey.ToString());

I would say use the UserID so Usernames can still be changed without affecting the primary key. I would also set the username column to be unique to stop duplicate usernames.

If you'll mainly be searching on username rather than UserID then make Username a clustered index and set the Primary key to be non clustered. This will give you the fastest access when searching for usernames, if however you will be mainly searching for UserIds then leave this as the clustered index.

Edit : This will also fit better with the current ASP.Net membership tables as they also use the UserID as the primary key.

This is old but I just want people who find this to note a few things:

  1. The aspnet membership database IS optimized when it comes to accessing user records. The clustered index seek (optimal) in sql server is used when a record is searched for using loweredusername and applicationid. This makes a lot of sense as we only have the supplied username to go on when the user first sends their credentials.

  2. The guid userid will give a larger index size than an int but this is not really significant because we often only retrieve 1 record (user) at a time and in terms of fragmentation, the number of reads usually greately outweighs the number of writes and edits to a users table - people simply don't update that info all that often.

  3. the regsql script that creates the aspnet membership tables can be edited so that instead of using NEWID as the default for userid, it can use NEWSEQUENTIALID() which delivers better performance (I have profiled this).

  4. Profile. Someone creating a "new learning website" should not try to reinvent the wheel. One of the websites I have worked for used an out of the box version of the aspnet membership tables (excluding the horrible profile system) and the users table contained nearly 2 million user records. Even with such a high number of records, selects were still fast because, as I said to begin with, the database indexes focus on loweredusername+applicationid to peform clustered index seek for these records and generally speaking, if sql is doing a clustered index seek to find 1 record, you don't have any problems, even with huge numbers of records provided that you dont add columns to the tables and start pulling back too much data.

  5. Worrying about a guid in this system, to me, based on actual performance and experience of the system, is premature optimization. If you have an int for your userid but the system performs sub-optimal queries because of your custom index design etc. the system won't scale well. The Microsoft guys did a generally good job with the aspnet membership db and there are many more productive things to focus on than changing userId to int.

I would use an auto incrementing number usually an int.

You want to keep the size of the key as small as possible. This keeps your index small and benefits any foreign keys as well. Additonally you are not tightly coupling the data design to external user data (this holds true for the aspnet GUID as well).

Generally GUIDs don't make good primary keys as they are large and inserts can happen at potentially any data page within the table rather than at the last data page. The main exception to this is if you are running mutilple replicated databases. GUIDs are very useful for keys in this scenario, but I am guessing you only have one database so this is not a problem.

If you're going to be using LinqToSql for development, I would recommend using an Int as a primary key. I've had many issues when I had relationships built off of non-Int fields, even when the nvarchar(x) field had constraints to make it a unique field.

I'm not sure if this is a known bug in LinqToSql or what, but I've had issues with it on a current project and I had to swap out PKs and FKs on several tables.

I agree with Mike Stone. I would also suggest only using a GUID in the event you are going to be tracking an enormous amount of data. Otherwise, a simple auto incrementing integer (Id) column will suffice.

If you do need the GUID, .NET is lovely enough that you can get one by a simple...

Dim guidProduct As Guid = Guid.NewGuid()

or

Guid guidProduct = Guid.NewGuid();

I'm agreeing with Mike Stone also. My company recently implemented a new user table for outside clients (as opposed to internal users who authenticate through LDAP). For the external users, we chose to store the GUID as the primary key, and store the username as varchar with unique constraints on the username field.

Also, if you are going to store the password field, I highly recommend storing the password as a salted, hashed binary in the database. This way, if someone were to hack your database, they would not have access to your customer's passwords.

I would use the guid in my code and as already mentioned an email address as username. It is, after all, already unique and memorable for the user. Maybe even ditch the guid (v. debateable).

Someone mentioned using a clustered index on the GUID if this was being used in your code. I would avoid this, especially if INSERTs are high; the index will be rebuilt every time you INSERT a record. Clustered indexes work well on auto increment IDs though because new records are appended only.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top