I want to store extra information in the authenticated user so that I can have it easily accessible (like User.Identity.Id, for example), instead of just the name, since I'm planning on having that non-unique.
So far I've gathered that I should look to implement custom Principal and/or Identity, but I'm not sure how to go about it. I've been looking for documentation and tutorials on the matter, but I've found related stuff in different places and I've found it a bit confusing.
I have seen how to add custom info to the authentication cookie in the user data property, but I'd like to have the benefit of dependency injection for unit testing, which I can have with the principal and identity.
What are the exact steps I need to consider if I want to implement my own Principal or Identity?
What would be the simplest I could do in this scenario (just add the ID and keep all the defaults in place)? "Defaults" would include the default providers (membership, roles, etc.).
I have seen the other question, but I'd appreciate answers that do not leave any holes in between, such as the roles magic strings in the AuthenticateRequest event in the examples. Instead I need to know how to add the roles from the default SqlRoleProvider to the current user: when and where to do it, and if I need to do anything else to connect my new classes with the other default providers.
It'd be awesome to be able to go to a sample ASP.NET MVC 2 application (from the visual studio 2010 template, for example), make the edits and have it work.
EDIT: I have edited the question to better show that I'm pretty much lost here, so I can't make do with too high level answers.
P.S.: It seems to me that it makes more sense to have the ID in the Identity instead of the principal, although I have, in a way, stated this before.
This question has been asked and answered before:
ASP.NET MVC - Set custom IIdentity or IPrincipal
But to summarize...
Crate a custom principal class with the additional properites you want to store:
Public Class CustomPrincipal
Inherits System.Security.Principal.GenericPrincipal
Private _eyeColor As String
Public ReadOnly Property EyeColor As String
Get
Return _eyeColor
End Get
End Property
Public Sub New(id As System.Security.Principal.IIdentity, roles As String(), eyeColor As String)
MyBase.New(id, roles)
_eyeColor = eyeColor
End Sub
End Class
Modify global.asax Global.Application_AuthenticateRequest to use your custom principal:
Protected Sub Application_AuthenticateRequest(ByVal sender As Object, ByVal e As System.EventArgs)
...
Dim roles() As String = {"examplerole"}
Context.User = new CustomPrincipal(Context.User.Identity, roles, "green")
End Sub
Then elsewhere in your code when you want to refer to one of these properties do this:
CType(My.User.CurrentPrincipal, CustomPrincipal).EyeColor
You can't realy expect that someone can teach you everything you don't know about .NET in a few paragraphs. You can read pretty good example at MSDN http://msdn.microsoft.com/en-us/library/system.security.principal.genericprincipal.aspx and dig through the class and it's derivatives in Reflector - there's nothing spectacularly special about it.
Roles are just a string arrray of names for your own use, in your app/server.
Having said that, you don't really have to aim at exact GenericPrincipal derrivative at all. Check out
HttpContext.Current.Items
It's a Hashtable for free use just for the request you are servicing - meaning that at one point you can do say:
HttpContext.Current.Items["TokenUser"] = new MyThinUser(anything,I,want,there);
and then everythere else in the code just do:
var user = HttpContext.Current.Items["TokenUser"] as MyThinUser;
and you are done.
Store in your new class everything you need/want to pass around from the authentification code to all other functions. Leaves User property intact (so you can peek into it and not have to worry that you changed something). Wihr that you can simplify or complicate your system at will but you keep full independence.
For example if you have your own authentification and just a few levels of acces instead of enumerated roles you can just carry good old access level number (enumerated roles carried around as strings are very inefficient anyway).
Keep in mind that autogenned samples in VS are usually geared towards some particular scenario. So if you see SQL providers for user management that doesn't mean that you actually have to use it - you can still just call your own sproc to get what you need from your own table in SQL.