Im implementing the ASP.NET Profile Provider alongside the Membership Provider using Jon Galloway's (slightly dated) example here:
and Im getting the error Provider must implement the class 'System.Web.Profile.ProfileProvider'
As per the example, I've created a custom UserProfile inheriting from ProfileBase
public class UserProfile : ProfileBase
{
public static UserProfile GetUserProfile(string username)
{
if (username != null)
{
var profile = Create(username) as UserProfile;
return profile;
}
}
public static UserProfile GetUserProfile()
{
var membershipUser = MembershipProvider.GetUser();
if (membershipUser != null)
return Create(membershipUser.UserName) as UserProfile;
}
[SettingsAllowAnonymousAttribute(true)]
public virtual string Name
{
get { return base["Name"] as string; }
set { base["Name"] = value; }
}
}
I'm calling above method from a Class library like this:
var profile = UserProfile.GetUserProfile(name);
In turn, Im calling that method from a Unit test project, which has an app.config:
<profile enabled="true" defaultProvider="MyProfileProvider" inherits="NAMESPACE.UserProfile, NAMESPACE">
<providers>
<clear/>
<add
name="MyProfileProvider"
connectionStringName="MembershipConnection"
applicationName="/"
type="NAMESPACE.UserProfile, NAMESPACE"
/>
</providers>
<properties>
<add name="Name" type="String"/>
</properties>
</profile>
Inheriting from ProfileBase (like Jon's example) should be enough right? I think i've used all variations on the 'type' and 'inherit' attributes, am I missing something here?
I've managed to at least save Profile values using a variation on this example
dynamic profile = ProfileBase.Create(UserName);
profile.Name = name;
profile.Save();
Not sure how to retrieve that same property yet tho, since ProfileBase has no such method...
Related
Within a signalR hub method, I'm trying to check if the user authenticated is within a specific role. In plane MVC, I can call user.IsInRole and the class overriding RoleProvider's GetRolesForUser method is called.
The CustomRoleProvider is set up in the web.config with:
<roleManager cacheRolesInCookie="false" defaultProvider="CustomRoleProvider" enabled="true">
<providers>
<clear />
<add name="CustomRoleProvider" type="CustomRoleProvider" />
</providers>
</roleManager>
When user.IsInRole is called CustomRoleProvider.GetRolesForUser(string username) is called.
Hub code
public IEnumerable<Items> GetList()
{
IList<Items> result;
var user = Context.User;
if (user.IsInRole("Test_Role"))
result = itemProvider.GetItems();
else
result = new[] { };
return result;
}
CustomRoleProvider
public class CustomRoleProvider:RoleProvider
{
public override string[] GetRolesForUser(string username)
{
return new[]{"Test_Role"};
}
}
Why is this not working in signal R? user.IsInRole does not call GetRolesForUser and always returns False.
I am using this article to implement ASP.NET SQLMembership Profile Provider in my ASP.NET 4.0 Web Application project (NOT website project). I am using Forms authentication. On my admin page I need to display the profile info of all the users. But for some reason, the following code is always returning the profile of the current user instead of each user whose username is provided:
ProfileInfoCollection oProfInfoColl = ProfileManager.GetAllProfiles(ProfileAuthenticationOption.All);
string sUserName = "";
foreach (ProfileInfo oPi in oProfInfoColl)
{
sUserName = oPi.UserName;
UserProfile oPc = UserProfile.GetUserProfile(sUserName);
oDataTbl.Rows.Add(new string[] { oPc.Company, oPc.FirstName, oPc.LastName, sUserName, Roles.GetRolesForUser(sUserName)[0] });
}
In the above code oPi.UserName correctly returns the username of each user but GetUserProfile(sUserName) always returns the profile of the currently logged in user.
When I display the Profile properties (FirstName, LastName etc.) on the page I see that these properties are for the currently logged in user in each row even though the UserName and roles of each users are displayed correctly in each row for the specified user. Please note that the username and the roles are not coming from the profile.
My UserProfile custom class is:
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Profile;
using System.Web.Security;
namespace WebAppName
{
public class UserProfile : ProfileBase
{
public static UserProfile GetUserProfile(string username)
{
return Create(username) as UserProfile;
}
public static UserProfile GetUserProfile()
{
return Create(Membership.GetUser().UserName) as UserProfile;
}
[SettingsAllowAnonymous(true)]
public string Company
{
get
{
return (string)HttpContext.Current.Profile.GetPropertyValue("Company");
}
set
{
HttpContext.Current.Profile.SetPropertyValue("Company", value);
}
}
[SettingsAllowAnonymous(true)]
public string FirstName
{
get
{
return (string)HttpContext.Current.Profile.GetPropertyValue("FirstName");
}
set
{
HttpContext.Current.Profile.SetPropertyValue("FirstName", value);
}
}
[SettingsAllowAnonymous(true)]
public string LastName
{
get
{
return (string)HttpContext.Current.Profile.GetPropertyValue("LastName");
}
set
{
HttpContext.Current.Profile.SetPropertyValue("LastName", value);
}
}
}
}
My web.config file has following Profile section:
<profile inherits="WebAppName.UserProfile" enabled="true" defaultProvider="ProjectNameSqlProvider" automaticSaveEnabled="true">
<providers>
<clear />
<add name="ProjectNameSqlProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="MyConnectionString" applicationName="ProjectName" />
</providers>
</profile>
I found my own mistake. In my UserProfile class I am getting and setting the properties of current user; whereas, Jon Galloway in his article that I referred to in my original post is clearly getting/setting the properties of specified user - that is what I should have done. Thanks to those who may have tried to help.
In my ASP.NET MVC application, I'm trying to figure out whether the user has access to a particular controller, restricted by the authorize data annotation as follows
[Authorize(Roles = "user")]
I'm attempting to override OnAuthorization in order to check:-
If the request is authenticated (which works great)
If the user is authorised to access the requested view (which doesn't work)
My user roles are stored in a SessionManager object I've created - SessionManager.ActiveUser.Roles
Here's what I have in the form of pseudo-code but if anybody could help me get this right, I'd really appreciate it.
public class HomeBaseController : Controller
{
protected override void OnAuthorization(AuthorizationContext context)
{
if (context.HttpContext.User.Identity.IsAuthenticated)
{
// these values combined are our roleName
bool isAuthorised = context.HttpContext.User.IsInRole(context.RequestContext.HttpContext.User.Identity.);
if (!context.HttpContext.User.IsInRole(---the roles associated with the requested controller action (e.g. user)---))
{
var url = new UrlHelper(context.RequestContext);
var logonUrl = url.Action("LogOn", "SSO", new { reason = "youAreAuthorisedButNotAllowedToViewThisPage" });
context.Result = new RedirectResult(logonUrl);
return;
}
}
}
As far as overriding OnAuthorization according to ProASP.NET MVC3 Book they do not recommend overriding it since the default implementation of this method securely handles content cached using OutputCache Filter.
If you are looking for Custom Authentication (using Forms Auth) and Authorization (Using Role provider logic then below is how I secured my application.
EDIT: The following logic uses in-built forms authentication and roles manager. Once user is authenticated and authorized the User Identity can be used to check both the authentication (User.Identity.IsAuthenticated) and the roles User.IsInRole("admin")
In Web.Config:
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" timeout="15" slidingExpiration="true" enableCrossAppRedirects="false" protection="All" />
</authentication>
<roleManager enabled="true" defaultProvider="MyRolesProvider" cacheRolesInCookie="true" cookieProtection="All">
<providers>
<clear />
<add name="MyRolesProvider" type="MyApp.Library.CustomRolesProvider" />
</providers>
</roleManager>
For Role Authorization Extend RoleProvider and override methods as required.
public class CustomRolesProvider : RoleProvider
{
public override string[] GetRolesForUser(string username)
{
// You need to return string of Roles Here which should match your role names which you plan to use.
//Some Logic to fetch roles after checking if User is Authenticated...
return new string[] { "admin" , "editor" };
}
//Rest all of them I have kept not implemented as I did not need them...
}
In Your controller Now you can use this:
[Authorize(Roles="Admin")]
public class AdminController : Controller
{
....
}
For Authentication I have implemented my custom Authentication Check but I still use Forms Authentication:
//This one calls by Custom Authentication to validate username/password
public ActionResult LogOn(LogOnViewModel model, string returnUrl)
{
if(Authenticate("test","test"))
{
.......
}
}
public bool Authenticate(string username, string password)
{
//Authentication Logic and Set the cookie if correct else false.
//..... your logic....
//.....
FormsAuthentication.SetAuthCookie(username, false);
}
I want to have custom profile provider in my asp.net mvc 3 app. The problem is, that I don't want to use default DB that is generated by ASP.NET Membership/Role/Profile provider, mainly because authentication is already done with WebService and DBs already exist.
I want to user profile properties to populate them and use within different areas of the site.
I took a look at this example (How to assign Profile values?) but I am getting this error:
An attempt to attach an auto-named database for file
C:\Projects\FWManager\App_Data\aspnetdb.mdf failed. A database with
the same name exists, or specified file cannot be opened, or it is
located on UNC share.
Here is the web.config
<profile inherits="FWMembership.Membership.FWProfileProvider" defaultProvider="AspNetSqlProfileProvider" automaticSaveEnabled="false" enabled="true">
<providers>
<clear/>
<add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/" />
</providers>
</profile>
This is my custom class
public class FWProfileProvider : ProfileBase
{
[SettingsAllowAnonymous(false)]
public string FirstName
{
get { return base["FirstName"] as string; }
set { base["FirstName"] = value; }
}
[SettingsAllowAnonymous(false)]
public string LastName
{
get { return base["LastName"] as string; }
set { base["LastName"] = value; }
}
[SettingsAllowAnonymous(false)]
public int? UserID
{
get { return base["UserID"] as int?; }
set { base["UserID"] = value; }
}
[SettingsAllowAnonymous(false)]
public string UserCompany
{
get { return base["UserCompany"] as string; }
set { base["UserCompany"] = value; }
}
[SettingsAllowAnonymous(false)]
public string Email
{
get { return base["Email"] as string; }
set { base["Email"] = value; }
}
public StringCollection Entitlements
{
get { return base["Entitlements"] as StringCollection; }
set { base["Entitlements"] = value; }
}
public string username;
public FWProfileProvider()
{
}
public FWProfileProvider(string username)
{
this.username = username;
}
static public FWProfileProvider CurrentUser
{
get
{
return (FWProfileProvider)
(ProfileBase.Create("Joe"));
}
}
}
The key is to avoid using asp.net default membership tables.
Any ideas?
EDIT:
Forgot to add - this web application, but profile provider is placed in the class library project within same soulution:
Solution
|->FWProfile (class library project)
|->UI (asp.net mvc 3 web application)
I think you have to write your own MemberShip Provider as well. Your web.config refers to the default asp.net membership provider. How to write a Membership provider you can find here custom membership provider
The default membership provider uses a connection string into a locally installed SQL Express database and that causes your error.
Your web.config would look like this:
<membership defaultProvider="MyCustomMembershipProvider">
<providers>
<clear />
<add name="MyCustomMembershipProvider"
type="FWMembership.Membership.MyCustomMembershipProvider"
enablePasswordRetrieval="true"
enablePasswordReset="true"
requiresQuestionAndAnswer="false"
requiresUniqueEmail="true"
passwordFormat="Clear"/>
</providers>
</membership>
<profile defaultProvider="MyProfileProvider" enabled="true">
<providers>
<clear/>
<add name="MyProfileProvider" type="FWMembership.Membership.FWProfileProvider" connectionStringName="ApplicationServices" applicationName="/" />
</providers>
</profile>
Hope this helps.
So I have an asp.net Web Application (Not Web Site) that I am trying to support profiles for anonymous users. I have a form and I want anonymous users to be able to enter their name and email only once, and have that information automatically accessible on the next load for them.
In my Web.config I have anonymous ID setup like so:
<anonymousIdentification enabled="true" cookieless="AutoDetect" />
I have my profile section setup like this:
<profile defaultProvider="SqlProvider" enabled="true" inherits="QA_Web_Tools.UserProfile">
<providers>
<clear />
<add connectionStringName="QAToolsConnectionString" name="SqlProvider"
type="System.Web.Profile.SqlProfileProvider" />
</providers>
</profile>
Finally, due to my app being a Web App and not a Web Site, I am using the profiles via this custom object:
public class UserProfile : ProfileBase
{
public static UserProfile GetUserProfile(string username)
{
return Create(username) as UserProfile;
}
public static UserProfile GetUserProfile()
{
return Create(Membership.GetUser().UserName) as UserProfile;
}
[SettingsAllowAnonymous(true)]
public string FullName
{
get { return base["FullName"] as string; }
set { base["FullName"] = value; }
}
[SettingsAllowAnonymous(true)]
public string BuildEmail
{
get { return base["BuildEmail"] as string; }
set { base["BuildEvmail"] = value; }
}
}
This code is based off of this reference.
The issue is that that code does not support anonymous users, or if it does I don't know how. I can't use the GetUserProfile() method with no parameters because if the user is anonymous, Membership.GetUser() is null. I could pass in the anonymous ID token into the first GetUserProfile(string username) method but I cant' find any way to get the anonymous ID token for the current user.
Does anyone know how to get this information? Google doesn't seem to be returning useful results.
Thanks,
Success!
I changed:
public static UserProfile GetUserProfile()
{
return Create(Membership.GetUser().UserName) as UserProfile;
}
to
public static UserProfile GetUserProfile()
{
return HttpContext.Current.Profile as UserProfile;
}
and now it works!