1. Set web. config related options
Enable the form authentication and default logon page, as shown in the following figure.
<Authentication mode = "forms">
<Forms loginurl = "default. aspx"> </Forms>
</Authentication>
Set the website to be accessible anonymously, as shown below:
<Authorization>
<Allow users = "*"/>
</Authorization>
then set the Admin directory under the same directory to reject anonymous login, as shown below. Note that this section is under the system. web section.
Set the HTTP request and sent encoding to gb2312. Otherwise, the query string may fail, as shown below.
<Globalization requestencoding = "gb2312" responseencoding = "gb2312"/>
Set the session timeout to 1 minute and enable cookieless, as shown below.
<Sessionstate mode = "inproc" cookieless = "true" timeout = "1"/>
To enable page tracing, we first start the trace of each page for convenient debugging, as shown below.
<Trace enabled = "true" requestlimit = "1000" pageoutput = "true" tracemode = "sortbytime" localonly = "true"/>
2. Set the global. asax File
Process the application_start method, instantiate a Hasse table, and save it in the cache.
Protected void application_start (Object sender, eventargs E)
{
Hashtable H = new hashtable ();
Context. cache. insert ("online", H );
}
Call the logoutcache () method in the session_end method. The method source code is as follows:
/// <Summary>
/// Clear the current user in the cache, which is mainly called in the session_end method of Global. asax and the method of user logout /// </Summary>
Public void logoutcache ()
{
Hashtable H = (hashtable) Context. cache ["online"];
If (H! = NULL)
{
If (H [session. sessionid]! = NULL)
H. Remove (session. sessionid );
Context. cache ["online"] = h;
}
}
3. Set related logon and logoutCode
Call the preventrepeatlogin () method before logon. This method prevents repeated login by users. If the last logon times out for more than 1 minute, that is, the page under all admin directories is disabled for more than 60 seconds, it is deemed that the user logging on to the system has timed out, and you can log on to the system. If the time does not exceed 60 seconds, a custom exception will be generated. A Hasse table is saved in cache ["online"]. The key of the Hasse table is the sessionid of the current login user, and the value is an arraylist. This arraylist has two elements, the first is the user login name. The second element is the user login time. Then, when the page under each Admin directory is refreshed, the login time of the Current login user is updated, however, only one page in the Admin directory opens. Even if you do not manually send a request to the server, a request is automatically sent to update the logon time, below I have written a function in the base class of the page to do this. In fact, this will increase the burden on the server, but it is also a feasible method under certain circumstances.
/// <Summary>
/// Prevent repeated login by the user before the user wants to authenticate
/// </Summary>
/// <Param name = "name"> username to be verified </param>
Private void preventrepeatlogin (string name)
{
Hashtable H = (hashtable) cache ["online"];
If (H! = NULL)
{
Idictionaryenumerator e1 = H. getenumerator ();
Bool flag = false;
While (e1.movenext ())
{
If (string) (arraylist) e1.value) [0] = Name)
{
Flag = true;
Break;
}
}
If (FLAG)
{
Timespan Ts = system. datetime. Now. Subtract (convert. todatetime (arraylist) e1.value) [1]);
If (TS. totalseconds <60)
Throw new Oa. cls. myexception ("sorry, the account you entered is in use. If you are the real owner of this account, please change your password in time upon the next login, because your password is very likely to be stolen! ");
Else
H. Remove (e1.key );
}
}
Else
{
H = new hashtable ();
}
Arraylist Al = new arraylist ();
Al. Add (name );
Al. Add (system. datetime. Now );
H [session. sessionid] = Al;
If (Cache ["online"] = NULL)
Context. cache. insert ("online", H );
Else
Cache ["online"] = h;
}
Call the logoutcache () method mentioned above when logging out.
4. Set the base class for all pages under the Admin directory
Using system;
Using system. Web;
Using system. Web. UI;
Using system. Web. UI. webcontrols;
Using system. Web. UI. htmlcontrols;
Using system. collections;
Namespace Oa. CLs
{
Public class mybasepage: system. Web. UI. Page
{
/// <Summary>
/// Obtain whether the current page is in a protected directory. Program Under the virtual directory of OA, the protected directory is the Admin directory.
/// </Summary>
Protected bool isadmindir
{
Get {return request. filepath. indexof ("/OA/admin") = 0 ;}
}
///
// prevents Session Timeout, if the timeout occurs, log out of authentication and prompt and go to the website homepage
///
private void preventsessiontimeout ()
{< br> If (! This. isadmindir) return;
If (session ["user_name"] = NULL & this. isadmindir)
{< br> system. web. security. formsauthentication. signout ();
This. alert ("Login timeout", request. applicationpath)
}< BR >}
/// <Summary>
/// Update the logon time option in the cache every time you refresh this page and call it in the oninit method below.
/// </Summary>
Private void updatecachetime ()
{
Hashtable H = (hashtable) cache ["online"];
If (H! = NULL)
{
(Arraylist) H [session. sessionid]) [1] = datetime. now;
}
Cache ["online"] = h;
}
/// <Summary>
/// Output all the elements of a hashtable in the trace and call the following oninit method to conveniently observe the cached data
/// </Summary>
/// <Param name = "mylist"> </param>
Private void tracevalues (hashtable mylist)
{
Idictionaryenumerator myenumerator = mylist. getenumerator ();
Int I = 0;
While (myenumerator. movenext ())
{
Context. Trace. Write ("onlinesessionid" + I, myenumerator. Key. tostring ());
Arraylist Al = (arraylist) myenumerator. value;
Context. Trace. Write ("onlinename" + I, al [0]. tostring ());
Context. Trace. Write ("onlinetime" + I, al [1]. tostring ());
Timespan Ts = system. datetime. Now. Subtract (convert. todatetime (Al [1]. tostring ()));
Context. Trace. Write ("the current time and the number of seconds between this logon time", ts. totalseconds. tostring ());
I ++;
}
}
/// <Summary>
/// Pop-up information and return to the specified page
/// </Summary>
/// <Param name = "MSG"> pop-up message </param>
/// <Param name = "url"> specify the page for redirection </param>
Protected void alert (string MSG, string URL)
{
String scriptstring = "<script language = JavaScript> alert (\" "+ MSG +" \ "); location. href = \ "" + URL + "\" </SCRIPT> ";
If (! This. isstartupscriptregistered ("alert "))
This. registerstartupscript ("alert", scriptstring );
}
/// <Summary>
/// To prevent Session Timeout caused by frequent page refreshing, write a script and send a request to this page every minute to ensure that the session is not timed out, here, we use XMLHTTP for refreshing requests.
/// This method is also called in the oninit method below
/// </Summary>
Protected void xmlreload ()
{
System. Text. stringbuilder htmlstr = new system. Text. stringbuilder ();
Htmlstr. append ("<script language = \" javascript \ "> ");
Htmlstr. append ("function getmessage (){");
Htmlstr. append ("Var XH = new activexobject (\" Microsoft. XMLHTTP \");");
Htmlstr. append ("XH. Open (\" Get \ ", window. Location, false );");
Htmlstr. append ("XH. Send ();");
Htmlstr. append ("window. setTimeout (\" getmessage () \ ", 60000 );");
Htmlstr. append ("}");
Htmlstr. append ("window. onload = getmessage ();");
Htmlstr. append ("</SCRIPT> ");
If (! This. isstartupscriptregistered ("xmlreload "))
This. registerstartupscript ("alert", htmlstr. tostring ());
}
Override protected void oninit (eventargs E)
{
Base. oninit (E );
This. preventsessiontimeout ();
This. updatecachetime ();
This. xmlreload ();
If (this. cache ["online"]! = NULL)
{
This. tracevalues (system. Collections. hashtable) cache ["online"]);
}
}
}
}
5. Write a custom exception class
First, you need to write an error display page showerr. aspx under the directory. This page displays an error message on a label based on the value of the passed query string MSG.
Using system;
Namespace Oa. CLs
{
/// <Summary>
/// Summary of myexception.
/// </Summary>
Public class myexception: applicationexception
{
/// <Summary>
/// Constructor
/// </Summary>
Public myexception (): Base ()
{
}
/// <Summary>
/// Constructor
/// </Summary>
/// <Param name = "errmessage"> exception message </param>
Public myexception (string message): Base (Message)
{
System. Web. httpcontext. Current. response. Redirect ("~ /Showerr. aspx? MSG = "+ message );
}
/// <Summary>
/// Constructor
/// </Summary>
/// <Param name = "message"> exception message </param>
/// <Param name = "innerexception"> exception class that causes this exception </param>
Public myexception (string message, exception innerexception): Base (message, innerexception)
{
}
}
}
Vi. Summary
I found that the value saved in the session. For example, session ["name"] is automatically lost when no request to the server reaches 1 minute, however, the session ID is lost and changed after the browser page of the same process is closed for one minute, because as long as you open the browser, there will be a session ID, whether stored in a URL or in cookies. I don't know if this conclusion is correct. After setting the timeout OF THE SESSION TO 1 minute, the value of session ["name"] is no longer available, but the sessionid is old, global. the code in session_end in asax is not executed, and the authentication ticket is not lost. I don't know what the relationship between the three is like. After who is the first, it seems that a timeout attribute can be set in the <authentication> section, but the project is too busy, so I have no time to study it.
The above code is scattered. It took me two days to summarize this solution. It is not perfect, but it is only possible for the moment. You cannot waste a lot of time in this regard, you can organize the above code into a class, and then modify all methods into static methods for convenient calling.