I have an existing ASP.NET application with lots of users and a large database. Now I want to have it in MVC 2. I do not want to migrate, I do it more or less from scratch. The database I want to keep and not touch too much.
I already have my database tables and I also want to keep my LINQ to SQL-Layer. I didn't use a MembershipProvider in my current implementation (in ASP.NET 1.0 that wasn't strongly supported).
So, either I write my own Membershipprovider to meet the needs of my database and app or I don't use the membershipprovider at all.
I'd like to understand the consequences if I don't use the membership provider. What is linked to that? I understand that in ASP.NET the Login-Controls are linked to the provider. The AccountModel which is automatically generated with MVC2 could easily be changed to support my existing logic.
What happens when a user is identified by a an AuthCookie? Does MVC use the MembershipProvider then?
Am I overlooking something?
I have the same questions regarding RoleProvider.
Input is greatly appreciated.
With MVC it is simple to bypass the Membership and Role provider framework altogether. Sometimes it is easier to do this than to implement custom Membership/Role providers, in particular if your authn/authz model doesn't quite fit the mold of those providers.
First, you should realize that you don't need to write everything from scratch, you can use the core Forms authentication API, which can be used independently of the Membership/Role provider framework:
FormsAuthentication.SetAuthCookie -
Call this after user has been
authenticated, specify the user name
Request.IsAuthenticated - Returns
true if SetAuthCookie was called
HttpContext.Current.User.Identity.Name - Returns the user name specified in the call to SetAuthCookie
So here is what you do in MVC to bypass the Membership/Role provider:
Authentication: In your
controller, authenticate the user
using your custom logic.If
successful, call
FormsAuthentication.SetAuthCookie
with the user name.
Authorization: Create a custom
authorize attribute (deriving from
AuthorizeAttribute) . In the
AuthorizeCore override, implement
your custom authorization logic,
taking the user in
HttpContext.Current.User.Identity.Name
and the roles defined in the Roles
property of the AuthorizeAttribute base class.
Note you can also define properties on your custom
authorization attribute and use that in your authorization logic.
For example you can define a property representing roles as enumerated values
specific to your app, instead of using the Roles property which is just a string.
Affix your controllers and actions with your
custom authorize attribute,
instead of the default Authorize
attribute.
Although you most likely can do this without a custom membership provider, I'm not sure that you save that much effort. Until I read this blog post I thought implementing one was hard, but it's really not. Basically you do this:
Create a class that inherits System.Web.Security.MembershipProvider.
MembershipProvider is an abstract class, so you are readily shown what methods need to be implemented.
The names are pretty self explanatory, so you can probably more or less copy your existing logic.
You might end up doing more than you need with this approach - but on the other hand, anything you might want to use now or in the future that requires a membership provider will already have its needs met.
The source of the SQLMembershipProvider is available here http://weblogs.asp.net/scottgu/archive/2006/04/13/442772.aspx. Take that as a base.
It looks a bit much at first, but you only have to implement the methods you need.
Yes the AuthCookie is used. Yes its a good idea to use the MembershipProvider, because it is well known by other developers.
There are thinks I dont like about it: For example It is not possible to have a transaction that spans the creation of a user by the membershipsystem and some other data in your own datbase. But still it works well.
Related
I am a bit confused with customizing UserManager and UserStore.
Out of the box solution comes with EF implementation and i don't want to use EF but my own DAL that uses MSSQL. I want to have Claims based security where one of the users Claims will be roles.
What i am confused with is the overall process i should do. From what i undestand so far is that i need to make my own
CustomApplicationUser : IUser
CustomUserManager : UserManager<CustomApplicationUser>
CustomUserStore : IUserStore, IUserClaimStore
Questions:
Am i on the right track with this?
I want to use IsInRole() method on my CustomUserManager but not sure how to do it with Claims. I am aware there is IUserRoleStore.IsInRole() which default UserManager calls in UserManager.IsInRole() but i don't want separate Roles table in my DB. What i want is Claims DB table with one of ClaimType being Role and that UserManager.IsInRole() uses that.
Now, i am not evet sure why would i ever need UserManager.IsInRole() method? Would i actually need to have something like custom ClaimsIdentity SignInManager.CreateUserIdentityAsync() and within that one call my own implementation of filling in all users info including Claims?
It seems a bit confusing for me and i can't seem to find some clear documentation about it so if anyone could shed a bit of light on it i would highly appreciate it!
Instead of just copying I will just point you to following article: Overview of Custom Storage Providers for ASP.NET Identity.
Take a look at this, it should give you nice overview of how identity works in ASP.NET. It's also good for choosing what you want to override and customize in your application.
hello everyone
i have a project where am using ASP.NET Identity 2.0. in this project am following the Onion architecture.
the layers are :
1.UI: no reference to Owin or ASP.Net Identity
2.AuthenticationService:contains a wrapper for the asp.net identity usermanager.this wrapper implement an interface that lives in the Bal layer.this layer also contain my custom UserStore.
3.Dal: DbContext lives here.
4.Bal: contain Domaine entities and interfaces .no reference to Owin or ASP.NET identity or anything else.
5.DependencyResolver: Owin Startup is here plus some Ninject Modules and the NinjectWebCommon.So am Using Ninject.
till now everything is fine. users are happy creating accounts and ,they can login/logout/manage any time they want.the problem am facing now is with the Authorize(Role="rolename").it just doesn't work.
[Authorize(Users="pedro")]
[Authorize]
both of these works
[Authorize(Roles="Admin")]
this is one no.
in my Database i have users who belongs to the Role Admin.I am not sure why this doesn't work.mybe because i moved all the authentication stuff to another layer so the IPrincipal.IsInRole(string role) can't figure out how to check this anymore.
am working on creating a custom Authorize attribute or create some extensions. but i decided to seek your advices first.
Thank you for your time
well Here i am answering My Own Question.
Indeed the problem was because the Method User.IsInRole(or IPrincipal.IsInRole because User is an IPrincipal). Inspecting the code of AuthorizeAttribute Using Reflector Shows that this Attribute uses the IsInRole Method To Check if The Authenticated User Is In Role X or Xs.but here comes another question .why it can't do that , i mean why it can't find out if a user belongs to a specific role or not.
the problem come from the Cookie generated for the user.because roles are associated to the Cookie they need to be there so IsInRole can Find Them and this is where i made My mistake.I moved the Authentication and authorization to somewhere else but i didn't provide a way to embed the roles informations inside the cookie so the IsInRole (from User or from Roles) couldn't find them in order for the Authorize Attribute to do it's job as i wanted it to.so the good news is that i only needed to insert the roles inside the cookie somehow.
the better news is : ASP.NET Identity wich am using now support claims,and in 4.5 GenericPrincipal derives from ClaimsPrincipal wich in turn derive from IPrincipal,so i can work with claims rather than old fashion roles (wich we can still use if we want to).
well.if someone came across the same issue,i recommand the following:
1.Authorize Attribute needs that the cookie to contain all the informations you are trying to rely on (Roles,User Names).
2.use thinktecture Nuget rather than Authorize or ClaimsPrincipalPermission attributes wich gives you the pros of both of them.
3.Learn About Claims.yo will never regret it.
In my app I want to add properties to the user class.
How should I do it?
My current solution is to create Users table in th database, but I just read that Asp.Net provides out-of-the-box users registration API and functionality.
How can I update the new properties?
Thank you
Do you mean you want a custom Principal? In that case you want to hook into the AuthenticateRequest method and add your own, derived principal. I recently answered a question regarding the creation of a custom principal here. While that question deals with WindowsAuthentication, the idea is the same:
Get the current authenticated principal,
use it to create your own custom principal,
set your principal on the HttpContext and Thread.
You can write a custom Membership Provider that plugs into the membership & authorization features built into the framework. You can also write your own custom User class that inherits from the standard class. You can design it so that it uses your existing users table if you want.
This has worked out well for us on a couple different projects.
Here's some documentation:
http://msdn.microsoft.com/en-us/library/f1kyba5e.aspx
I'm trying to be a Good Developer and separate my concerns out. I've got an ASP.NET MVC project with all my web code, and a DAL project with all the model code.
Sometimes code in the DAL needs to check if the current user is authorized to perform some actions, by checking something like CurrentUser.IsAdmin.
For the web site, the current is derived from the Windows username (from HttpContext.Current.User.Identity), but this is clearly a web concern and shouldn't be coupled to the DAL.
What's the best pattern to loosely couple the authentication? Should the DAL be asking the MVC code for a username, or the MVC be telling the DAL? Are there advantages or disadvantages to one or the other?
Thank you!
Typically I handle the security at the controller level, not at the data level. If you want to handle it at the data level, then I'd use injection to give your DAL either the current user or the means to access who the current user is. In this case it would mean injecting the User object from the Controller when you create the DAL instance. I sometimes do this for auditing, i.e., the current user may be a member of a role that allows access to a modify a user's data. In that case I want to insert the actual user making the change into the audit table. I would avoid using HttpContext.Current -- you should use the properties on the controller instead and inject them rather than having the DAL obtain them from a static object. That will make your DAL much easier to test.
When handling security in the controller you can use the AuthorizeAttribute or custom attributes derived from it to implement your cross-cutting security concerns.
I know what are you saying already (baad idea), but please read first :)
I am developing ASP.NET MVC based app, which will require some specific features:
combination of "local" users and facebook connect login, but FB users will be "mirrored" to some kind of local representation, because there will be some statistics and other stuff needed to keep for both types
authorization will be 3-layered instead of asp.net standard 2 layers. By this i mean : User is in Group (m:n) and Group is in Role (m:n), instead of User is in role (m:n).
So, if i would want to use standard authentication/authhorization approach, i would have to:
implement custom Membership provider, and it wont be even "right", because it will utilize methods like AddUserToGroup and AssignRoleForGroup etc.
implement custom Principal/Identity for sake of accessing my own User objects
casting HttpContext.User to my object every time needed...
implement custom Role provider
custom mechanism of sessting AuthCookie (unique userId in userdata, cant rely on username with third-party FB users in system)
... (you surely can think of something else)
Well, i really dont like the idea of "bending" and replacing every part to get pretty messy solution in the end. So I think of implementing my own mechanism encapsulated in one place - lets call it AuthService.
AuthService will be thread-safe singleton
Instead of AuthCookie will be using standard Session object (i know sessions also use cookies, but i really dont see advantage of low-level storage (cookie) over session)
AuthService will provide AuthService.CurrentUser (of my own type), populated from session on beginning of every request (Application_AuthenticateRequest, I think)
AuthService will provide in one place all methods - ValidateUser, RolesForUser, IsInRole, Logout, etc.
So now.. why should I not do this this way ? :)
I think session is equally secure to AuthCookie (same risks for ticket and authcookie)..
I dont really look for "modularity" (plug-and-play role providers, membership providers, profile providers..) - I deal here with pretty specific stuff, I dont expect standard components to fit.. have "my approach" any other disadvantages ?
Thanks for all good ideas and sorry my terrible english, I am from non-english-speaking country :)
R.
I can certainly see why you don't want to implement an entire Membership provider. However, I would take advantage of the low-level support offered by Forms Authentication (e.g. the cookie, expiration etc.) and just do my own custom authentication. If you do this, you can inject your own custom user class into the HTTP context and use it throughout your code. Your custom user object would implement IIdentity and IPrincipal. Your IPrincipal.IsInRole would work against your custom authentication scheme. This would allow your higher level code to use standard .NET framework permissions stuff. This is the neatest, simplest way to accomplish what you want while taking advantage of what already exists.