1, HTTP stateless protocol Web application adopts Browser/Server architecture, HTTP as a communication protocol. HTTP is a stateless protocol. Each request of the browser is handled by the server independently, without any connection with the previous or subsequent requests. This process is illustrated in the following figure, and there is no connection between the three request/response pairs

But it also means that any user can access server resources through the browser, and if you want to protect certain resources on the server, you must restrict browser requests; To limit browser requests, you must identify browser requests, respond to legitimate requests, and ignore illegal requests. To identify a browser request, you must know the state of the browser request. Since the HTTP protocol is stateless, let the server and browser maintain a state together! This is the conversational mechanism

2, session mechanism browser requests the server for the first time, the server creates a session, and the session id as part of the response sent to the browser, the browser session id, and in the subsequent second and third take a session id in the request, the server has requested session id will know whether the same user, this process using an illustration, Subsequent requests are associated with the first request

The server stores the session object in memory. How does the browser store the session ID? You can think of two ways

The request parameter cookie takes the session ID as the parameter of each request. When the server receives the request, it can parse the parameter to get the session ID and determine whether it is from the same session. Obviously, this method is not reliable. The browser maintains the session ID itself. The browser automatically sends the session ID every time an HTTP request is made, and the cookie mechanism is used to do just that. Cookie is a mechanism used by the browser to store a small amount of data. Data is stored in the form of “key/value”, and the browser automatically sends the cookie information along with the HTTP request

Of course, Tomcat session mechanism also implements cookie. When accessing Tomcat server, you can see a cookie named “JSessionID” in the browser, which is the session ID maintained by Tomcat session mechanism. The request response process using cookie is shown in the figure below

3, login status with the session mechanism, login status is easy to understand, we assume that the first time the browser requests the server needs to enter the user name and password to verify identity, the server gets the user name and password to compare with the database, if correct, it means that the current user holding this session is a legitimate user. This session should be marked as “authorized” or “logged in” or something like that. Since it is the state of the session, it should be stored in the session object. Tomcat sets the login status in the session object as follows: Tomcat looks at the login status in the session object when the user revisits

HttpSession session = request.getSession();
session.setAttribute("isLogin", true);
HttpSession session = request.getSession();
session.getAttribute("isLogin");

The browser request server model with login status implemented is described in the figure below

The login mechanism is implemented by checking the login status in the session object each time a protected resource is requested, and only the session that isLogin=true can access it.

Web system has long been developed from a single system to an application group composed of multiple systems. Faced with so many systems, do users need to log in one by one, and then log out one by one? It looks like this

Web system develops from a single system into an application group composed of multiple systems. Complexity should be borne by the system itself, rather than the users. No matter how complex the web system is inside, it is a unified whole for users, that is to say, users can access the entire application group of the web system just as they can access a single system, and it is enough to log in/log out once

Although the single-system login solution is perfect, it is no longer suitable for multi-system application groups. Why?

At the heart of the single-system login solution is the cookie, which carries the session ID to maintain session state between the browser and the server. But there is a limit to cookies. This limit is the domain of the cookie (usually the domain name of the website). When the browser sends an HTTP request, it automatically carries the cookies that match that domain, not all the cookies

In this case, why not put all subsystems in a web application cluster under one top-level domain name, such as “*.baidu.com”, and then set their cookie field to “baidu.com”, which is theoretically possible. Even in the early days, many multi-system logins used this method of sharing cookies with the domain name.

However, what works is not good, and there are many limitations to the way cookies are shared. First, the application group domain name must be unified; Secondly, the technology used by each system of the application group (at least the Web server) should be the same, otherwise the key value of the cookie (tomcat is JSessionID) is different, unable to maintain the session, the way of sharing the cookie is unable to achieve cross-language technology platform login, such as Java, PHP,.NET system; Third, cookies themselves are not secure.

Therefore, we need a new login method to realize multi-system application group login, which is single sign-on

