The lab environment configuration host file is configured as follows:
127.0.0.1 app.com
127.0.0.1 sso.com
IIS is configured as follows:
Application pools with the. Net Framework 4.0
Note The IIS-bound domain name, two completely different domain names.
The App.com website is configured as follows:
The Sso.com website is configured as follows: Memcached cache:
Database configuration:
The database uses EntityFramework 6.0.0, and the first run automatically creates the corresponding database and table structure.
The authorization verification process demonstrates:
Access in the browser address bar: http://app.com, if the user has not logged in the site will be automatically redirected to: Http://sso.com/passport, while the querystring through the parameters of the corresponding Appkey app identity passed over, Run as follows:
URL Address: http://sso.com/passport?appkey=670b14728ad9902aecba32e22fa4f6bd&username=
After entering the correct login account and password, click the Login button system automatically 301 redirect to the app will drop the home page, destroy the success as follows:
Because SSO authorization is logged under different domains, the authorization identity is returned in querystring manner. Cookies can be used under the same domain website. Since the 301 redirect request is sent by the browser, the browser redirection is lost if the authorization ID is placed in handers. After the redirect succeeds, the program automatically writes the authorization ID to the cookie, and when you click on a different page address, the authorization information is no longer visible in the URL address bar. The cookie is set as follows:
Follow-up authorization verification after successful login (access other pages that require authorization access):
Verify Address: http://sso.com/api/passport?sessionkey=xxxxxx&remark=xxxxxx
return Result: True,false
Depending on the actual business situation, the client may choose to prompt the user that the authorization has been lost and need to be re-authorized. Default automatic redirection to SSO landing page, i.e.: Http://sso.com/passport?appkey=670b14728ad9902aecba32e22fa4f6bd&[email protected] At the same time landing page email address text box will be customized to complete the user's login account, the user only need to enter the login password can be authorized after the successful session of the duration of the automatic extension of one year.
SSO Database Validation Log:
User Authorization Verification log:
User Licensing Sessions session:
Database user account and application information:
Application Authorization Login Verification page core code:
1//<summary> 2//Public key: AppKey 3///private key: Appsecret 4//session: SessionKey 5//</SUMMARY&G T 6 public class Passportcontroller:controller 7 {8 private readonly iappinfoservice _appinfoservice = New Appinfoservice (); 9 private readonly Iappuserservice _appuserservice = new Appuserservice (); Ten private readonly Iuserauthsessionservice _authsessionservice = new Userauthsessionservice (); One private readonly iuserauthoperateservice _userauthoperateservice = new Userauthoperateservice (); The private const string AppInfo = "AppInfo"; The private const string sessionkey = "SessionKey"; The private const string sessionusername = "Sessionusername"; 16 17//Default login interface public ActionResult Index (String appKey = "", String username = "") 19 {20 Tempdata[appinfo] = _appinfoservice.get (AppKey); var ViewModel = new Passportloginrequest 23 {AppKey = AppKey, UserName = UserName 26}; Return View (ViewModel); 29} 30 31//Authorized login [HttpPost] public actionresult Index (passportloginrequest model) 34 {35//Get application information var appInfo = _appinfoservice.get (model. AppKey); PNS if (appInfo = = null) 38 {39//application does not exist with a return View (model); 41 } Tempdata[appinfo] = AppInfo; if (Modelstate.isvalid = = False) 46 {47//entity validation failed View (model); 49} 50 51//filter field Invalid character in the model. Trim (); 53 54//Get user information in var userInfo = _appuserservice.get (model. UserName); if (UserInfo = = null) 57 {58//user does not exist on the return View (model); 60 } 61 62 if (userinfo.userpwd! = model. PASSWORD.TOMD5 ()) 63 {64//password incorrect + return View (model); 66} 67 68//Get current unexpired session var currentsession = _authsessionservice.existsbyvalid (Appinfo.appkey, use Rinfo.username); if (currentsession = = null) 71 {72//build session Currentsessi on = new Userauthsession AppKey = Appinfo.appkey, creat ETime = DateTime.Now, Invalidtime = DateTime.Now.AddYears (1), IpAddress = Re Quest. userhostaddress, SessionKey = Guid.NewGuid (). ToString (). ToMd5 (), UserName = Userinfo.username 81}; 82 83//Create session _authsessionservice.create (Currentsession); 87} (88 Extended validity period, default one year _authsessionservice.extendvalid (Currentsession.sessionkey); 90} 91 92//Record User authorization log _userauthoperateservice.create (new Userauthoperate 94 {createtime = DateTime.Now, IpAddress = request.userhostaddress, 97 Remark = string. Format ("{0} login {1} authorization succeeded", Currentsession.username, Appinfo.title), 98 SessionKey = Currentsession.sessionk EY 99}); 104 var RedirectURL = string. Format ("{0}"? SESSIONKEY={1}&SESSIONUSERNAME={2} ", 106 Appinfo.returnurl, 107 Currentsession.sessionk EY, 108 userinfo.username); 109 110//Jump default callback page 111 return Redirect (RedirectURL); 112 }113}
memcached session ID validation Core code:
public class Passportcontroller:apicontroller {private readonly Iuserauthsessionservice _authsessionservice = New Userauthsessionservice (); Private readonly Iuserauthoperateservice _userauthoperateservice = new Userauthoperateservice (); public bool Get (string sessionkey = "", String remark = "") {if (_authsessionservice.getcache (Sessionke Y) {_userauthoperateservice.create (new Userauthoperate {Cre Atetime = DateTime.Now, IpAddress = Request.RequestUri.Host, Remark = string. Format ("Validation succeeded-{0}", remark), SessionKey = SessionKey}); return true; } _userauthoperateservice.create (new userauthoperate {createtime = DateTime.Now, IpAddress = Request.RequestUri.Host, Remark = string. Format ("Validation failed-{0}", remark), SesSionkey = SessionKey}); return false; } }
Client Authorization Verification Filters Attribute
public class Ssoauthattribute:actionfilterattribute {Public Const string sessionkey = "SessionKey"; Public Const string sessionusername = "Sessionusername"; public override void OnActionExecuting (ActionExecutingContext filtercontext) {var cookiesessionkey = "" ; var cookiesessionusername = ""; SessionKey by QueryString if (Filtercontext.httpcontext.request.querystring[sessionkey]! = null) { Cookiesessionkey = Filtercontext.httpcontext.request.querystring[sessionkey]; FILTERCONTEXT.HTTPCONTEXT.RESPONSE.COOKIES.ADD (New HttpCookie (SessionKey, Cookiesessionkey)); }//sessionusername by QueryString if (filtercontext.httpcontext.request.querystring[sessionusername ] = null) {Cookiesessionusername = Filtercontext.httpcontext.request.querystring[sessionuserna Me]; FilterContext.HttpContext.Response.CooKies. ADD (New HttpCookie (Sessionusername, cookiesessionusername)); }//read from Cookie SessionKey if (filtercontext.httpcontext.request.cookies[sessionkey]! = NULL) {Cookiesessionkey = Filtercontext.httpcontext.request.cookies[sessionkey]. Value; }//read from Cookie Sessionusername if (filtercontext.httpcontext.request.cookies[sessionusername]! = NULL) {cookiesessionusername = Filtercontext.httpcontext.request.cookies[sessionusername]. Value; } if (string. IsNullOrEmpty (Cookiesessionkey) | | String. IsNullOrEmpty (Cookiesessionusername)) {//Direct login Filtercontext.result = Ssologinres Ult (Cookiesessionusername); } else {//verify if (Checklogin (Cookiesessionkey, Filtercontext.httpconte Xt. Request.rawurl) = = False) {//session lost, jump to login page Filtercontext.result = Ssologinresult (cookiesessionusername); }} base. OnActionExecuting (Filtercontext); public static bool Checklogin (string sessionkey, string remark = "") {var httpClient = new Htt pclient {baseaddress = new Uri (configurationmanager.appsettings["Ssopassport"])}; var RequestUri = string. Format ("Api/passport?sessionkey={0}&remark={1}", SessionKey, remark); try {var resp = Httpclient.getasync (RequestUri). Result; Resp. Ensuresuccessstatuscode (); Return resp. Content.readasasync<bool> (). Result; } catch (Exception ex) {throw ex; }} private static ActionResult Ssologinresult (string username) {return new Redirectresul T (string. Format ("{0}/passport?appkey={1}&username={2}", configurationmanager.appsettings["Ssopassport"], configurationmanager.appsettings["SSOAp PKey "], username)); } }
Sample SSO Validation Attribute usage:
[Ssoauth] public class Homecontroller:controller {public actionresult Index () { return View (); } Public ActionResult About () { viewbag.message = "Your Application description page."; return View (); } Public ActionResult Contact () { viewbag.message = ' Your contact page. '; return View (); } }
Summarize:
From the draft sample code, you can see that there are many optimizations in code performance, as well as a series of informational messages such as a user account that does not exist for the SSO Application authorization landing page, a password error, and so on. After the business code is running basically correctly, you can consider optimizing for more security aspects, such as enabling Appsecret private key signature verification, IP range authentication, fixed session request attack, authentication code for the SSO authorization login interface, session cache auto-rebuild, SSO server, level expansion of the cache, etc.
Source Address: Https://github.com/smartbooks/SmartSSO
ASP. NET MVC SSO Single Sign-on design and implementation