I am working with ASP.NET Membership Providers. I am using SqlMembership Provider, I have overriden the CreateUser class as shown below.
As you can see I have a SportDetails fields which contains many values, this I want to use in the CreateUser method. How do I pass these values ? since these values are taken from ViewModel. Infact SportDetails is my viewModel for registration page.
public class CustomMembershipProvider : SqlMembershipProvider
{
public SportsDetails SportsDetails { get; set; }
public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
{
string.empty
MembershipUser membershipUser = base.CreateUser(username, password, "", null,null, false, null, out status);
// here is where I want to be able to use the value from Sports Details.
return membershipUser;
}
}
and my web.config
<membership defaultProvider="CustomMembershipProvider">
<providers>
<clear/>
<add name="CustomMembershipProvider" type="Service.Security.CustomMembershipProvider" connectionStringName="my_db" requiresQuestionAndAnswer="false" enablePasswordRetrieval="false" enablePasswordReset="true" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="3" minRequiredNonalphanumericCharacters="0" passwordFormat="Clear" passwordAttemptWindow="10" applicationName="myApp" />
</providers>
</membership>
Please help me out on this.
Found the answer the hard way ;)
I used Interface for this.
below is my interface used.
public interface ISportsDetailer{
public SportDetails SportsDetails { get; set; }
}
and then in my custom provider I had this Interface implemented as
public class CustomMembershipProvider : SqlMembershipProvider, ISportsDetailer
{}
and to call CreateUser and pass these values before it, I used
((ISportsDetailer)Membership.Provider).SportsDetails = valueFromModel;
Hope this helps some one in future :)
Related
I am beginner with mvc3 and i and i have created an internet application for which i need to apply windows authentication and check for the user roles in the AD. Is that possible with LDAP? I have searched online but nothing seems clear. Hence, request you guys to assist or post some links which have clear explanation of the procedure to be followed.
Thanks in advance!
It is possible,
Have a look at this URL
Yes it is possible. There are many samples of this online.
In your web.config add the LDAP connection string:
<connectionStrings>
<add name="ADConnectionString" connectionString="LDAP://what ever it is" />
</connectionStrings>
Also add the following:
<authentication mode="Forms">
<forms name=".ADAuthCookie" loginUrl="~/Account/LogOn" timeout="15" slidingExpiration="false" protection="All" />
</authentication>
<membership defaultProvider="ADMembershipProvider">
<providers>
<clear />
<add name="ADMembershipProvider" type="System.Web.Security.ActiveDirectoryMembershipProvider" connectionStringName="ADConnectionString" attributeMapUsername="sAMAccountName" />
</providers>
</membership>
The rest should work the same as normal SQL membership:
public ActionResult LogOn()
{
return View();
}
[HttpPost]
public ActionResult LogOn(LogOnViewModel viewModel, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(viewModel.UserName, viewModel.Password))
{
}
}
}
Your LogOnViewModel:
public class LogOnViewModel
{
public string UserName { get; set; }
public string Password { get; set; }
}
I hope this can help you in the right direction.
I'm using a custom IIdentity and IPrincipal in my ASP.NET MVC application via EF 4.3 as expalined here (and follow accepted answer's solution). Also, I have a custom RoleProvider. In local (using IIS Express), it works currectly. But now, when I upload the application on a real host, it seems all users are in "admin" role! e.g. I create a user that is not in role "admin", but it can access to all protected pages (that need "admin" role). e.g. Role.IsUserInRole always returns true. Have you any idea please? Can you help me? Is there any setting that I should to do in IIS?
I explain that solution and it works for me. I don't now, may be you should rollback to the AuthenticateRequest event.If you want to try this way, you have to remove RoleManagerModule completely from your project. Try this and let me know if works or nop:
// in your module:
public void Init(HttpApplication context) {
_application = context;
// rollback this line:
_application.AuthenticateRequest += ApplicationAuthenticateRequest;
}
// and in web.config
<!-- in system.web section: -->
</system.web>
<!-- other stufs -->
<httpModules>
<remove name="RoleManager"/>
</httpModules>
</system.web>
<!-- and in system.webServer section: -->
<system.webServer>
<!-- other stufs -->
<modules runAllManagedModulesForAllRequests="true">
<remove name="RoleManager"/>
</modules>
<system.webServer>
If you want to keep using the default RoleManager, it gets difficult. I tried creating my own RoleManager by deriving from the default, without any luck.
After 2 days trying several things, I ended up creating some extension methods for RolePrincipal:
public static bool IsEmployee(this RolePrincipal principal)
{
if (IsAuthenticated())
return principal.IsInRole("Employee");
return false;
}
public static bool IsAdmin(this RolePrincipal principal)
{
if (IsAuthenticated())
return principal.IsInRole("Admin");
return false;
}
Created a new WebViewPage class:
public abstract class BaseViewPage : WebViewPage
{
public virtual new RolePrincipal User
{
get
{
if (base.User == null)
return null;
return (RolePrincipal)base.User; //Hard casting: If it goes wrong, it better goes wrong here
}
}
}
public abstract class BaseViewPage<TModel> : WebViewPage<TModel>
{
public virtual new RolePrincipal User
{
get
{
if (base.User == null)
return null;
return (RolePrincipal)base.User; //Hard casting: If it goes wrong, it better goes wrong here
}
}
}
Modified the web.config in the views folder:
<pages pageBaseType="MyCompany.MyProject.BaseViewPage">
And all my Controllers derive from my BaseController:
public abstract class BaseController : Controller
{
protected virtual new RolePrincipal User
{
get { return HttpContext.User as RolePrincipal; }
}
}
Downside is that the methods query my database everytime they get called.
I'm using MVC 4 btw
Hope this helps anyone
I know I can setup OutputCacheProfiles at web.config file.
I like to know how to apply different cache profile to different user role on page (controller) level?
You can decorate a controller with the OutputCache attribute which allows arguments to be passed as parameters. For example;
[OutputCache(Duration = 3600, VaryByParam = "None")]
There is no reason why you couldn't extend the attribute to take a further argument "RoleName" and perform a "Roles.IsUserInRole(RoleName)" and load different settings based upon each role.
EDIT
After comments from the author, I have reviewed my solution.
Firstly, you can define you cache profiles within the Web.config;
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<clear />
<add name="Default" duration="60" />
<add name="Admin" duration="10" />
</outputCacheProfiles>
</outputCacheSettings>
</caching>
I have extended the OutputCacheAttribute to account for authorisation of a user, and if the user authenticates, it loads that CacheProfile;
public class AuthorisedOutputCache : OutputCacheAttribute
{
public string RoleName { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Default Profile.
CacheProfile = "Default";
if (HttpContext.Current.Request.IsAuthenticated)
{
if (Roles.IsUserInRole(RoleName))
{
CacheProfile = RoleName;
}
}
base.OnActionExecuting(filterContext);
}
}
Here is the Index.cshtml file for completeness;
#model DateTime
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
The time is #Model.TimeOfDay.ToString()
</p>
Note: You will have to make sure to define a cacheprofile for each of your roles, aswell as a default for when no role is found.
EDIT
The author wished to know how to set the cache profile within the controller, I have posted a viable solution, but I don't like it because of the use of HttpContext.Items - so if anyone can suggest alternatives?
Firstly, you must change the OnActionExecuting to OnActionExecuted;
public class AuthorisedOutputCache : OutputCacheAttribute
{
public string RoleName { get; set; }
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
// Do you wish to force the profile?
if (HttpContext.Current.Items["Cache.Force"] != null)
{
// Force the profile and remove the flag.
CacheProfile = HttpContext.Current.Items["Cache.Force"].ToString();
HttpContext.Current.Items.Remove("Cache.Force");
}
else
{
// If the profile has not been set - use the role based authorisation -
// otherwise, carry on as normal.
if (string.IsNullOrEmpty(CacheProfile))
{
CacheProfile = "Default";
if (HttpContext.Current.Request.IsAuthenticated)
{
if (Roles.IsUserInRole(RoleName))
{
CacheProfile = "Admin";
}
}
}
}
base.OnActionExecuted(filterContext);
}
}
The following line allows you to set the profile within the controller;
public ActionResult Index()
{
// Forces the cache profile to one of the name of "Mandatory".
HttpContext.Items["Cache.Force"] = "Mandatory";
return View(IndexViewName, DateTime.Now);
}
Let me know if I can be of further assistance,
Matt
I'm trying to use a custom role provider in an MVC3 app. I've already got the membership provider working ok using Ninject but can't seem to get the role provider working. The Membership provider doesn't require a parameterless constructor but role provider does. Here's some code snippets:
Web.config
<membership>
<providers>
<clear/>
<add name="MyMembershipProvider" type="MyApp.Models.NHibernateMembershipProvider"
applicationName="myApp" />
</providers>
</membership>
<roleManager enabled="true">
<providers>
<add name="MyRolesProvider" type="MyApp.Models.NHibernateRoleProvider"
applicationName="myApp" />
</providers>
</roleManager>
I have a Ninject module.
public class MyNinjectModule : NinjectModule
{
public override void Load()
{
this.Bind<ISession>().ToMethod(
x => MyApp.MvcApplication.SessionFactoryData.GetCurrentSession());
// Respository
this.Bind<IUserRepository>().To<UserRepository>();
this.Bind<MembershipProvider>().To<NHibernateMembershipProvider>();
this.Bind<RoleProvider>().To<NHibernateRoleProvider>();
}
}
The custom Membership provider
public class NHibernateMembershipProvider : MembershipProvider
{
private IUserRepository _repo;
public NHibernateMembershipProvider(IUserRepository repository)
{
_repo = repository;
}
...
The role provider
public class NHibernateRoleProvider : RoleProvider
{
private IUserRepository _repo;
public NHibernateRoleProvider(IUserRepository repository)
{
_repo = repository;
}
...
I then configure my controller to require an authorize
[Authorize(Roles="Admin")]
public ActionResult Edit(int? id)
{
...
I get this error when starting the app.
Parser Error Message: No parameterless constructor defined for this object.
Source Error:
Line 49: <roleManager enabled="true">
Line 50: <providers>
Line 51: <add name="MyRolesProvider" type="MyApp.Models.NHibernateRoleProvider"
Line 52: applicationName="myApp" />
Line 53: </providers>
I can access the users through the membership provider, so the repository is being injected ok, but the roles provider seems to be different. Why does the role provider require a constructor-less parameter? Is there a simple way to get the role provider to work with Ninject. Any help appreciated.
Since the role provider, in this case the NHibernateRoleProvider is instantiated by the ASP.NET framework the best solution is to use the service locator pattern. The service locator pattern is normally considered to be an anti-pattern but sometimes you have to be pragmatic and accepted the limitation on the framework that is being used (in this case the ASP.NET framework).
Assuming you are using an implementation of the IDependencyResolver interface for Ninject. The following code should work.
public class NHibernateMembershipProvider : MembershipProvider
{
private IUserRepository _repo;
public NHibernateMembershipProvider()
{
_repo = DependencyResolver.Current.GetService<IUserRepository>();
}
// ...
}
Alternatively, if you're using the Ninject.Web.Mvc nuget package you can always use property injection on your role provider as illustrated here:
ASP.NET MVC 3 Ninject Custom Membership and Role Provider
I have created application in mvc3 and I used the default account controller for my users.
I followed instructions from http://www.asp.net/mvc/tutorials/authenticating-users-with-forms-authentication-cs to put all tables (from aspnetdb) in one database.
My trouble is how to set webconfig and connection string corectly?
I set the conn string to my databse but if I try to register Visual studio create aspnetdb and put my user info there.
I am trying to find solution to stop vs creating aspnetdb.
My hosting provider is http://www.inside.hr it is hosting company from Croatia
If your shared hosting environment only allows you to use one database, you can add the ASP.NET Membership database tables to your existing database. Joe Stagner has a walkthrough on how to do that here.
Can you update your question to tell us where you're hosting? That will help.
I'm not sure if I follow you correctly, but did you try something like this:
<connectionStrings>
<add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"
providerName="System.Data.SqlClient" />
<add name="MyDevArmyDB" connectionString="Data Source=DATASOURCE;Initial Catalog=devarmydb;Persist Security Info=True;User ID=USERID;Password=PASSWORDSTRING"
providerName="System.Data.SqlClient" />
</connectionStrings>
DATASOURCE- replace with the address of your database
USERID- replace with the actual user id
PASSWORDSTRING- replace with the actual password
Accessing the DB is done like this:
public class SqlUserRepository : IUserRepository
{
private DataContext dataContext;
private Table<User> usersTable;
public IQueryable<User> Users { get { return usersTable; } }
public SqlUsersRepository(string databaseName)
{
HttpRequestWrapper request = new HttpRequestWrapper(System.Web.HttpContext.Current.Request);
Configuration config = WebConfigurationManager.OpenWebConfiguration(request.ApplicationPath);
dataContext = new DataContext(config.GetConnetionString(databaseName));
}
}
Note that GetConnectionString is an extension function which supports encryption/decryption of the connection string (if you decide to protect the connection string):
public static class ConfigExtension
{
public static string GetConnetionString(this Configuration config, string databaseName, string provider = "RSAProtectedConfigurationProvider")
{
string sectionName = "connectionStrings";
ConfigurationSection section = config.GetSection(sectionName);
if (section != null && !section.SectionInformation.IsProtected)
{
section.SectionInformation.ProtectSection(provider);
config.Save();
}
return WebConfigurationManager.ConnectionStrings[databaseName].ConnectionString;
}
}