how to prevent the user repeat-login - asp.net

In my application,I do not want two user login with the same login name.
For example, user1 login with name "test1",then user2 try to login with "test1" too,but at this moment the user1's formauthentication does not expire,so the login of user2 should be denied.
I created a cache class to record all the active session:
public class SessionDb {
private static Dictionary<string, HttpSessionState> sessionDB=new Dictionary<string, HttpSessionState>();
public SessionDb() {
}
public static void addUserAndSession(string name, HttpSessionState session) {
sessionDB.Add(name, session);
}
public static bool containUser(string name) {
//in fact,here I also want to check if this session is active or not ,but I do not find the method like session.isActive() or session.HasExpire() or something else.
return sessionDB.ContainsKey(name);
}
public static void removeUser(string name) {
if(sessionDB.ContainsKey(name)) {
sessionDB.Remove(name);
}
}
}
In the login.aspx.cs:
//check the name and password
if(checkNameAndPass(sUserName, sUserPwd)) {
if(!SessionDb.containUser(sUserName)) {
//let the user login
Session["current_user_name"] = sUserName;
SessionDb.addUserAndSession(sUserName, Session);
FormsAuthentication.RedirectFromLoginPage(UserName.Text, false);
}
else {
//
this.error.Text=string.Format("user {0} have logined!", sUserName);
}
}
Global.asax:
void Session_End(object sender, EventArgs e)
{
SessionDb.removeUser(Session["current_user_name"].ToString());
}
But it seems that it the Session_End() method is called at some time according the timeout setting in the sessionState.
Obviously I need the the SessionDb remove the related session when the authentication timeout.
Any idea to improve my code? or any other idea to implement my requirement?
I just do not want the user repeat-login(with the same name).
UPDATE:
BTW,I think my code also have some problems: I store the log in token using the Session,but how about if the formauthentication have timeout but the session does not?

If you are using a Membership provider:
A user is considered online if the current date and time minus the UserIsOnlineTimeWindow property value is earlier than the LastActivityDate for the user.
from MSDN Article
so you can simple use the check
Membership.IsOnline();
before you login the user.

In asp.net site how to prevent multiple logins of same user id?
Another approach (Disclaimer: I have not tested this.):
In the web.config add userIsOnlineTimeWindow to 1 and in the loggingIn event handler:
protected void Login1_LoggingIn(object sender, LoginCancelEventArgs e)
{
MembershipUser u = Membership.GetUser(Login1.UserName);
Response.Write(u.IsOnline);
if (u.IsOnline)
{
Login1.FailureText = "A user with this username is already logged in.";
e.Cancel = true;
}

Related

How to Authorize user in controller action using list of user from database in ASP.NET MVC 4?

i am doing this in order to authorize user.
[Authorize(Users = #"user1, user2, user3")]
public class MyController : Controller
{
// my stuff
}
i want to do authorization from the list of user which are in database table..
This is how I got it done:
Create a new class (which inherits from AuthorizeAttribute class).
public class CustomAuthorizeAttribute : AuthorizeAttribute
Override the AuthorizeCore method (in CustomAuthorizeAttribute class) and include your custom logic in it.
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool isUserAuthorized = false;
// custom logic goes here
// You can get the details of the user making the call using httpContext
// (httpContext.User.Identity.Name)
// Then get the information you have stored on your db, and compare it
// with these details.
// Set isUserAuthorized to true if the values match
return isUserAuthorized;
}
Decorate your controller action method with the attribute that you just created.
[CustomAuthorize]
public ActionResult DoSomething(string something, string someOtherThing)
This link form Gotalove is helpful.
try the following:
"using the link shared by #VikasRana http://www.codeproject.com/Articles/578374/AplusBeginner-splusTutorialplusonplusCustomplusF
I got rid of my enum Role and my method
public CustomAuthorizeAttribute(params object[] roles)
{ ...}
I then changed Role in my model to be a string e.g. User.Role="Admin" instead of int. In my onAuthorization method I changed it to:
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Controller.TempData["ErrorDetails"] = "You must be logged in to access this page";
filterContext.Result = new RedirectResult("~/User/Login");
return;
}
if (filterContext.Result is HttpUnauthorizedResult)
{
filterContext.Controller.TempData["ErrorDetails"] = "You don't have access rights to this page";
filterContext.Result = new RedirectResult("~/User/Login");
return;
}
}
and in my global.asax added this.
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
if (FormsAuthentication.CookiesSupported == true && Request.IsAuthenticated== true)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
//let us take out the username now
string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
string roles = string.Empty;
using (GManagerDBEntities db = new GManagerDBEntities())
{
User user = db.Users.SingleOrDefault(u => u.Username == username);
roles = user.Role;
}
//let us extract the roles from our own custom cookie
//Let us set the Pricipal with our user specific details
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(
new System.Security.Principal.GenericIdentity(username, "Forms"), roles.Split(';'));
}
catch (Exception)
{
//something went wrong
}
}
}
}
"
Source: Custom user authorization based with roles in asp.net mvc
PS.: In this link, in the same post, there is a second way to fix your problem.
In the bottom of the post.
If this can't to help you, you should try it to.

