Custom security objects may seem like a good idea in a web application. The .NET security model is extensible making it easy to store more than just the basic information in the security principal (IPrincipal).
Having said that, there is also a potential problem with this when the security principal crosses appdomains. Crossing an appdomain boundary requires serialization on both sides and that's where things can go wrong.
If you run a basic web application odds are you don't register your assemblies in the GAC; that's what xcopy deployment is all about, right? Well that also means deserialization is impossible because the receiving app domain is likely not to be aware of your web application's /bin folder.
So, make sure this doesn't happen, you might think. Well, in some cases you don't have a choice. A prominent example is SqlDependency.Start. Internally the SqlDependency creates a new app domain to handle the SqlServer notifications and it will fail if you're using custom implementations of IPrincipal and/or IIdentity that are serializable. Note that if you don't make these classes serializable SqlDependency will work.
I came across this issue after switching to out-of-process session state on one of my projects. Out-of-process session state requires serialization. Since objects representing users were stored in session state, I implemented serialization support on them. All of the sudden, SqlDependency.Start starts throwing exceptions like "Assembly not found". Thankfully, Microsoft has blessed us with the sources to the .NET framework which made debugging this issue a lot less painful.