SSO Service Source Analysis

Source: Internet
Author: User

SSO English full name Single sign on, one-point login. SSO is a multi-application system in which users can access all trusted applications with only one login.

the essence of single sign-on is to solve how to generate and store trust, and then how other systems verify the validity of this trust, so the key points are as follows:

    • Storage Trust
    • Verifying trusts

as long as the above problem has been solved, it is possible to say that the result of the beginning is SSO. The simplest way to implement SSO is to use cookies to implement the process as follows:


However, there are two problems with the implementation of cookies:

    • cookies are not secure
    • no cross-domain free

The first problem can be dealt with by a cookie, and the second problem is flawed.

There are many implementations of SSO in addition to cookies, where a cookie-based implementation of the source code is analyzed for a moment.


first give the conclusion of this analysis, the specific source affixed to the conclusion.

concrete implementation of logical summary
  • Sets the filter for the Web app to initialize the (which contains login validity ticket The user's business data (such as UserID) httpservletrequest and httpservletresponse ) ).
  • read cookies get ticket into ssoinfo, none ticket null
  • Store the Ssoinfo in a container with a thread isolation level (implemented here using threadlocal)
  • set the interceptor before the controller that needs to be intercepted, and validate the ticket contained in the Ssoinfo. (There is a lot of implementation of the validation here, the system is using Redis to store and manage ticket effectiveness)
  • Invalid ticket boot login, create ticket (implemented by specific field with Uuid.randomuuid ();), save (Redis as key store value for user ID), management (Redis set timeout rule) Ticket

The above is the specific implementation logic of this SSO system. It is simple to analyze and implement logic. can be applied to a general small single domain site .

The following is a concrete implementation code:

Web project Settings initialization filter.

Web. XML

<filter>     <filter-name>AuthFilter</filter-name>     <filter-class> com.jc.sso.client.authfilter</filter-class> </filter> <filter-mapping>     <filter-name> Authfilter</filter-name>     



AuthFilter: Read cookies initialization ssoinfo

public void DoFilter (ServletRequest request, servletresponse response, Filterchain chain) throws IOException, servletexception {    Ssoinfo info = Ssocookieutil.vistssocookie ((httpservletrequest) request);  Ssomanager.setssoinfo (info);  Info.setrequestobj ((httpservletrequest) request);  Info.setresponseobj ((httpservletresponse) response);  try {  //pass the request along the filter chain  chain.dofilter (request, response);  } finally {  ssomanage R.clearssoinfo ();  }  



Ssoinfo

The ticket bean that records SSO, for additional information acquisition, also Records HttpServletRequest and HttpServletResponse (here only for additional information records, such as access to IP addresses, etc.).


private user user;  Private String ticket;  Private string uid;//identifies the PC host's ID    private string app;  /**   * has the ticket check * */  Private Boolean isvalidated = false;    Private HttpServletRequest requestobj;  Private HttpServletResponse responseobj;    public boolean IsLogin () {  if (ticket = = null) {  return false;  }  if (!isvalidated) {  throw new notvalidateexception ();  }    return user! = NULL;  



Ssocookieutil

the Operation class of a cookie

public static Ssoinfo Vistssocookie (HttpServletRequest request) {  cookie[] cookies = getallcookies (request);  if (cookies = null | | cookies.length = = 0) {  return new ssoinfo (null);  }  String ticket = null;  String uid = "none";  for (Cookie cookie:cookies) {  if (ticket_grant_ticket_cookie.equals (Cookie.getname ())) {  TICKET = Cookie.getvalue ();  } else if (Uid_cookie.equals (Cookie.getname ())) {  ticket = Cookie.getvalue ();  }  }    Ssoinfo si = new Ssoinfo (ticket);  Si.setuid (UID);  String app = SsoManager.config.getValue (ssomanager.config_app_id);  Si.setapp (app);    Return si;  

The initial access returns a ticket null ssoinfo.


Stores thread-level ssoinfo. (Note that the above is the initialization in filter, at which time the request continues to be distributed)



Ssomanager

private static threadlocal<ssoinfo> Tempstore = new threadlocal<ssoinfo> ();       public static Ssoinfo Getssoinfo () {  return tempstore.get ();  }    public static void Setssoinfo (Ssoinfo info) {  tempstore.set (info);  



setting interceptors in requests


<mvc:interceptors>      <mvc:interceptor>         <mvc:mapping path= "/user/*.html"/>         <bean class= "Com.jc.site.common.interceptor.UserAccountInterceptor" ></bean>      </mvc:interceptor> </mvc:interceptors>    


Useraccountinterceptor.prehandle

if (Ssomanager.validatewebticket ()) {//Login status     


Verifying logon status

public static Boolean Validatewebticket () {  Ssoinfo si = Tempstore.get ();  if (SI = = null) {  Logger.warn ("The Ssoinfo object is missed, check whether some unexpected operation on ThreadLocal are Executed! ");  return false;  }  Validate2server (SI);  return Si.islogin ();  



Validate2server

private static void Validate2server (Ssoinfo si) {  if (si = = null) {  return;  }    if (si.isvalidated ()) {  return;  }    if (si.getticket () = = NULL | | si.getticket (). Length () = = 0) {  si.setvalidated (true);  return;  }  ............ (Background is remote call authentication system incoming ticket)    


Verification System


@RequestMapping (value = "validate.html")  @ResponseBody public  String validatelogin (@RequestParam (value= "T") , Required=false) string ticket, String app,  @RequestParam (value= "did", Required=false) string deviceId) {  if ( Stringutils.isempty (Ticket)) {  return Seterrorview ("Ticket value is empty");  } else if (Stringutils.isempty (app)) {  return Seterrorview ("app type cannot be empty");  } else if (Stringutils.isempty ( DEVICEID) {  return Seterrorview ("Device ID is empty");  }  try {  String user = AUTHMANAGER.CHECKTGT (ticket, app);  if (user! = null) {  return buildsuccessresponse (user);  } else {  return builderrorresponse (user);  }    } catch (Exception e) {  logger.error ("Login exception (unexpected)", e);  Return Seterrorview ("service exception, please try again later");  }  


this takes ticket as key to get the UserID information from Redis.


public string checktgt (string tgt, string app) {  string user = null;  try{  user = Redistemplate.get (TGT);  int tmpapp = Stringutil.getintvalue (app, ssoconstant.app_site);  if (! Stringutils.isempty (user) {  prolongticket (tgt,app, User, Getvaliatetime (Tmpapp));}    } catch (Exception e) {  logger.error ("Check TGT exception:", e);  }  return user;  


The above is the entire certification process, the following is the landing process


try {  userindb = loginserviceimpl.login (user),  } catch (Passwordnotmatchexception e) {  if ( Logger.isinfoenabled ()) {  Logger.info ("Login failed, password error");  }  }     4. In case of successful landing, generate ticket  user.settype (ssoconstant.app_site);  



public string generatesitetgt (httpservletrequest request,httpservletresponse Response, string app, user user) {  String TGT = null;  try{  uuid uuid = Uuid.randomuuid ();  TGT = app + "-" + Ssoconstant.ticket_grant_ticket + "-" + uuid.tostring (). ReplaceAll ("-", "" ");  int tmpapp = Stringutil.getintvalue (app, ssoconstant.app_site);  int longlogin = Getvaliatetime (Tmpapp);  Setupticket (TGT, App, "", User, longlogin);    Cookie ticket = new Cookie (Ssoconstant.ticket_grant_ticket_cookie, TGT);  String domain = propertiesutil.getstring (ssoconstant.propery_domain);  Ticket.setdomain (domain);  Ticket.setpath ("/");  Ticket.setmaxage (longlogin);    Response.addcookie (ticket);  } catch (Exception e) {  logger.error ("Generate TGT Exception:", e);  }  return TGT;  }


private void Setupticket (String ticket, String app, string deviceId, user user, int longlogin) {  if (ticket = = null) {  return;  }    if (Longlogin < 1) {  //Save 30 minutes  Longlogin = Ssoconstant.ticket_grant_ticket_time_out_default;  }  String Oldticket = redistemplate.get (App + "_" + User.getuserid ());  if (oldticket! = null) {  redistemplate.delkey (oldticket);  }  Redistemplate.setex (Ticket, Longlogin, User.getid () + ":" + User.getuserid ());  Redistemplate.setex (App + "_" + User.getuserid (), Longlogin, ticket);  




SSO Service Source Analysis

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.