ASP.NET session stateid issue

i have a load balancing application, and we have an issue where a user try to log in, he/she will then see some else's name.
during the logout process we only call "Session.Abandon();". The article in http://support.microsoft.com/kb/899918 states the following:
When you abandon a session, the session ID cookie is not removed from
the browser of the user. Therefore, as soon as the session has been
abandoned, any new requests to the same application will use the same
session ID but will have a new session state instance. At the same
time, if the user opens another application within the same DNS
domain, the user will not lose their session state after the Abandon
method is called from one application.
does anyone have a clue of why the user sees some else's name while loging in?
Edited - code:
public class CacheManager
{
public Contact.Contact User
{
get { return HttpContext.Current.Session["Contact"] as Contact.Contact; }
set { HttpContext.Current.Session["Contact"] = value; }
}
}
header.ascx.cs
/// <summary>
/// This is the session manager
/// </summary>
public readonly CacheManager Localcache = new CacheManager();
public Login()
{
var contact = BAL.Contact.Get(this.UserName, this.Password);
Localcache.User = contact;
Response.Redirect(Request.Url.AbsoluteUri);
}
protected void Logout_Click(object sender, ImageClickEventArgs e)
{
Session.Abandon();
Response.Redirect(Constants.HomePage);
}
header.ascx:
You are logged in as
<br />
<span class="user_desc">
<%= string.Format("{0} {1}",LocalCache.User.FirstName ,LocalCache.User.LastName)%></span>
when a user explicitly logs out and a new user accesses the page (assuming the browser wasn't closed), the browser still maintains the sessionId (even with Session.Clear() and Session.Abandon()).
Try to add these lines of code
Session.Abandon();
Response.Cookies.Add(new HttpCookie("ASP.NET_SessionId", ""));
Link to check

How can i validate password for user login

I have the following code to check for valid users:
protected void Login_LoginError(object sender, EventArgs e) {
//See if this user exists in the database
MembershipUser userinfo = Membership.GetUser(Login.UserName);
if (userinfo == null || !userinfo.IsApproved || userinfo.IsLockedOut) {
//The user entered an invalid username/password...
Login.FailureText = "Invalid User/Password";
} else {
Login.FailureText = string.Empty;
}
}
This code doesn't show the failure text when the password is wrong for users, I need code-behind logic for validating both the user and password! Any suggestions appreciated.
You should use the Authenticate handler on the login control. For more reading see this link
If you're using the out of the box MembershipProvider you can authenticate your user with the Membership.ValidateUser method in the Authenticate handler.

How to handle "Remember me" in the Asp.Net Membership Provider

Ive written a custom membership provider for my ASP.Net website.
Im using the default Forms.Authentication redirect where you simply pass true to the method to tell it to "Remember me" for the current user.
I presume that this function simply writes a cookie to the local machine containing some login credential of the user.
What does ASP.Net put in this cookie? Is it possible if the format of my usernames was known (e.g. sequential numbering) someone could easily copy this cookie and by putting it on their own machine be able to access the site as another user?
Additionally I need to be able to inercept the authentication of the user who has the cookie. Since the last time they logged in their account may have been cancelled, they may need to change their password etc so I need the option to intercept the authentication and if everything is still ok allow them to continue or to redirect them to the proper login page.
I would be greatful for guidance on both of these two points. I gather for the second I can possibly put something in global.asax to intercept the authentication?
Thanks in advance.
For me the solution was differentiating between a browser-session auth cookie (not to be confused with the asp.net session cookie) and a persistent one - setting a low expiration will create a persistent cookie meaning it gets remembered when the browser is closed and re-opened within the expiration time. The following works for me:
public void SetAuthenticationCookie(LoginView loginModel)
{
if (!loginModel.RememberMe)
{
FormsAuthentication.SetAuthCookie(loginModel.Email, false);
return;
}
const int timeout = 2880; // Timeout is in minutes, 525600 = 365 days; 1 day = 1440.
var ticket = new FormsAuthenticationTicket(loginModel.Email, loginModel.RememberMe, timeout);
//ticket.
string encrypted = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encrypted)
{
Expires = System.DateTime.Now.AddMinutes(timeout),
HttpOnly = true
};
HttpContext.Current.Response.Cookies.Add(cookie);
}
FormsAuthentication and MembershipProviders are two completely different things, still they are made to work with each other very well. If you have written a persistent cookie ["Remember Me"] then next time, you can simply call Membership.GetUser() which will return you the MembershipUser instance of the currently logged in user or null if no user is logged in.
So first time when user arrives and authenticates with "Remember Me", you shall write a persistent cookie as following.
FormsAuthentication.RedirectFromLoginPage(strUserName, true);
Assuming user does not logout and leaves webpage and comes back after sometime. You can simply call MembershipUser.GetUser() as following and check if the user is already logged from the persistent cookie written by FormsAuthentication.
MembershipUser someUser = Membership.GetUser();
if(someUser == null)
{
FormsAuthentication.SignOut();
FormsAuthentication.RedirectToLoginPage();
}
else
{
//Take where logged in users go.
}
You can do this check on your Login page itself or main landing page to intercept the User account to check if he needs to change the password or if the account is disabled as in your case.
EDIT
There are two ways to do this.
1.) Check for authentication as mentioned above in Session_Start event in global.asax and set a session key that becomes available on all pages for that particular session.
2.) Another way is too keep a common application wide common PageBase class that inherits from System.Web.UI.Page and acts as base page class for all your asp.net pages. On the Page Load of the common PageBase class check for the authentication as mentioned above. You will have to carefully write conditional redirection in this case since this might head towards infinite redirection with no end since it will run on Page_Load of all page from the common PageBase class.
public class PageBase : System.Web.UI.Page
{
/// <summary>
/// Initializes a new instance of the Page class.
/// </summary>
public Page()
{
this.Load += new EventHandler(this.Page_Load);
}
private void Page_Load(object sender, EventArgs e)
{
try
{
AuthenticateUser();
}
catch
{
//handle the situation gracefully.
}
}
private AuthenticateUser()
{
MembershipUser someUser = Membership.GetUser();
if(someUser == null)
{
FormsAuthentication.SignOut();
FormsAuthentication.RedirectToLoginPage();
}
else
{
//Take where logged in users go.
}
}
}
//in your asp.net page code-behind
public partial class contact : PageBase
{
protected void Page_Load(object sender, EventArgs e)
{
}
}

