Problems encountered
When developing app s or projects with separate front and back ends, sessions are different each time when using ajax and other ways to access the background, so using Shiro verification is totally impossible to pass. Originally, we used the way of token, which can realize the problem of authority judgment by validating token by ourselves, but we still need to use shiro. Rewrite your own permission judgment. Then how to achieve session ID invariance through token in shiro?
We solve this problem by configuring shiro's session manager and storing shiro's sessions in redis. However, different sessions accessed each time still need to be solved by transferring token. In fact, the token passed by the client is stored as session ID.
Solution code
The following code:
First add the jar package to the pom file
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.4.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>org.crazycake</groupId> <artifactId>shiro-redis</artifactId> <version>2.8.24</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.4.0</version> <scope>compile</scope> </dependency>
Adding redis configuration to the project is my own redis configuration item used in the project, when using the @Value annotation
spring: redis: shiro: #Configure redis cache usage host: localhost port: 6379 timeout: 10000 password: 123456
Add shiro configuration class and add the following to implement custom management session
import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.crazycake.shiro.RedisCacheManager; import org.crazycake.shiro.RedisManager; import org.crazycake.shiro.RedisSessionDAO; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.servlet.Filter; import java.util.LinkedHashMap; import java.util.Map; @Configuration public class ShiroConfig { @Value("${spring.redis.shiro.host}") private String host="127.0.0.1"; @Value("${spring.redis.shiro.port}") private int port=6379; @Value("${spring.redis.shiro.timeout}") private int timeout=100000; @Value("${spring.redis.shiro.password}") private String password = ""; //Custom Session Manager @Bean("sessionManager") public DefaultWebSessionManager sessionManager() { MySessionManager mySessionManager = new MySessionManager(); mySessionManager.setSessionDAO(new RedisSessionDAO()); return mySessionManager; } /** * Configure Shiro redis Manager * <p> * The shiro-redis open source plug-in is used * * @return */ @Bean public RedisManager redisManager() { RedisManager redisManager = new RedisManager(); redisManager.setHost(host); redisManager.setPort(port); redisManager.setExpire(1800);// Configure cache expiration time redisManager.setTimeout(timeout); redisManager.setPassword(password); return redisManager; } /** * Inject Security Manager */ @Bean("SecurityManager") public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setSessionManager(sessionManager()); return securityManager; } /** * RedisSessionDAO shiro sessionDao Layer implementation through redis * <p> * The shiro-redis open source plug-in is used */ @Bean public RedisSessionDAO redisSessionDAO() { RedisSessionDAO redisSessionDAO = new RedisSessionDAO(); redisSessionDAO.setRedisManager(redisManager()); return redisSessionDAO; } }
Add the configuration classes for the custom management session as follows:
import org.apache.shiro.web.servlet.ShiroHttpServletRequest; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.apache.shiro.web.util.WebUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Configuration; import org.springframework.util.StringUtils; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import java.io.Serializable; /** * Modify the default to get session ID */ @Configuration public class MySessionManager extends DefaultWebSessionManager { private Logger logger = LoggerFactory.getLogger(MySessionManager.class); private static final String TOKEN = "token"; private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request"; public MySessionManager() { super(); } @Override protected Serializable getSessionId(ServletRequest request, ServletResponse response) { String id = WebUtils.toHttp(request).getHeader(TOKEN); //If there is token in the request header, the value is session Id if (!StringUtils.isEmpty(id)) { request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, REFERENCED_SESSION_ID_SOURCE); request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id); request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE); return id; } else { //Otherwise, take session Id from cookie by default rule return super.getSessionId(request, response); } } }
In the configuration, the token passed by the client is used as session Id, and if no token is passed, the session ID in reques is used. If the token is obtained in the request header, the token is set to the session Id of the current request.
The variable private static final String TOKEN = token; is the token variable name in the client request header. By this way, the session ID of the same user request session ID can be kept unchanged.