I have created a class to handle membership user creation with custom fields.
I have done it based on this solutions:
How to assign Profile values?
Using ASP .NET Membership and Profile with MVC, how can I create a user and set it to HttpContext.Current.User?
namespace CCL
{
public static MemberProfile CurrentUser
{
get
{
if (Membership.GetUser() != null)
return ProfileBase.Create(Membership.GetUser().UserName) as MemberProfile;
else
return null;
}
}
}
And now I'm trying to use create the user and get the profile data:
if (Membership.GetUserNameByEmail(email) == null)
{
MembershipUser member = Membership.CreateUser(username, password, email);
Roles.AddUserToRole(username, "WebsiteUsers");
CCL.MemberProfile currentProfile = CCL.MemberProfile.CurrentUser;
bool exists = currentProfile != null;
Response.Write(exists.ToString());
}
but currentProfile is returning null.
So I'm unable to assign values from the form to my member custom properties which are handled by the properties set in the class :(
I don't get how I can make it working :(
Does anyone have some thoughts? Thanks
Suggestion 1:
Make sure that ProfileBase.Create returns something that can be cast to a "MemberProfile", otherwise if it can't then casting it will just return NULL.
Suggestion 2:
Make sure the context you are running in has a logged in user, so your call to Membership.GetUser() can find the current user object.
Other thoughts:
The ProfileBase.Create method assumes that the username you pass in is an authenticated user, I'm not sure on it's behavior when the user isn't authenticated..maybe it returns NULL?
Related
I'm using asp.net identity in my asp.net core mvc core 5 project.
I have a controller, where I need to save the name and email of the currently logged in user in two variables.
So, I now have this controller action:
public string GetUser(string name)
{
string u = User.Identity.Name;
if (u != null)
{
return u;
}
}
Right now, I'm simply trying to save the name of the current user in a variable.
I start the program in debug mode, while I am logged in.
I have a breakpoint exactly on the line string u = User.Identity.Name;.
If I hover hover User.Identity.Name then I can see that the expression evaluates to the name of the currently logged in user.
But when I then step over to the next line, I can see that u evaluates to null.
Thus the if statement evaluates to false and is not executed.
If I write the action like this instead:
public string GetUser(string name)
{
if (User.Identity.Name != null)
{
return User.Identity.Name;
}
return "what";
}
Then everything works as it should.
Why is this? why can I not assign the currently logged in user to any variable?
I have a project running MVC4 and using Simple Membership for authentication. I only want to allow a user to login on one browser. To make this transparent to the user, I need a way to have any other authenticated browser log out whenever a user logs in. This means, if two users are trying to use the same login, they would just continuously kick each other off making that very unproductive.
Right now, I have it set up to only allow a user to login once but if that user were to close the browser and move to another computer, they would be locked out for 30 minutes I can see this creating a number of unnecessary support calls.
I would assume I need to track some sort of identifier in a database and check to make sure it matches with each request otherwise they are logged out. Maybe, adding some sort of cookie.
If anyone has an elegant solution to this, I would appreciate it!
This is what I am currently using to lock users into only one login:
Login:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
string sKey = model.UserName;
string sUser = Convert.ToString(System.Web.HttpContext.Current.Cache[sKey]);
if (sUser == null || sUser == String.Empty)
{
TimeSpan SessTimeOut = new TimeSpan(0, 0, System.Web.HttpContext.Current.Session.Timeout, 0, 0);
System.Web.HttpContext.Current.Cache.Insert(sKey, sKey, null, DateTime.MaxValue, SessTimeOut, System.Web.Caching.CacheItemPriority.NotRemovable, null);
Session["user"] = model.UserName;
if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
{
return RedirectToLocal(returnUrl);
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
else
{
ModelState.AddModelError("", "You are already logged in.");
}
return View(model);
}
Global.asax
protected void Application_PreRequestHandlerExecute(Object sender, EventArgs e)
{
if (HttpContext.Current.Session != null)
{
if (Session["user"] != (null)) // e.g. this is after an initial logon
{
string sKey = (string)Session["user"];
// replace the last hit with current time
// Accessing the Cache Item extends the Sliding Expiration automatically
string sUser = (string)HttpContext.Current.Cache[sKey];
}
}
}
Logout:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
UserProfile user = db.UserProfiles.SingleOrDefault(s => s.UserName == User.Identity.Name);
string sKey = user.UserName;
System.Web.HttpContext.Current.Cache.Remove(sKey);
WebSecurity.Logout();
return RedirectToAction("Start", "Home");
}
I had used the term session and have removed it. I'm not trying to delete the user's session but make their authorization invalid using web security.
There's nothing built-in for this. You'd have to develop some methodology on your own. You'd basically need two pieces:
Some way of tracking a logged in user across requests. This could be as simple as a table with a username column which you could use to determine if that particular username has been logged in. You'd need to keep this in sync with your logins/logouts of course, and you would also need to store the session id for the user. You'll need that for the next piece:
Some mechanism of removing the session from whatever store it exists in. This would be easiest if you're using SQL sessions, as you could simply delete the row from the table session table with the matching id. There's no way to do this directly with ASP.NET, so you'd have to directly query the database, used a stored procedure, etc.
So, the general idea would be that when a user logs in, you record their username and session id in a table or some other persisted store. When someone attempts to log in, you'd check this store for the username that is being attempted, and if it exists, go delete the session that corresponds to this. The next time the user with that session tries to access a page, their session cookie will no longer match a valid session and they'll be treated as if they've been logged out.
I'm trying to customize my own implementation of ExtendedMembershipProvider. I have no idea what the GetUserIDFromOauth method is supposed to do? I see it is throwing an exception by default, and that it is supposed to return the user ID from the open auth provider.
I fail to see how this is supposed to be done, unless this means find if that user exists in the system? Is that it's purpose? I find the lack of documentation confusing...
Thanks.
GetUserIdFromOAuth is a method used by ExtendedMembershipProvider class to find User.Id in your table of users in your web application database based on Provider and ProviderUserId that you get from OAuth or OpenId Provider. After getting Provider and ProviderUserId data for a specified user, you need to save it in your database.
It returns throw new NotImplementedException(); by default. You need to implement this method to return an integer of your User.Id from your application database.
This is a sample implementation:
public override int GetUserIdFromOAuth(string provider, string providerUserId)
{
using (var context = new YourApplicationEntities())
{
// Try to find user with certain Provider and ProviderUserId
var user = context.Users.SingleOrDefault(
q => q.Provider == provider &&
q.ProviderUserId == providerUserId
);
if (user != null)
{
return user.Id;
}
}
return -1;
}
This implementation assumed that you have Provider and ProviderUserId field in your User table. If this information saved in a different table, you just need to modify the LINQ to return the desired result.
I'm developing an application in .NET mvc2. I'm using aspnetMembershipProvider for User registration and related activities. I need some custom information about user that I stored in a separate table (sysUser for example) and linked it to aspnetUser table through foreign key.
After login I need to fetch user's credentials from sysUser table and push it to the session. For this Account controller's Logon method seemed best to me and I pasted following code in my Logon ActionResult
if (!ValidateLogOn(userName, password))
{
return View();
}
FormsAuth.SignIn(userName, rememberMe);
ApplicationRepository _ApplicationRepository = new ApplicationRepository();
MembershipUser aspUser = Membership.GetUser(userName);
SessionUser CurrentUser = _ApplicationRepository.GetUserCredentials(aspUser.ProviderUserKey.ToString());
//Session["CurrentUser"] = CurrentUser;
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
The code is working perfectly for me and put my desired information in the session but the thing is that if a user selects Remember me and on his next visit he won't have to Log in and I would not find my desired information in the Session. Where should I put my code that stores the user information in the session?
FormsAuthentication.SetAuthCookie(userName, saveLogin);
MSDN Documentation for SetAuthCookie Method
I am writing my own custom Identity class which implements IIdentity. I don't need to change the default method IsAuthenticated but so now I was wondering how does the default IIdentity determines if it should return true or false?
I thought to find the answer in the FormsAuthenticationTicket I am using but not sure if that is correct.
Thanks in advance,
Pickels
There is no 'default IIdentity' in the context of an ASP.Net handler.
There is a GenericIdentity that is pass to a GenericPrincipal which is the default User for an ASP.Net handler, and it's behavior is that if it is instantiated with a non-empty username then it is authenticated.
e.g.
public virtual bool IsAuthenticated
{
get
{
return !this.m_name.Equals("");
}
}
That said, the determination of IsAuthenticated is completely arbitrary and the class implementing IIdentity is fully responsible for implementing this logic.
Typically, there is no use case for instantiating an un-authenticated principal/identity as this is done automatically by the asp.net runtime, thus implementing your custom IIdentity with a 'dumb' IsAuthenticated that returns true should be appropriate in most cases.
Also, while fully implementing IPrincipal and IIdentity is trivial, you could also simply derive from GenericPrincipal and GenericIdentity reducing the amount of code you need to maintain.
In the context of FormsAuthentication you will only have a ticket if the user is authenticated and the User will be an instance of RolePrincipal with an identity of type FormsIdentity and it's implementation of IsAuthenticated is super complex ;-) ...
public bool IsAuthenticated
{
get
{
return true;
}
}
Hope that helps clear things up.
I use a custom UserPrinciple to embed more information about the current user into my pages than the standard GenericPrinciple allows. I didn't find a need to implement my own IIdentity as you can easily leverage the built in FormsIdentity similar to my fashion (I'm not sure if this is divergent from standard practices of Auth for .NET it's worked great in practice for myself though). I did create a custom GuestIdentity that returns a hardcoded IsAuthenticated = false perhaps this could be replaced by just GenericPrinciple I'm not sure off hand if it's abstract or not.
public class UserPrincipal : IPrincipal
{
private readonly IIdentity _identity;
public UserPrincipal()
{
_identity = new GuestIdentity();
var guest = //my custom object
User = guest;
}
public UserPrincipal(HttpContext context)
{
var ident = context.User.Identity as FormsIdentity;
string msg1 = "Context.User.Identity is null for authenticated user.";
if (ident == null) throw new ApplicationException(msg1);
_identity = ident;
string msg2 = "Forms Identity Ticket is null";
if (ident.Ticket == null) throw new AccessViolationException(msg2);
var userData = ident.Ticket.UserData;
...
User = jsonSerializer.Deserialize<User>(userJson);
}
#region IPrincipal Members
public bool IsInRole(string role)
{
return User.Roles.FirstOrDefault(x => x.RoleName == role) != null;
}
public IIdentity Identity
{
get { return _identity; }
}
#endregion
}
Random aside, you can cache data in the Forms Authentication ticket like extended UserData, if you follow this type of idea though make sure you have logic in place that can correctly expire stale data since it's stored on the client computer.