Im trying to use FormsAuthentication in asp.net MVC 4 application.
The authentication itself works fine, but whenever Im getting the User from FormsAuthenticationEventArgs.User and assign to Http.Context.Current.User it works at that exactly moment and next call method bellow Http.Context.Current.User is null again...
What am I doing wrong?
protected void FormsAuthentication_OnAuthenticate(Object sender, FormsAuthenticationEventArgs e)
{
if (FormsAuthentication.CookiesSupported == true)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
var usuarioRn = new UsuarioRN();
string roles = usuarioRn.GetRoles(username);
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value);
e.User = new System.Security.Principal.GenericPrincipal(new System.Web.Security.FormsIdentity(ticket), roles.Split(';'));
//First time get here assign e.User to HttpContext.Current.User, all good
//Next call HttpContext.Current.User is again null, why?
HttpContext.Current.User = e.User;
}
catch (Exception)
{
}
}
}
FormsAuthenticationEventArgs.User is just so you can set the User property of the current HttpContext to a custom IPrincipal object.
It would probably be a lot easier to understand if it had this signature:
FormsAuthenticationEventArgs.SetHttpContextUser(IPrinciple user);
In other words, it will always be null - it actually sets something else (the HttpContext User) when you assign something to it.
Related
I know that there are a lot of topics about this issue but I already tried several solutions and cannot make it work.
So, I am trying to verify the currently logged user role in my view. As referred in the major part of topics about this in StackOverflow, I just have to do:
#User.IsInRole("Admin")
Unfortunately this always returns false even with the "Role" column, in the AspNetUsers table, of the current logged user is populated with "Admin".
I also tried below approach but it says that "UserManager does not exist in current context".
<p>#UserManager.GetRoles(userId)</p>
One of my suspects is that I am not correctly setting the role for the user upon registration. My AspNetRoles table is correctly populated but AspNetUserRoles table is empty.
How can I troubleshoot this to find what is wrong with my application so I can use #User.IsInRole(...) instruction?
Thanks in advance for any help.
This worked perfectly fine for me.
Just make sure you've seeded the roles in the database and also the registered user is assigned a role and this should work fine.
{
<a asp-action="StudentDashboard" asp-controller="Home">Dashboard</a>
}
else
if (User.IsInRole("College"))
{
<a asp-action="CollegeDashboard" asp-controller="Home">Dashboard</a>
}
else
if (User.IsInRole("Manager"))
{
<a asp-action="AdminDashboard" asp-controller="Home">Dashboard</a>
}
else
if (User.IsInRole("Admin"))
{
<a asp-action="AdminDashboard" asp-controller="Home">Dashboard</a>
}```
i think you did not write or you write but in the wrong way this below code on global.asax :
protected void FormsAuthentication_OnAuthenticate(Object sender, FormsAuthenticationEventArgs e)
{
if (FormsAuthentication.CookiesSupported == true)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
//let us take out the username now
string Email = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
string roles = string.Empty;
using (DatabaseContext entities = new DatabaseContext())
{
var user = entities.TblUsers.Where(u => u.Email == Email).FirstOrDefault().IDRole;
//here
roles = entities.TblRoles.Where(x => x.IDRole == user).FirstOrDefault().RoleName;
}
//let us extract the roles from our own custom cookie
// and here
//Let us set the Pricipal with our user specific details
e.User = new System.Security.Principal.GenericPrincipal(
new System.Security.Principal.GenericIdentity(Email, "Forms"), roles.Split(';'));
}
catch
{
//somehting went wrong
}
}
}
}
Have you tried adding below at the top of the view page:
#using Microsoft.AspNet.Identity
Alternatively:
#if(Roles.IsUserInRole(User.Identity.GetUserName(), "Admin"))
I have a sectiontree which varies based on the current logged in users UserType.
The thing is that if i log-out from the backoffice, and logs in with a new user with a lower UserType, the tree is not refreshed - The code is not rerun to generate the tree.
This means that the user with a non administrative UserType can access administrative areas in the section, as long as an administrator have been logged in earlier on the same solution.
How would i make the SectionTree refresh on new users login?
Update
protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
{
var sectionApi = new SectionApiController();
// Root handler
if (id == Constants.System.Root.ToInvariantString())
{
this.RootHandler();
}
else if(id.Contains("COUNTRY_") || id.Contains("LEVEL_") )
{
var section = new IdConvert(id);
if ( section.Area.Equals("country") )
{
this.FirstLevelHandler(section.Id);
}
else if (section.Area.Equals("level"))
{
this.GetLevels(section.Id);
}
// Render clubs.
this.ClubHandler();
// Render levels
this.LevelHandler();
} else if(id.Contains("CLUB_")) {
}
else if(id.Contains("SPORTS_")) {
var Country = new IdConvert(id);
this.SportsHandler(Country.Id);
}
else if (id.Contains("QUESTIONS_"))
{
var Country = new IdConvert(id);
this.QuestionsHandler(Country.Id);
}
return this._nodes;
}
The Tree works fine, it renders what it should render. But It doesent refresh upon new user login.
I'm using the following to check wether or not a person is "admin"
public static bool IsAdministrator()
{
try
{
if (_curNewUser == null)
{
GetCurrentUser();
}
if (_curNewUser.UserType.Alias == "admin")
{
return true;
}
}
catch (Exception e) { }
return false;
}
Based on a comment you are not clearing _curNewUser when user logs out and that's why you are seeing this issue.
Instead of keeping the reference to _curNewUser you should use umbraco built in UmbracoContext.Current.Security.CurrentUser directly in your UserProvider and that will fix it, something like this:
public static bool IsAdministrator()
{
var user = UmbracoContext.Current.Security.CurrentUser;
return user != null && user.UserType.Alias == "admin";
}
No need for you to hook up to logout events or anything like that.
So, what I am trying to accomplish is a basic "remember me" style action for users of my application.
I have completed writing everything so far, and it is working as expected most of the time. Occasionally though, the method to check for the persistent Forms Authentication ticket doesn't auto login, and I can't figure out why it is only happening occasionally.
To test my code, what I have done is start the debugger, manually kill my session cookie in chrome's dev tools, then reload the page. Stepping through the code, it enters into the auto login method as expected and proceeds to reset my session data. However, if I wait an inordinate amount of time, like 4 hours perhaps, and try the same thing it does not auto reset my session. (Assuming that i've left the debugger running for that amount of time).
EDIT: For clarity's sake, when this error is happening, I can open the dev tools and see that the authentication ticket is still available. It's just the code to reset my session is either not running, for erroring out somewhere. Due to the infrequency in which this is happening, it's hard to track down.
So, onto the code.
I'm calling the static void auto login method in the controller's constructor, and passing the httpcontext into the auto login method.
Controller
public class SiteController : Controller
{
public SiteController()
{
this.UserAutoLogin(System.Web.HttpContext.Current);
}
// GET: /Site/
public ActionResult Index()
{
ViewBag.CatNav = this.RenderNavCategories();
return View();
}
}
Auto Login Code
public static void UserAutoLogin(this Controller Controller, System.Web.HttpContext context)
{
HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(FormsAuthentication.FormsCookieName);
if (cookie != null)
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
if (ticket != null)
{
if (ticket.Name.Length > 0)
{
try
{
if (context.Session["UserName"] == null)
{
//get user from db
PersonRepository PersonRepo = new PersonRepository();
PersonModel Member = PersonRepo.GetUserUserName(ticket.Name);
if (Member.FirstName != null) //if this is null...then the cookie is wrong, so don't do shit
{
//Set the session parameters
context.Session["FirstName"] = Member.FirstName;
context.Session["LastName"] = Member.LastName;
context.Session["UserId"] = Member.Id;
context.Session["UserName"] = Member.Username;
context.Session["Email"] = Member.Email;
context.Session["IsUser"] = 1;
context.Session["Zip"] = Member.Zip;
FormsAuthentication.SignOut();
FormsAuthentication.SetAuthCookie(Member.Username, true);
}
}
}
catch (Exception ex)
{
// don't do anything for now - do something smart later :)
Console.WriteLine(ex.ToString());
}
}
}
}
}
Because when IIS is recycling the app, a new machine key is generated. The FormsAuthentication ticket is signed using that key so when the key changes the old ticket isn't recognized. You need to use a fixed machine key.
Edit: Removed link to key generator site (now defunct)
i am new to windows programming, as we use Store user's details in Session when user successfully logged into a web application and check the session in master page every time, if it will null then redirect the user to login page. I want to do the same thing in Windows application, i have created a login form: the code is written below:
private void btnLogin_Click(object sender, EventArgs e)
{
clsLogin obj = new clsLogin();
DataTable dtLogin = obj.Login_Check(txtUserName.Text.Trim(), txtPassword.Text.Trim());
if (dtLogin.Rows.Count > 0)
{
if (dtLogin.Rows[0]["result"].ToString() == "3")
{
lblMessage.Text = "Password does not matched";
}
else
if (dtLogin.Rows[0]["result"].ToString() == "2")
{
lblMessage.Text = "User does not exists";
}
else
{
Staff.Home home = new Staff.Home();
this.Hide();
home.Show();
}
}
}
}
Now what i want to do is: store the user info some where and when user click on Log off then it will destroy that session and it will open the Login form.
i know it is a very silly question, as i am new to windows programming its tough for me, please help.
Apart from the obvious issues with the code:
Direct access to rows by index
Login being done in the event handler directly
You should have separate login service and data access service
I would:
Create a login service that maintains the current logged in user details and performs the authentication itself.
Create a data access service that the login service can call to access the datastore
Then in your event handler you just need to call:
if (loginService.Authenticate(username, password))
{
// Do your UI handling here
}
then the loginService will have a .CurrentUser property for example and you can go from there.
e.g.
public class LoginService
{
private User _currentUser;
public bool Authenticate(string username, string password)
{
if (_currentUser != null)
{
Logout();
}
else
{
var user = DataAccess.Get("users").SingleOrDefault(u => u.Username = username);
if (user == null)
{
throw new Exception("No user with that username found");
}
if (password == user.Password)
{
_currentUser = user;
return true;
}
else
{
return false;
}
}
}
public User CurrentUser
{
get { return _user; }
}
}
In a Web application it is supposed that there are multiple clients connected to the single server; you should use Session to distinguish between them and to pass data to each of them "there and back again". For a desktop application this problem does not exist at all - there is exactly one user and his data is all here: you do not need some special mechanism like Session for it.
This means that you may use a number of different approaches to pass data from your form. In your example it seems more logical to pass data to your "home" form directly, either through constructor
else
{
var userData = .... (txtUserName.Text);
Staff.Home home = new Staff.Home(userData);
this.Hide();
home.Show();
}
or through a property
else
{
var userData = .... (txtUserName.Text);
Staff.Home home = new Staff.Home();
home.UserData = userData;
this.Hide();
home.Show();
}
This is only an example, there are a lot alternatives - just think about this "single user, always on site" model.
I am testing to see whether the user has cookies turned on and I don't seem to be doing something right.
Here is my test:
private bool CookiesAllowed()
{
var testCookie = new HttpCookie("TestCookie", "abcd");
System.Web.HttpContext.Current.Response.Cookies.Set(testCookie);
var tst = System.Web.HttpContext.Current.Request.Cookies.Get("TestCookie");
if (tst == null || tst.Value == null)
{
return false;
}
return true;
}
I'm putting a cookie out there... and then getting it back. But it always succeeds.
Here is how I'm disabling them:
I go to Gmail and it tells me my cookies are disabled so I believe I am doing that part right.
What am I doing wrong?
EDIT
To answer James' question, I am calling this from my logon screen, which is my entry screen as the first check:
public ActionResult LogOn(string id)
{
if (!CookiesAllowed())
{
return View("CookiesNotEnabled");
}
Also, I have tested this live, outside of visual studio and not at localhost and it did the same thing.
You have to let your client/browser do a new Request in order to see if you get the cookie back. When you add a Cookie to the response object, you can only check the presence of it in subsequent new Requests.
Here's a way to do it within the same page in ASP.NET WebForms (since I saw your edit indicating you are using MVC):
private bool IsCookiesAllowed()
{
string currentUrl = Request.RawUrl;
if (Request.QueryString["cookieCheck"] == null)
{
try
{
var testCookie = new HttpCookie("SupportCookies", "true");
testCookie.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(testCookie);
if (currentUrl.IndexOf("?", StringComparison.Ordinal) > 0)
currentUrl = currentUrl + "&cookieCheck=true";
else
currentUrl = currentUrl + "?cookieCheck=true";
Response.Redirect(currentUrl);
}
catch
{
}
}
return Request.Cookies.Get("SupportCookies") != null;
}
This code snippet is inspired by this thread.