What is Single Sign-On? The full name of Single Sign On (hereinafter referred to as SSO) refers to that when you log in one system in a multi-system application group, you can be authorized in all other systems without needing to log in again, including Single sign-on and Single sign-off

Compared with a single system login, SSO needs an independent authentication center, only the authentication center can accept the user’s username and password and other security information, other systems do not provide login entry, only accept the indirect authorization of the authentication center. Indirect authorized by token, sso authentication center to verify the user’s user name password no problem, create the authorization token, in the process of the next jump, authorization token as parameters sent to each subsystem, subsystem get tokens, quick to authorize, to create a local session, local session login method with single system login the same way. This process, the principle of single sign-on, is illustrated in the following figure

When the user accesses the protected resources of System 1, System 1 finds that the user is not logged in, jumps to the SSO Certification Center, and takes his/her address as the parameter. SSO Certification Center finds that the user is not logged in, directs the user to the login page, and the user enters the user name and password to submit the login application. SSO Certification Center verifies the user information. Create a session between the user and the SSO Certification Authority, called a global session, and create an authorization token. The SSO Certification Authority takes the token and redirect it to the original request address (System 1). System 1 gets the token and goes to the SSO Certification Authority to verify that the token is valid. Registration system 1 1 USES the token creation and the user’s session, referred to as the local session, return the user to access the protected resources system 2 2 found that users are not protected resources system login, jump to the sso authentication center, and your address as a parameter sso authentication center found that the user is logged in, jump back to the system 2 address, System 2 gets the token and goes to the SSO Certification Center to verify whether the token is valid. SSO Certification Center verifies the token and returns valid. System 2 uses the token to create a local session with the user and returns the protected resource. The session established between the user and the SSO Certification Authority is called the global session, and the session established between the user and each subsystem is called the local session. After the local session is established, the user will no longer access the protected resources of the subsystem through the SSO Certification Authority. The global session and the local session have the following constraint relationship

You can deepen your understanding of single sign-on through the login process of Blog Park, Baidu, CSDN, Taobao and other websites. Pay attention to the jump URL and parameters in the login process

Logout Single sign-on is also a natural single sign-off, in a subsystem logout, all subsystem sessions will be destroyed, as illustrated by the following figure

The SSO Certification Authority is always listening for the status of the global session, and once the global session is destroyed, the listener notifies all registry systems to perform a logout

A brief explanation of the above figure is given below

The user initiates a logout request to System 1. System 1 obtains the token based on the session ID established between the user and System 1 and initiates a logout request to the SSO Certification Center. At the same time, take out all the system addresses registered with this token, SSO Certification Authority issues a logout request to all the registration systems. Each registration system receives the logout request from SSO Certification Authority, destroy the local session. SSO Certification Authority leads the user to the login page. The subsystem and the SSO authentication center need to communicate to exchange tokens, verify tokens and initiate logout requests, so the subsystem must integrate the SSO client, and the SSO authentication center is the SSO server. The whole single sign-on process is essentially the communication process between the SSO client and the server, as described in the following figure

The SSO Certification Authority can communicate with SSO clients in a variety of ways, including Web Services, RPC, and RESTful APIs, such as the simple and easy-to-use HttpClient

Five, implementation is only a brief introduction to the implementation process based on Java, do not provide complete source code, understand the principle, I believe you can achieve their own. SSO uses a client/server architecture. Let’s first look at the functions of sso-client and sso-server.

sso-client

Intercept the request of the unlogged user in the subsystem, skip to the SSO Certification Center to receive and store the token sent by the SSO Certification Center to communicate with the SSO-server, verify the validity of the token, establish a local session to intercept the user’s logout request, send the logout request to the SSO Certification Center and receive the logout request sent by the SSO Certification Center. Destroy the local session sso-server

Verify user login information create global session create authorization token communicate with sso-client send token verify sso-client token validity system register receive sso-client logout request log off all sessions let’s follow the principle of implementing sso step by step.

