I'm working for the first time with Forms Authentication, I'm using an example from the web to learn, I included in my web.config
<authentication mode="Forms">
<forms name="MYWEBAPP.ASPXAUTH" loginUrl="Login.aspx" protection="All" path="/"/>
</authentication>
<authorization>
<deny users="?"/>
</authorization>
Then I created a page for logging in "login.aspx", and coded this on a button, just to start;
private void btnLogin_Click(Object sender, EventArgs e)
{
// Initialize FormsAuthentication
FormsAuthentication.Initialize();
// Create a new ticket used for authentication
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // Ticket version
Username.Value, // Username associated with ticket
DateTime.Now, // Date/time issued
DateTime.Now.AddMinutes(30), // Date/time to expire
true, // "true" for a persistent user cookie
"accountants, seekers, copiers, typers", // User-data, in this case the roles
FormsAuthentication.FormsCookiePath);// Path cookie valid for
// Encrypt the cookie using the machine key for secure transport
string hash = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(
FormsAuthentication.FormsCookieName, // Name of auth cookie
hash); // Hashed ticket
// Set the cookie's expiration time to the tickets expiration time
if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;
// Add the cookie to the list for outgoing response
Response.Cookies.Add(cookie);
}
Also I coded in Global.asax;
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
if(HttpContext.Current.User != null)
{
if(HttpContext.Current.User.Identity.IsAuthenticated)
{
if (HttpContext.Current.User.Identity is FormsIdentity)
{
FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
FormsAuthenticationTicket ticket = id.Ticket;
// Get the stored user-data, in this case, our roles
string userData = ticket.UserData;
string[] roles = userData.Split(',');
HttpContext.Current.User = new GenericPrincipal(id, roles);
}
}
}
}
And finally in another page I tried to confirm the roles aquired;
protected void Page_Load(object sender, EventArgs e)
{
string str = null;
if (User.IsInRole("seekers"))
{
str += " seekers ";
}
if (User.IsInRole("accountants"))
{
str += " accountants ";
}
if (User.IsInRole("copiers"))
{
str += "copiers";
}
Response.Write(str);
}
But something strange happens cause it only writes "accountants" (note that "accountants" is the firts element in the delimited comma string) and not the other roles, which were supposed to be showed. I changed the order of the role list in the btnlogin click event writing "copiers" as the first element and it's written only "copiers" in the page.
I've tried with different combinations and always is printed the first element of the delimited comma string.
Sorry by my ignorance but what is happening here, are all the roles there or not? is normal? or there's something I'm forgetting here?
Thanks in advance.
Drop the spaces in
"accountants, seekers, copiers, typers"
Try it without the spaces after the commas:
"accountants,seekers,copiers,typers"
The Split will be creating strings like "accountants", " seekers", " copiers", " typers",
You're splitting on ',' ... but when you initialize your string of roles it's actually ", " (comma space).
A tip on this is to use debugger and use the immediate window to actually "see" what's happening as it happens.
Related
I have an Asp.net web application where I am using FormsAuthentication for User login.
I want to prevent multiple logins to the same user at the same time.
For this I have set the FormsAuthentication timeout to 15 minutes and Session.timeout to 15 minutes.
When the user closes the browser without logging out, or if the user is inactive for 15 minutes, it is not firing the Session_End() event in global.asax.cs file. I want to update the database field in the Session_End() event.
Code for Login:
if (Membership.ValidateUser(username, password))
{
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1,
username,
DateTime.Now,
DateTime.Now.AddMinutes(15),
false,
FormsAuthentication.HashPasswordForStoringInConfigFile(password, "SHA1"));
// Now encrypt the ticket.
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
// Create a cookie and add the encrypted ticket to the cookie as data.
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
context.Response.Cookies.Add(authCookie);
context.Response.Redirect("/HomePage", false);
}
Global.asax.cs:
protected void Session_Start(Object sender, EventArgs e)
{
Session["init"] = 0;
Session.Timeout = 15;
}
protected void Session_End(Object sender, EventArgs e)
{
PersonObject person = new PersonObject();
// calling the function to update entry in database
person.ResetUserLoginStatus(HttpContext.Current.User.Identity.Name);
}
Function to update entry in database:
public bool ResetUserLoginStatus( string username="")
{
string sql = "UPDATE Person SET IsLogged=0 WHERE Person = #Person";
PersonObject person = new PersonObject();
object id = person.ExecuteScalar(sql, new Dictionary<string, object>() {
{ "Person", (!string.IsNullOrEmpty(username)?username:User.Name )}
}, "Person");
return true;
}
Web.config:
<authentication mode="Forms">
<forms loginUrl="/Security/Login.ashx/Home" name="SecurityCookie" timeout="15" slidingExpiration="true">
</forms>
</authentication>
<sessionState timeout="15" mode="InProc"></sessionState>
The problem is that when the browser is closed the ResetUserLoginStatus() method isn't called and I am unable to reset my value to 0. Since the field has not been reset to 0, that user won't be able to log in again.
Please suggest.
Session_End is actually not that useful or reliable. For one thing, it only fires at the end of the pipeline processing when an HTTP request has been received and a response has been rendered. That means it does NOT fire for a user who has simply closed their browser. Also, the event will never fire except for certain types of session state-- it won't work with State Server, for example, or SQL-based session state. The bottom line is you can't rely on it to maintain an unambiguous "Is logged in" flag.
Instead, I would store a "last page request received" time stamp. You can then infer the value of a "is logged in" flag; any user who has submitted a request in the past 15 minutes is still logged in.
My web app based on.NET/Webforms does not work like expected because of losing value of set cookie after redirecting to page on the same app domain. But this app worked perfect before. The problem is as following:
Set cookie on Login:
protected void LogIn(object sender, EventArgs e)
{
if (IsValid)
{
. . .
string userData = JsonConvert.SerializeObject(eng);
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1,
UserName.Text,
DateTime.Now,
DateTime.Now.AddMinutes(15),
false,
userData);
string encTicket = FormsAuthentication.Encrypt(authTicket);
HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
Response.Cookies.Add(faCookie);
Response.Redirect("~/View_Id");
}
}
else
{
FailureText.Text = "Invalid username or password.";
ErrorMessage.Visible = true;
}
}
Setting a new cookie works fine, but the value get lost after redirecting. The value will be need on Global.FormsAuthentication_OnAuthenticate(Object sender, FormsAuthenticationEventArgs e).
ok fox, after reading about cookie i found out, that the set user data was too big (more than allowed 4k) - hence the set cookie value will be lost or overrided with null. Reducing the size of user data to the max. limit of 4k is the solution!
I wanted to add authorization before accessing all web pages. So I have used the following configuration in web.config
<authentication mode="Forms">
<forms loginUrl="~/Login/Login.aspx" />
</authentication>
<authorization>
<deny users="?"/>
</authorization>
After this for every page Login.aspx asked, But after logged in successfully Redirection is not working with below code.
//http://localhost:55217/Login/Login.aspx?ReturnUrl=%2fHome%2fdeleteUser.aspx
if (returnMsg == "Success") {
string query0 = Request.QueryString[0];
finalStr = "~" + query0;
Response.Redirect(finalStr, false);
//Session["Login"] = username;
//Response.Redirect("~/Home/Home.aspx");
//Response.Redirect("/Home/HomeTest.aspx");
} else {
StatusLabel.Attributes["style"] = "color:red; font-weight:bold;";
StatusLabel.Text = "Error: Username or Password Wrong";
}
It is staying on the Login page again asking for credentials. But not showing error "Error: Username or Password Wrong"
Any ideas why it is not working?
If you are using Forms authentication you need to create an authentication cookie if authentication is successful. Otherwise the ASP.NET subsystem will not know that the authentication was successful.
See this article:
https://support.microsoft.com/en-us/kb/301240
Here is the relevant text from this article:
4.You can use one of two methods to generate the forms authentication cookie and redirect the user to an appropriate page in the cmdLogin_ServerClick event. Sample code is provided for both scenarios. Use either of them according to your requirement.
•Call the RedirectFromLoginPage method to automatically generate the forms authentication cookie and redirect the user to an appropriate page in the cmdLogin_ServerClick event:
private void cmdLogin_ServerClick(object sender, System.EventArgs e)
{
if (ValidateUser(txtUserName.Value,txtUserPass.Value) )
FormsAuthentication.RedirectFromLoginPage(txtUserName.Value,
chkPersistCookie.Checked);
else
Response.Redirect("logon.aspx", true);
}
•Generate the authentication ticket, encrypt it, create a cookie, add it to the response, and redirect the user. This gives you more control in how you create the cookie. You can also include custom data along with the FormsAuthenticationTicket in this case.
private void cmdLogin_ServerClick(object sender, System.EventArgs e)
{
if (ValidateUser(txtUserName.Value,txtUserPass.Value) )
{
FormsAuthenticationTicket tkt;
string cookiestr;
HttpCookie ck;
tkt = new FormsAuthenticationTicket(1, txtUserName.Value, DateTime.Now,
DateTime.Now.AddMinutes(30), chkPersistCookie.Checked, "your custom data");
cookiestr = FormsAuthentication.Encrypt(tkt);
ck = new HttpCookie(FormsAuthentication.FormsCookieName, cookiestr);
if (chkPersistCookie.Checked)
ck.Expires=tkt.Expiration;
ck.Path = FormsAuthentication.FormsCookiePath;
Response.Cookies.Add(ck);
string strRedirect;
strRedirect = Request["ReturnUrl"];
if (strRedirect==null)
strRedirect = "default.aspx";
Response.Redirect(strRedirect, true);
}
else
Response.Redirect("logon.aspx", true);
}
I'm writing an ASP.net MVC 5 application using FormsAuthentication. I had everything up and working properly using FormsAuthentication.SetAuthCookie(user.Email, model.RememberMe).
However, I wanted to create a custom ticket so I could store some extra information in the UserData field of the ticket. This is how I'm creating my ticket and storing it in a cookie:
var ticket = new FormsAuthenticationTicket(1, user.Email, DateTime.Now, DateTime.Now.AddMinutes(FormsAuthentication.Timeout.Minutes), model.RememberMe, user.AuthToken);
var encryptedTicket = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket) { Domain = FormsAuthentication.CookieDomain, Path = FormsAuthentication.FormsCookiePath, HttpOnly = true, Secure = FormsAuthentication.RequireSSL };
HttpContext.Response.Cookies.Add(cookie);
This creates an encrypted ticket and sends it to the browser. I've verified with developer tools and Fiddler that the ticket is present in the browser and that it is sent back to the server on the subsequent requests.
But authentication is now broken. Also, the cookie is not available in Application_AuthenticateRequest or Application_PostAuthenticateRequest events. When I use the debugger to explore Context.Request.Cookies it is not present in the list.
Oddly enough the cookie does exist if I step back in the pipeline and check it in Application_BeginRequest:
void Application_BeginRequest(object sender, EventArgs e)
{
// Auth cookie exists in the collection here! Ticket decrypts successfully
HttpCookie authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie == null)
return;
var encTicket = authCookie.Value;
var ticket = FormsAuthentication.Decrypt(encTicket);
}
void Application_AuthenticateRequest(object sender, EventArgs e)
{
// Auth cookie missing from the cookies collection here!
HttpCookie authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie == null)
return;
var encTicket = authCookie.Value;
var ticket = FormsAuthentication.Decrypt(encTicket);
using (var db = new BadgerContext())
{
var user = db.Users.OfType<RegisteredUser>().FirstOrDefault(x => x.UserName == ticket.Name);
if (ticket.UserData != user.AuthToken)
{
FormsAuthentication.SignOut();
Response.Redirect(FormsAuthentication.DefaultUrl);
}
}
}
So it appears that something is stripping my custom FormsAuthenticationTicket out of the cookies after BeginRequest but before AuthenticateRequest. Unfortunately, this breaks authentication altogether on the site.
Any ideas what is causing this behavior when I create a custom ticket? Am I doing something wrong with my cookie creation?
Check in the .config file the inside the system.web node, the httpRuntime tag.
<httpRuntime targetFramework="4.5" />
as same as main web site
Rowan suggested I look at the value for FormsAuthentication.Timeout.Minutes. After investigation, this value always came back as 0. This led to an immediate expiration of the ticket. I had to use FormsAuthentication.Timeout.TotalMinutes instead and everything started working properly
as the title says how do o allow users to sign in using the email they specified when they registered.
using asp 3.5 , both the login and signup are the ones that are built-in visual studio.
also is there a way to remove the secret question and answer.
thanks
My simplest and effective workaround for this was to do the following:
1- Rename the label of username field as E-mail: ( so the user will see it Email, but it's actually still the username that ASP.NET membership will save).
2- Save my entry normally along side with any additional info I need to save
3- now my users will be forced to login using their provided Email
4- Smile :)
I think you are looking for forms authentication. There are alot of instructions on google. Or see here: http://msdn.microsoft.com/en-us/library/system.web.security.formsauthentication.aspx
You need to wire up the control's login click event to your authentication logic,
protected void Login_Click(object sender, EventArgs e)
{
// your logic here
}
Also something like the following should go into Global.asax.cs to create an authentication ticket (cookie) that represents the users authenticated session.
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
String cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
if (null == authCookie)
{//There is no authentication cookie.
return;
}
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch (Exception ex)
{
//Write the exception to the Event Log.
return;
}
if (null == authTicket)
{//Cookie failed to decrypt.
return;
}
//When the ticket was created, the UserData property was assigned a
//pipe-delimited string of group names.
String[] groups = authTicket.UserData.Split(new char[] { '|' });
//Create an Identity.
GenericIdentity id = new GenericIdentity(authTicket.Name, "LdapAuthentication");
//This principal flows throughout the request.
GenericPrincipal principal = new GenericPrincipal(id, groups);
Context.User = principal;
}
You will also need an 'IsAuthenticted' boolean method to contain the logic of authentication. In your case you need store their e-mail addresses somewhere and point your authentication logic at that source.