ASP.NET private member field loses value on postback

Consider the following code:
public partial class TeacherControlPanel : System.Web.UI.Page
{
protected string username = string.Empty;
protected void Page_Load(object sender, EventArgs e)
{
username = (string)Request.QueryString["username"];
Ice_Web_Portal.BO.Teacher teacher = Ice_Web_Portal.BO.Teacher.GetTeacherByUsername(username);
if (teacher != null)
{
labUsername.Text = username;
labName.Text = teacher.TeacherName;
labTeacherCode.Text = teacher.TeacherCode;
Dept dept = teacher.Department;
if (dept != null)
{
labDepartment.Text = dept.DeptName;
}
}
else
{
//labErrorMessage.Text = "No teacher found";
}
}
protected void btnSendMail_Click(object sender, EventArgs e)
{
Response.Redirect(#"~/Teacher/TeacherComposeMail.aspx?username=mahabub" + username);
}
}
In this code, when I am declaring 'username' as private, it is initialized to null after subsequent post backs.
Why?
What is the secret?
Because ASP.NET is stateless meaning it does not keep it state from post back to postback. Save the user to the viewstate, session, or application to see it on postback to postback.
#region UserName
public string UserName
{
get
{
if (this.ViewState["UserName"] == null)
return string.Empty;
return (string)this.ViewState["UserName"];
}
set { this.ViewState["UserName"] = value; }
}
#endregion
Every time you do any postback, even for "simple" things like button click events, you're working with a new instance of the page class. That's ASP.Net 101.
Declaring the username field as private or protected has no bearing on this situation. The only bearing protected/private would have is the accessibility of the variable outside the class or in inherited members.
I believe this is likely a lifecycle problem.
When you navigate to this page for the first time, user name will only have a value if the query string was set for the request. So, "/TeacherControlPanel.aspx" will have a user name with no value, but "/TeacherControlPanel.aspx?username=SomeUserName". In these cases, the field username is only going to have a value if one is set. And if no querystring is set, then when the page processes the button click event, the load will fire, no query string set means that username will be null, which means that the click event will have nothing to append to the redirect string.
So the question is, in your application, what navigation path are you using to get to TeacherControlPanel.aspx?

Resources