Updated on: Click: 1 some time ago, SSO (Single Sign-On) for our system was referenced in many documents, including logon to the second-level domain name of the blog Park. this article is due to the author's sentence: all thoughts are the same, but creative thinking is needed to achieve it.
--------------------------------------------------------------------------------
Single Sign-On (SSO) is a hot topic recently. more than one of my clients is running.. Net Framework. they even hope that they can log on to all sites only once in different domain names. today we are focusing on how to implement SSO in different application scenarios. from Simplicity to complexity, we can break through them one by one.
Implement SSO between the master application and sub-Application of the virtual directory
Use different authentication mechanisms to implement SSO (username mapping)
SSO is implemented between applications under a subdomain name in the same domain name.
Implement SSO between applications running in different versions of. NET
Implement SSO between Web applications under two different domain names
Implementing SSO in Forms and Windows
1. Implement SSO between the master application and sub-Application of the virtual directory
Assume there are two. net Web application-Foo and Bar, Bar runs in the subdirectory of the Foo virtual directory (http://foo.com/bar ). both implement Forms authentication. to implement Forms authentication, We need to rewrite Application_AuthenticateRequest. At this time, we will call FormsAuthentication once the authentication passes. redirectFromLoginPage. the parameters received by this method are the user name or some other identity information. in Asp.net, the user login status is stored persistently in the client's cookie. when you call RedirectFromLoginPage, a cookie containing the encrypted token FormsAuthenticationTicket is created. The cookie name is the username of the login user. the configuration section below is in the Web. config defines how to create such a cookie:
<Authentication mode = "Forms">
<Forms name = ". FooAuth" protection = "All" timeout = "60" loginUrl = "login. aspx"/>
Authentication>
<Authentication mode = "Forms">
<Forms name = ". BarAuth" protection = "All" timeout = "60" loginUrl = "login. aspx"/>
Authentication>
The two important attributes are name and protection. According to the following configuration, the Foo and Bar programs can read and write cookies at the same protection level, which achieves the SSO effect:
<Authentication mode = "Forms">
<Forms name = ". SSOAuth" protection = "All" timeout = "60" loginUrl = "login. aspx"/>
Authentication>
When the protection attribute is set to "All", data is encrypted and verified by the Hash value in the Cookie. the keys used for verification and encryption are stored in the machine by default. config file, which can be found in the Web. the Config File overwrites these values. the default value is as follows:
<MachineKey validationKey = "AutoGenerate, IsolateApps" decryptionKey = "AutoGenerate, IsolateApps" validation = "SHA1"/>
IsolateApps indicates that different keys are generated for each application. we cannot use this. to use the same Key in multiple applications to encrypt and decrypt cookies, we can remove the IsolateApps option or use a better method in the Web of all applications that require SSO. set a specific Key value in Config:
<MachineKey validationKey = "F9D1A2D3E1D3E2F7B3D9F90FF3965ABDAC304902" decryptionKey = "decrypt" validation = "SHA1"/>
If you use the same storage method, implementing SSO only changes Web. config.
2. Use different authentication mechanisms to implement SSO (username mapping)
If the FOO site uses the database for authentication, what if the Bar site uses the Membership API or other authentication methods? In this scenario, the cookie created by the FOO site is useless for the Bar site, because the user name in the cookie has no significance for the Bar.
To use cookies, you need to create a cookie for the Bar site for authentication. here you need to map the users of the two sites. assume that the user "John Doe" of a Foo site needs to be identified as "johnd" at the Bar site ". the following code is required for the Foo Website:
FormsAuthenticationTicket fat = new FormsAuthenticationTicket (1, "johnd", DateTime. Now, DateTime. Now. AddYears (1), true ,"");
HttpCookie cookie = new HttpCookie (". BarAuth ");
Cookie. Value = FormsAuthentication. Encrypt (fat );
Cookie. Expires = fat. Expiration;
HttpContext. Current. Response. Cookies. Add (cookie );
FormsAuthentication. RedirectFromLoginPage ("John Doe ");
Hard-coded username to demonstrate. this code snippet creates a token FormsAuthenticationTicket for the Bar site. the user name in the token makes sense in the context of the Bar site. then, call RedirectFromLoginPage to create the correct authentication cookie. in the above example, you have unified the cookie names for Forms authentication, and here you need to make sure they are different-because we do not need two sites to share the same cookie:
<Authentication mode = "Forms">
<Forms name = ". FooAuth" protection = "All" timeout = "60" loginUrl = "login. aspx" slidingExpiration = "true"/>
Authentication>
<Authentication mode = "Forms">
<Forms name = ". BarAuth" protection = "All" timeout = "60" loginUrl = "login. aspx" slidingExpiration = "true"/>
Authentication>
Now, when a user logs on to the Foo site, he will be mapped to the user at the Bar site and created the authentication token for both the Foo and Bar sites. if you want to log on to the Foo site at Bar, the code will be as follows:
FormsAuthenticationTicket fat = new FormsAuthenticationTicket (1, "John Doe", DateTime. Now, DateTime. Now. AddYears (1), true ,"");
HttpCookie cookie = new HttpCookie (". FooAuth ");
Cookie. Value = FormsAuthentication. Encrypt (fat );
Cookie. Expires = fat. Expiration;
HttpContext. Current. Response. Cookies. Add (cookie );
FormsAuthentication. RedirectFromLoginPage ("johnd ");
Make sure that the configuration section of the Web. config of the two sites has the same encryption and decryption Key!
3. SSO is implemented between applications under different subdomains in the same domain name.
In this case how: Foo Bar two sites run under different domain names: http://foo.com and http://bar.foo.com. the above Code does not work: Because cookies are stored in different files and their cookies are invisible to other websites. to make it work, we need to create domain-level cookies, because domain-level cookies are visible to subdomains! Here we can no longer use the RedirectFromLoginPage method, because it cannot create domain-level cookies flexibly and we need to manually complete this process!
FormsAuthenticationTicket fat = new FormsAuthenticationTicket (1, "johnd", DateTime. Now, DateTime. Now. AddYears (1), true ,"");
HttpCookie cookie = new HttpCookie (". BarAuth ");
Cookie. Value = FormsAuthentication. Encrypt (fat );
Cookie. Expires = fat. Expiration;
Cookie. Domain = ".foo.com ";
HttpContext. Current. Response. Cookies. Add (cookie );
FormsAuthenticationTicket fat = new FormsAuthenticationTicket (1, "John Doe", DateTime. Now, DateTime. Now. AddYears (1), true ,"");
HttpCookie cookie = new HttpCookie (". FooAuth ");
Cookie. Value = FormsAuthentication. Encrypt (fat );
Cookie. Expires = fat. Expiration;
Cookie. Domain = ".foo.com ";
HttpContext. Current. Response. Cookies. Add (cookie );
Note cookie. domain = ".foo.com"; pay attention to this line. here we explicitly specify the cookie domain name as ".foo.com", so we ensure that the cookie is visible to the http://foo.com and http://bar.foo.com and other sub-domain names. (Note: cookie domain name matching rules are from right to left ). you can set the domain name of the Bar site's authentication cookie to "bar.foo.com ". in this way, the cookies of other subdomain names are invisible, which ensures security. note that RFC 2109 requires that there are two cycles before the cookie, so we have added an expiration time. (the cookie value is actually a string separated by commas ).
Again, we need to unify the Key value of the Web. config configuration section of each site. This solution only has one exception, and you can refer to the following section for details.
4. run in different versions of. Net to implement SSO between applications
If Foo and Bar are running on different sites. the above examples in the. Net environment do not work. this is because Asp.net 2.0 uses an encryption algorithm different from 1.1: 1.1 uses 3DES and 2.0 uses AES. fortunately, Asp. one attribute in net2.0 is 1.1 compatible:
<MachineKey validationKey = "F9D1A2D3E1D3E2F7B3D9F90FF3965ABDAC304902" decryptionKey = "encrypt" validation = "SHA1" decryption = "3DES"/>
When decryption = "3DES" is set, ASP. NET 2.0 uses an earlier version of the encryption algorithm to enable normal use of cookies. do not try in Asp. net1.1 Web. if this attribute is added to the config file, an error is returned.
5. Implement SSO for applications under two different domain names
We have successfully created a shared authentication Cookie, but what if the Foo site and Bar site are under different domain names, such as: http://foo.com and http://bar.com? They cannot share cookies or create a readable cookie for the other party. in this case, each site needs to create its own cookie and call the pages of other sites to verify whether the user is logged on. one of the implementation methods is to use a series of redirection.
To achieve this goal, we need to create a special page (for example, sso. aspx ). this page is used to check whether the cookie under this domain name exists and return the username of the logged-on user. in this way, other sites can also create a cookie for this user. below is the sso of Bar.com. aspx:
Bar.com:
<Script language = "C #" runat = "server">
Void Page_Load ()
{
// This is our caller, we will need to redirect back to it eventually
UriBuilder uri = new UriBuilder (Request. UrlReferrer );
HttpCookie c = HttpContext. Current. Request. Cookies [". BarAuth"];
If (c! = Null % 26amp; % 26amp; c. HasKeys) // the cookie exists!
{
Try
{
String cookie = HttpContext. Current. Server. UrlDecode (c. Value );
FormsAuthenticationTicket fat = FormsAuthentication. Decrypt (cookie );
Uri. Query = uri. Query + "% 26amp; ssoauth =" + fat. Name; // add logged-in user name to the query
}
Catch
{
}
}
Response. Redirect (uri. ToString (); // redirect back to the caller
}
Script>
This page is always redirected back to the called site. If Bar.com has an authentication cookie, it decrypts the user name in the ssoauth parameter.
At the other end (Foo.com), we need to add some code to the HTTP Rquest pipeline. it can be the Application_BeginRequest event of the Web application, or the custom HttpHandler or HttpModule. the basic idea is to intercept all Foo.com page requests and check whether the cookie exists as soon as possible:
1. If the Foo.com authentication cookie already exists, process the request. The user has logged on to Foo.com.
2. Redirect to Bar.com/sso.aspx if the authentication Cookie does not exist.
3. If the current request is directed back from bar.com/sso.aspx, analyze the authentication cookie created if the authorization is enabled.
The path is simple, but there are two more places to pay attention to the endless loop:
// See if the user is logged in
HttpCookie c = HttpContext. Current. Request. Cookies [". FooAuth"];
If (c! = Null % 26amp; % 26amp; c. HasKeys) // the cookie exists!
{
Try
{
String cookie = HttpContext. Current. Server. UrlDecode (c. Value );
FormsAuthenticationTicket fat = FormsAuthentication. Decrypt (cookie );
Return; // cookie decrypts successfully, continue processing the page
}
Catch
{
}
}
// The authentication cookie doesn' t exist-ask Bar.com if the user is logged in there
UriBuilder uri = new UriBuilder (Request. UrlReferrer );
If (uri. Host! = "Bar.com" | uri. Path! = "/Sso. aspx") // prevent infinite loop
{
Response. Redirect (http://bar.com/sso.aspx );
}
Else
{
// We are here because the request we are processing is actually a response from bar.com
If (Request. QueryString ["ssoauth"] = null)
{
// Bar.com also didn't have the authentication cookie
Return; // continue normally, this user is not logged-in
} Else
{
// User is logged in to Bar.com and we got his name!
String userName = (string) Request. QueryString ["ssoauth"];
// Let's create a cookie with the same name
FormsAuthenticationTicket fat = new FormsAuthenticationTicket (1, userName, DateTime. Now, DateTime. Now. AddYears (1), true ,"");
HttpCookie cookie = new HttpCookie (". FooAuth ");
Cookie. Value = FormsAuthentication. Encrypt (fat );
Cookie. Expires = fat. Expiration;
HttpContext. Current. Response. Cookies. Add (cookie );
}
}
Make sure that you use the correct cookie name (. fooAuth .. barAuth ). because cookies are not truly shared, because Web applications have different configuration sections. there is no need to unify the encryption and decryption keys here.
Some people regard the user name as a parameter in the url as a treasure. in fact, there are two things to protect: first, we can check that the reference page parameters do not accept sites other than bar.com/sso.aspx (or foo.com/ssp.aspx. second, the user name can be encrypted using the same Key. if Foo and Bar use different authentication mechanisms, additional user information (such as email addresses) can also be transmitted.
6. Implement SSO in Forms and Windows Mode
The above are all Forms authentication processes. let's design the authentication process like this: Do Forms authentication first. If the authentication fails, check whether the Intranet user has logged on to the NT domain. in this way, we need to check the following parameters to view the Windows logo information associated with the request:
Request. ServerVariables ["LOGON_USER"]
However, this value is always blank unless Anonymous logon is disabled for all sites. we can disable anonymous logon on the control panel of IIS and enable Windows Integration authentication for our site. in this way, the LOGON_USER value contains the name of the login user in the NT domain. however, all Internet users will encounter user names and passwords, which is not good. We want Internet users to use Forms authentication. If this method fails, then use Windows domain authentication.
One of the solutions to this problem is to set a special portal page for Intranet users: Windows integrated authentication method is available, Domain Users are verified, and Forms cookies are created to redirect to the main site. we can even hide the fact that the Server. transferIntranet users actually access different pages.
There is also a simple solution. the foundation of this method is that IIS controls authentication processing. if the site is available to anonymous users, IIS will pass the request to the Asp.net runtime. if the authentication fails, a 401 error is thrown. IIS will try to find other authentication methods for this site. you need to set anonymous access and Integration authentication to be available and execute the following code after Forms authentication fails:
If (System. Web. HttpContext. Current. Request. ServerVariables ["LOGON_USER"] = ""){
System. Web. HttpContext. Current. Response. StatusCode = 401;
System. Web. HttpContext. Current. Response. End ();
}
Else
{
// Request. ServerVariables ["LOGON_USER"] has a valid domain user now!
}
When this code is executed, it checks the domain user and obtains an empty initial value. this operation terminates the current request and returns the authentication error 401 to IIS. this allows IIS to automatically select another authentication mechanism. Windows integrated authentication is a candidate method. if the user can log on to the domain, the request can be continued and the information of the NT domain user is appended. if the user does not log on in the domain, there will be three chances to enter the user name and password. if it fails three times, the system will get an error 403 (AccessDenied ).
Conclusion
We have examined how to implement SSO between two Asp.net applications in various scenarios. We can also implement SSO between different systems and different platforms. The idea is the same, but creative thinking is needed to achieve it.
Source Document Http://www.yfeshop.cn/html/NETboke/200811/-yi-SSOjiejuefangandaquanSingleSign-Onforeveryone_4393.html