Java intercepts requests in three ways: Servlet, Filter, Listener. We use Filter. Create a new LoginFilter.java class in sso-client and implement the Filter interface. Add interception for unlogged users in doFilter() method

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; HttpSession session = req.getSession(); if (session.getAttribute("isLogin")) { chain.doFilter(request, response); return; } // Go to Res. sendRedirect("sso-server-url-with-system-url"); }

Intercepting Unlogged Requests Intercepts unlogged requests that jump from the Sso-client to the SSO Authentication Authority and are redirected to the login page in exactly the same way as the Sso-client

The user enters the username and password on the login page and requests to log in. The SSO Certification Center verifies the user’s information and marks the session status as “Login” after successful verification.


@RequestMapping("/login")

public String login(String username, String password, HttpServletRequest req) {

    this.checkLoginInfo(username, password);

    req.getSession().setAttribute("isLogin", true);

    return "success";

}

An authorization token is a random string of characters. It doesn’t matter which way it is generated, as long as it is not duplicated and is not easy to forge. Here is an example

String token = UUID.randomUUID().toString();

After the SSO authentication authority logs in, it jumps back to the subsystem and appends the token. The subsystem (sso-client) acquires the token and goes to the SSO authentication authority to verify it. Add a few lines to doFilter() in LoginFilter.java

String token = req.getParameter("token"); if (token ! Boolean verifyResult = this.verify(" sso-server-verific-url ", token); if (! verifyResult) { res.sendRedirect("sso-server-url"); return; } chain.doFilter(request, response); }

The verify() method is implemented using HttpClient. This is a brief introduction. See the official documentation for details on how to use HttpClient

HttpPost httpPost = new HttpPost("sso-server-verify-url-with-token");

HttpResponse httpResponse = httpClient.execute(httpPost);

After the user logs in to the SSO Certification Authority, the Sso-Server creates the authorization token and stores it. Therefore, the Sso-Server validates the token to find out whether the token exists and whether it has expired. Upon successful token validation, the sso-server registers the system sending the validation request with the SSO Certification Authority (” stored “).

The token and registration system address are usually stored in a key-value database such as Redis, which can set a valid time for the key, which is the period of validity of the token. Redis runs in memory and is very fast, just as sso-server does not need to persist any data.

Token and registration system addresses can be stored in Redis using the structure described in the following figure. You may ask, why store these system addresses? If you do not store it, you will be in trouble when logging out. The user submits a logout request to the SSO Certification Authority, and the SSO Certification Authority logs out the global session, but it does not know which systems have established their own local session with this global session, and it does not know which subsystems to send a logout request to log out the local session

After successful token validation, the sso-client marks the current local session as “Login”, modifies loginfilter.java, and adds a few lines


if (verifyResult) {

    session.setAttribute("isLogin", true);

}

The sso-client also needs to bind the current session ID to the token, indicating that the login status of the session is associated with the token. This relationship can be stored in a Java HashMap, and the saved data can be used to handle logout requests from the SSO Certification Authority

The user sends a request (logout request) with “logout” parameter to the subsystem. The SSO-Client interceptor intercepts the request and sends the logout request to the SSO Certification Authority

String logout = req.getParameter("logout"); if (logout ! = null) { this.ssoServer.logout(token); }

In the same way, the SSO Certification Authority identifies the SSO-client’s request as a logout request (with the “logout” parameter), and the SSO Certification Authority logs out the global session

@RequestMapping("/logout") public String logout(HttpServletRequest req) { HttpSession session = req.getSession(); if (session ! = null) { session.invalidate(); // trigger logoutListener} return "redirect:/"; }

The SSO Certification Authority has a listener for the global session and notifies all registration systems to log off once the global session is logged off

public class LogoutListener implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent } @Override public void sessionDestroyed(HttpClient) {// Send a write-off request to all registration systems via HttpClient}}