This is the sixth day of my participation in the More text Challenge. For details, see more text Challenge

I have participated in the weekend study program. Please click the link to see more details

In JavaWeb our projects are a little more formal

Javaweb in our project a little more formal point, will use single sign-on this technology. There are different views on how to do it. Due to the company's project needs, we are studying these days. Below tidy up the recent tidy up of experience.Copy the code

Introduction to the

  • In distributed projects, data sharing (i.e., Session sharing) is a major headache, and data loss often occurs. To solve this Bug. We have been given two solutions. I’m going to do both here today. The emphasis is on the second method

Configure Tomcat to implement session sharing


Configure Tomcat

  • Download the above JAR package and place it in the Tomcat lib file.

  • Then modify the conf/context. XML file in Tomcat
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" /> <Manager The className = "com. Orangefunction. Tomcat. Redissessions. RedisSessionManager" host = "192.168.1.130" port = "7006" database = "db0" maxInactiveInterval="60" />Copy the code
  • The host and port configured above are the host and port of our Redis, so we need to start a redis service first.

I want to see how to configure redis and spring integration point. I want to see how to configure redis and spring integration point

  • Database is the location in Redis of the session generated by tomcat and the browser

  • MaxInactiveInterval specifies the cache expiration time. But in actual testing I found that this attribute did not work. (What do you think?)

At this point our first Tomcat configuration is complete. The following is to repeat the above steps to configure a few more Tomcat

Configure nginx

  • Nginx has many functions. It can be used as an HTTP server, reverse proxy server, and mail server. Supports FastCGI, SSL, Virtual Host, URL Rewrite, and Gzip. It also supports many third-party module extensions.

  • Nginx download website has a ready-made, directly download the version of your computer to install the idiot on the line. (Install or decompress do not appear In Chinese)

  • Go to the conf/nginx.conf file and change the Settings there

-listen 802: port we are listening to -server_name 192.168.1.130: address we are listening to -proxy_pass http://mynginxserver: Configure multiple Tomcat servers in mynginxServer:Copy the code
Upstream mynginxserver {server 192.168.1.78:8080 weight=1; Server 192.168.1.130:8080 weight = 1; }Copy the code
  • Complete the configuration
