Shiro rights management framework (b): Shiro combined Redis achieve Session sharing in a distributed environment

Starting address: https://www.guitu18.com/post/2019/07/28/44.html


The second series is Benpian Shiro, Shiro use Redis achieve Session based distributed environment sharing. Speaking before the Session Sharing Session to say why do share.

Why do Session Sharing

What is Session

We all know that HTTP protocol (1.1) are stateless , so the server needs to identify the user access when you do the appropriate records used to track user actions, the implementation mechanism is Session. The first time a user accesses the server, the server will create a Session for the user, each Session has a unique SessionId (application level) is used to identify the user.

Session does not usually appear alone, because the request is stateless, then we must allow users to bring the server to its request at the next generation of the Session ID, Cookie achieved when using the usual practice (of course you have to request parameters bring in SessionId it is not impossible). SessionID is written to the browser when a Cookie request returns, the key is generally used JSESSIONID, so that the next user then requests that server, the server can be removed from the Cookie SessionId identify the user who views the request Yes.

For chestnut:

img

Cookie red box on the left part is a list of the current server is: localhost: 28080. The red frame part left to right is the right key Cookie value, the host, the path, and expiration time. Path /when the station showing effective, then the last expiration time is not set the default value of the Session, the Cookie indicates failure when the browser closes. We can also specify an expiration time of Cookie, session remains to be done.

What is Session Sharing

By Session and Cookie, we make the stateless HTTP protocol has indirectly become a state, you can achieve your logging store user information, shopping cart and more. But with the increase in the number of service access, single server has been insufficient to meet all the requests, it must deploy a clustered environment. But with the emergence of a cluster environment, tracking the status of user problems began to arise problems before the user logs in A server, A server stores user information, but sent to the server B to the next request, this time B server is not known a user in the server log of things, although it can also get the user Cookie request of SessionId, but in B services based on this SessionId not find the corresponding Session, B server will think that the user is not logged in, users need to log in again, this is no way for the user to accept.

At this time there are two common ways to solve this problem, the first is to allow the user all requests are sent to the A server, such as doing a series based on the IP address of the algorithm will assign all users to a different server up, so that each user where the only access one server. This approach is feasible, but the follow-up will also have other problems, better approach is the second, the Session on all the servers are made to share, A service can get all Session B on the server, empathy B server can also get all of the Session a server, so that the above problem does not exist.


Shiro combined share Redis achieve Session

Previous Shiro has been achieved through the user login and rights management, Shiro login is also based on the Session, Session is by default stored in memory. Since to do Session Sharing, then it is surely the Session drawn out into a place more to the server can access.

In a clustered environment, we just need to inherit AbstractSessionDAO, to achieve what several methods Session CRUD etc. can easily achieve Session sharing, Shiro has been the complete process has been done. This involves the design pattern is a template method pattern, we only need to participate in part of the business can improve the whole process, of course, we do not participate in this part of the process, then, Shiro also have default implementations that would Session management in the memory of the current application in.

Specific Session Management (shared) how to achieve our own decision, can be stored in the database can also be transmitted over the network, even rows are written to the file by IO streams, but in terms of performance, we generally will put Redis Session in. Redis Dafa is good! YES ~

Custom RedisSessionDAO

After it is easy to understand the principles of the work to achieve Session additions and deletions to change search after several methods inherited AbstractSessionDAO, and then distributed system, all items will then need to store or go get Session Redis operation, so did the cluster environment the Session shared. The code is very simple:

@Component
public class RedisSessionDao extends AbstractSessionDAO {

    @Value("${session.redis.expireTime}")
    private long expireTime;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = this.generateSessionId(session);
        this.assignSessionId(session, sessionId);
        redisTemplate.opsForValue().set(session.getId(), session, expireTime, TimeUnit.SECONDS);
        return sessionId;
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        return sessionId == null ? null : (Session) redisTemplate.opsForValue().get(sessionId);
    }

    @Override
    public void update(Session session) throws UnknownSessionException {
        if (session != null && session.getId() != null) {
            session.setTimeout(expireTime * 1000);
            redisTemplate.opsForValue().set(session.getId(), session, expireTime, TimeUnit.SECONDS);
        }
    }

    @Override
    public void delete(Session session) {
        if (session != null && session.getId() != null) {
            redisTemplate.opsForValue().getOperations().delete(session.getId());
        }
    }

    @Override
    public Collection<Session> getActiveSessions() {
        return redisTemplate.keys("*");
    }

}

Adding the above configuration file used to configure

###redis连接配置
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=foobared
### Session过期时间(秒)
session.redis.expireTime=3600

Injection RedisSessionDao

The above is just the way we manage the Session of their own to achieve, now needs to be injected into the SessionManager and set the expiration time and other relevant parameters.

    @Bean
    public DefaultWebSessionManager defaultWebSessionManager(RedisSessionDao redisSessionDao) {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setGlobalSessionTimeout(expireTime * 1000);
        sessionManager.setDeleteInvalidSessions(true);
        sessionManager.setSessionDAO(redisSessionDao);
        sessionManager.setSessionValidationSchedulerEnabled(true);
        sessionManager.setDeleteInvalidSessions(true);
        /**
         * 修改Cookie中的SessionId的key,默认为JSESSIONID,自定义名称
         */
        sessionManager.setSessionIdCookie(new SimpleCookie("JSESSIONID"));
        return sessionManager;
    }

SessionManager then injected Shiro of SecurityManager in security manager, as I said before, all of our operations around the relevant security, we need to deal with SecurityManager, this is the real Big Brother Shiro.

    @Bean
    public SecurityManager securityManager(UserAuthorizingRealm userRealm, RedisSessionDao redisSessionDao) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);
        // 取消Cookie中的RememberMe参数
        securityManager.setRememberMeManager(null);
        securityManager.setSessionManager(defaultWebSessionManager(redisSessionDao));
        return securityManager;
    }

OK, now based on Session sharing Redis implementation is complete, is not it incredibly simple.

Note: For the network transmission requested object implements Serializable sequence interfaces, such as the User class.

test

Different set of code to run two sets of port services (number of sets can theoretically run as long as you configure enough), two servers obtain user information access interface, unknown status will no doubt jump to login page :

img

Call logs in a log in on any server:

img

After a successful login to access two servers were again obtain user information interfaces:

img

Thus, distributed environment Session Sharing perfectly. Finally, we continue to put the project code, or the code before the very early part of the code in order to meet this post notes revised after finishing uploading.

Gitee:https://gitee.com/guitu18/ShiroDemo

GitHub:https://github.com/guitu18/ShiroDemo


Benpian end, just do not be too simple is not, in fact, this is mainly because most of the work will help us to do the Shiro, Shiro detail things are hidden, we just need to add some simple configuration can achieve powerful, this is the benefit framework.

But as a programmer, just call a method or add a comment on the realization of a very powerful, and if we do not see a judge and for the cycle when the heart should be very practical . We must not only learn to use frames and more to go in-depth understanding of the framework, at least to know why we have added an annotation framework can help us achieve a lot of functions, the only way to make us feel down to earth. Next, Shiro-depth look at the source code, you may need to kick some ideas to think about how to write notes.

Guess you like

Origin www.cnblogs.com/guitu18/p/11262106.html