Upstream mynginxserver {server 192.168.1.78:8080 weight=1; Server 192.168.1.130:8080 weight = 1; } server { listen 802; Server_name 192.168.1.130; #charset koi8-r; #access_log logs/host.access.log main; location / { proxy_pass http://mynginxserver; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php${# proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php${# root HTML; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #}}Copy the code
  • At this point both of our Tomcats are running and we are typing in the browser
192.168.1.130:802
Copy the code
  • Nginx will then randomly select a Tomcat to run. The two Tomcat sessions are shared. A Tomcat session B is available. Even if A is down, B will still press A’s session.


Configure the Spring session to implement session sharing

  • One of the above ways I also in the online case operation. Not a good fit in your own project. Because the Redis cluster (not Sentinel) is configured in my project. Therefore, it is not possible to configure it in Tomcat.

Description: The first mode of redis configuration defaults to single-node redis. That is, our session will generate a sessionID that will be stored as a key in our Redis library. However, if we are a Redis cluster, the cluster will calculate the slot value based on the key value, and then decide which Redis service provider to access according to the slot value. In other words, we don’t know which redis will be stored until we save the session. Therefore, this method is not suitable for Redis cluster.

Take a look at my mind map:

Chapter 2 is clearly wrong and is not actually stored on the Redis that implements the convention


The spring session configuration

  • With that said, let’s start with the session sharing configuration integrated with Spring. First, if you are a Maven project, import the JAR directly
<dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session</artifactId> < version > 1.1.1. RELEASE < / version > < / dependency >Copy the code
  • If you are not a Maven project, please download the relevant JARS yourself.
spring-data-redis.jar
redis.clients.jar
spring-session.jar
Copy the code
  • Again, you need the following articles to configure the Redis cluster

I want to see how to configure the redis point. I want to see how to configure the integration point between Redis and Spring

Spring configuration file configuration

  • With the above preparation materials, we can configure the Spring Session in the spring configuration file

  • We simply need to introduce beans from the Spring Session

<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"> 
Copy the code
  • We only need to configure this one bean in the Spring configuration file. There is only one more step to share sessions on the Redis cluster. The interceptor is configured in the web.xml file
<filter>
	<filter-name>springSessionRepositoryFilter</filter-name>
	<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
	  <filter-name>springSessionRepositoryFilter</filter-name>
	  <url-pattern>/*</url-pattern>
</filter-mapping>
Copy the code
  • Now that the configuration is complete, we can restart our project and run the session access section. Then go to the Redis cluster and see if there is any session. The default session key in Redis isspring:session:sessions:c0d1fadd-b04a-4244-9525-0f13ea7173bf. The last of these ids are the sessionids that were generated during our Tomcat and browser sessions.

The problem

  • We configured the Spring Session to share sessions. But careful friends can find out. Sessions are not really shared. We can see that the session key in the Redis cluster contains the Session ID of Tomcat and browser. In other words, this session on Redis can only be accessed by my Tomcat in this browser. Other Tomcat users will not be able to retrieve this session from Redis even if they interact with the same browser. That’s what you’re looking for. The answer is not. The effect achieved above is depicted in a picture.

  • This configuration only transfers Tomcat session to Redis. Multi-service sessions are still partitioned. This is a big crater. Pit for a long time. And then I came up with another way to solve this limitation now.

The solution

  • Solve the problems above. Here I offer three ideas. I’ve done all three. Each has its pros and cons. In the end, it was decided that the third was more reliable.

1– Rewrite the spring Session source code, rewrite the part of the code that describes the session stored in Redis, mainly to write the session key in Redis as a fixed value. In the future, when we go to the session and we get this fixed key, we can share the session.

2– Override the policy of our session repository in spring session, which is to pass the generated SESSION ID to project B after project A logs in. Item B is obtained in redis based on this sessionid.

3– Store the sessionID as value and the Host/Agent combination in the request header as key in Redis where the value is stored in the session. We can then obtain the sessionid in the spring Session method by obtaining the session ID based on the key of Host and Agent.

Access Policy Reconstruction

  • Here are the steps to implement the third one. First I create a new class that reads the key of the host and agent concatenation in the request header.
public static Map<String, Object> getInfoFromUrl(HttpServletRequest request)
    {
        Map<String, Object> resultMap=new HashMap<String, Object>();
        String Agent = request.getHeader("User-Agent"); 
        String Host = request.getHeader("Host"); 
        resultMap.put("agent", Agent);
        resultMap.put("host", Host);
        return resultMap;
    } 
    
    public static String getKeyFromUrl(HttpServletRequest request)
    {
        String result="";
        Map<String, Object> map = getInfoFromUrl(request);
        Set<String> keySet = map.keySet();
        for (String key : keySet)
        {
            result+=map.get(key).toString();
        }
        return result;
    }
Copy the code
  • And then at the point where we called the session store, which is where we logged in. It is stored by the Redis action class in our project.

  • Then we modify the policy for the session ID that goes to the request in the Cookie repository of the Spring Session

  • Finally, we changed the Spring Session policy to your cook policy in the Spring configuration
<bean id="redisCacheTemplate" class="com.bshinfo.web.base.cache.RedisCacheTemplate"/>
    <bean id="zxh" class="com.bshinfo.web.base.cache.CookieHttpSessionStrategyTest">
    	<property name="redisCacheTemplate" ref="redisCacheTemplate" />
    </bean>
 	<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"> 
 		<property name="httpSessionStrategy" ref="zxh"/>
 		<property name="maxInactiveIntervalInSeconds" value="60"/>
 	</bean> 
Copy the code
  • And that’s where we end up. The effect is that project A is logged in to the X browser. The user of project B who obtains the session in browser X can obtain the session normally. Otherwise, the acquisition fails.