From f7f8e9cc7de686fe3e8ef424f1d50fa821255449 Mon Sep 17 00:00:00 2001
From: whycxzp <perryhsu@163.com>
Date: 星期六, 23 一月 2021 17:30:48 +0800
Subject: [PATCH] update

---
 src/main/java/com/whyc/config/RedisSessionDao.java             |   95 +++++
 src/main/java/com/whyc/properties/RedisClusterProperties.java  |   83 ++++
 src/main/java/com/whyc/service/LoginService.java               |   18 
 src/main/java/com/whyc/properties/RedisSingleProperties.java   |   13 
 src/main/java/com/whyc/properties/ShiroRedisProperties.java    |   79 ++++
 readme.md                                                      |    8 
 src/main/java/com/whyc/properties/RedisPoolProperties.java     |   69 ++++
 pom.xml                                                        |    7 
 src/main/java/com/whyc/properties/RedisSentinelProperties.java |   43 ++
 src/main/java/com/whyc/config/ShiroConfig.java                 |   76 ++++
 src/main/java/com/whyc/properties/RedisProperties.java         |   87 +++++
 src/main/java/com/whyc/util/ShiroRedissionSerialize.java       |   78 ++++
 src/main/resources/config/authentication.properties            |    6 
 src/main/java/com/whyc/pojo/User.java                          |    5 
 src/main/java/com/whyc/filter/KickedOutFilter.java             |    8 
 src/main/resources/config/application.yml                      |   35 ++
 src/main/java/com/whyc/config/RedisConfig.java                 |  105 ++++++
 src/main/java/com/whyc/util/EmptyUtil.java                     |  148 ++++++++
 src/main/java/com/whyc/constant/SuperConstant.java             |   14 
 19 files changed, 962 insertions(+), 15 deletions(-)

diff --git a/pom.xml b/pom.xml
index ae68f78..a0ffac5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -123,6 +123,13 @@
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
         </dependency>
+        <!--redis缂撳瓨瀹㈡埛绔�-->
+        <dependency>
+            <groupId>org.redisson</groupId>
+            <artifactId>redisson</artifactId>
+            <version>3.5.0</version>
+        </dependency>
+
     </dependencies>
 
     <build>
diff --git a/readme.md b/readme.md
index 670e788..b78c251 100644
--- a/readme.md
+++ b/readme.md
@@ -3,7 +3,13 @@
 
 * 鏈�鍒濆鐗堟鏋�,鎺ュ彛鏂囨。璁块棶:{ip}:{port}/doc.html,渚嬪:localhost:8090/doc.html
 
-* 鐧诲綍Session涓篔WT鐗堟湰
+* 鐧诲綍Session涓篠essionCookie
+* 闆嗙兢鎶�鏈富瑕佽�冭檻鐨勬槸瑙e喅Session鍏变韩闂,瀵硅祫婧愭潵璇存渶濂界殑鏂瑰紡鏄痳edis浣滀负session鐨勫瓨鍌�,涔熷彲浠ヤ娇鐢╰omcat鐨勬彁渚涚殑闆嗙兢璁剧疆,瀹炵幇Session鍦ㄥ涓猼omcat涓殑澶嶅埗(杩欎釜鏈」鐩笉閫傜敤,鍥犱负鍐呭祵tomcat,涓嶆柟渚胯缃�)
+* 閲囧彇浜嗗垎甯冨紡缂撳瓨,闆嗘垚浜唕edis鍗曟満鐗�/鍝ㄥ叺/闆嗙兢鐗堟湰
+* web杞彂閲囩敤nginx,閰嶇疆绀轰緥濡備笅
+    ```yaml
+    TODO
+    ```
 
 * 绂佹鍦ㄦ湰閫氱敤鏋舵瀯涓婄洿鎺ユ洿鏂板叿浣撻」鐩唬鐮佹彁浜�! 绂佹鏈�氱敤鏋舵瀯涓奙erge鍏朵粬git鍒嗘敮!
 ***********
diff --git a/src/main/java/com/whyc/config/RedisConfig.java b/src/main/java/com/whyc/config/RedisConfig.java
new file mode 100644
index 0000000..2061cc9
--- /dev/null
+++ b/src/main/java/com/whyc/config/RedisConfig.java
@@ -0,0 +1,105 @@
+package com.whyc.config;
+
+import com.whyc.properties.RedisClusterProperties;
+import com.whyc.properties.RedisPoolProperties;
+import com.whyc.properties.RedisProperties;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
+import org.springframework.util.StringUtils;
+
+@Configuration
+@EnableConfigurationProperties(RedisProperties.class)
+@Slf4j
+public class RedisConfig {
+
+    @Autowired
+    RedisProperties redisProperties;
+
+
+    /**
+     * redis鍗曟満
+     */
+    @Bean("redisClient")
+    @ConditionalOnProperty(name = "redis.model", havingValue = "single")
+    @Order(1)
+    RedissonClient redissonClientSingle() {
+        log.error("redis鍗曟満鐗坈lient鍒濆鍖栦簡");
+        Config config = new Config();
+        String node = redisProperties.getSingle().getAddress();
+        SingleServerConfig serverConfig = config.useSingleServer()
+                .setAddress(node)
+                .setTimeout(redisProperties.getTimeout())
+                .setConnectionPoolSize(redisProperties.getPool().getSize())
+                .setConnectionMinimumIdleSize(redisProperties.getPool().getMinIdle());
+        if (!StringUtils.isEmpty(redisProperties.getPassword())) {
+            serverConfig.setPassword(redisProperties.getPassword());
+        }
+
+        return Redisson.create(config);
+
+    }
+
+    /**
+     * redis鍝ㄥ叺
+     */
+    @Bean("redisClient")
+    @ConditionalOnProperty(name = "redis.model", havingValue = "sentinel")
+    RedissonClient redissonClientSentinel() {
+        log.error("redis鍗曟満鐗坈lient鍒濆鍖栦簡");
+        Config config = new Config();
+
+        String[] nodes = redisProperties.getSentinel().getNodes().split(",");
+
+        SentinelServersConfig serversConfig = config.useSentinelServers()
+                .addSentinelAddress(nodes)
+                .setMasterName(redisProperties.getSentinel().getMaster())
+                .setReadMode(ReadMode.SLAVE)
+                .setFailedAttempts(redisProperties.getSentinel().getFailMax())
+                .setTimeout(redisProperties.getTimeout())
+                .setMasterConnectionPoolSize(redisProperties.getPool().getSize())
+                .setSlaveConnectionPoolSize(redisProperties.getPool().getSize());
+        if (!StringUtils.isEmpty(redisProperties.getPassword())) {
+            serversConfig.setPassword(redisProperties.getPassword());
+        }
+        return Redisson.create(config);
+
+    }
+
+    /**
+     * 闆嗙兢
+     */
+    @Bean("redisClient")
+    @ConditionalOnProperty(name = "redis.model", havingValue = "cluster")
+    RedissonClient redissonClientCluster() {
+        log.error("redis鍗曟満鐗坈lient鍒濆鍖栦簡");
+        Config config = new Config();
+        RedisClusterProperties cluster = redisProperties.getCluster();
+        RedisPoolProperties pool = redisProperties.getPool();
+        String[] nodes = cluster.getNodes().split(",");
+        ClusterServersConfig serversConfig = config.useClusterServers()
+                .addNodeAddress(nodes)
+                .setScanInterval(cluster.getScanInterval())
+                .setIdleConnectionTimeout(pool.getSoTimeout())
+                .setConnectTimeout(pool.getConnTimeout())
+                .setFailedAttempts(cluster.getFailedAttempts())
+                .setRetryAttempts(cluster.getRetryAttempts())
+                .setRetryInterval(cluster.getRetryInterval())
+                .setMasterConnectionPoolSize(cluster.getMasterConnectionPoolSize())
+                .setSlaveConnectionPoolSize(cluster.getSlaveConnectionPoolSize())
+                .setTimeout(redisProperties.getTimeout());
+
+        if (!StringUtils.isEmpty(redisProperties.getPassword())) {
+            serversConfig.setPassword(redisProperties.getPassword());
+        }
+        return Redisson.create(config);
+    }
+
+}
diff --git a/src/main/java/com/whyc/config/RedisSessionDao.java b/src/main/java/com/whyc/config/RedisSessionDao.java
new file mode 100644
index 0000000..e59ef6b
--- /dev/null
+++ b/src/main/java/com/whyc/config/RedisSessionDao.java
@@ -0,0 +1,95 @@
+package com.whyc.config;
+
+import com.whyc.constant.SuperConstant;
+import com.whyc.util.ShiroRedissionSerialize;
+import io.swagger.annotations.ApiModel;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.session.Session;
+import org.apache.shiro.session.UnknownSessionException;
+import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
+import org.redisson.api.RBucket;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.context.annotation.DependsOn;
+
+import javax.annotation.Resource;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 瀹炵幇Shiro session鐨刴emcached闆嗕腑寮忕鐞�
+ */
+@Slf4j
+public class RedisSessionDao extends AbstractSessionDAO {
+
+    /*@Resource(name = "redissonClient4Shiro")
+    RedissonClient redissonClient;*/
+
+    @Autowired
+    RedissonClient redissonClient;
+
+    private Long globalSessionTimeout;
+
+    /**
+     * 淇濆瓨Session
+     * @param session
+     * @return
+     */
+    @Override
+    protected Serializable doCreate(Session session) {
+        Serializable sessionId = generateSessionId(session);
+        assignSessionId(session,sessionId);
+
+        //灏哠ession瀛樺叆redis
+        RBucket<String> sessionIdBucket = redissonClient.getBucket(SuperConstant.GROUP_CAS + sessionId.toString());
+        sessionIdBucket.trySet(ShiroRedissionSerialize.serialize(session),globalSessionTimeout, TimeUnit.SECONDS);
+        return sessionId;
+    }
+
+    /**
+     * 璇诲彇Session
+     * @param sessionId
+     * @return
+     */
+    @Override
+    protected Session doReadSession(Serializable sessionId) {
+        RBucket<String> sessionIdBucket = redissonClient.getBucket(SuperConstant.GROUP_CAS + sessionId.toString());
+        Session session = (Session) ShiroRedissionSerialize.deserialize(sessionIdBucket.get());
+        return session;
+    }
+
+    /**
+     * 鏇存柊Session
+     * @param session
+     * @throws UnknownSessionException
+     */
+    @Override
+    public void update(Session session) throws UnknownSessionException {
+        RBucket<String> sessionIdBucket = redissonClient.getBucket(SuperConstant.GROUP_CAS + session.getId().toString());
+        sessionIdBucket.set(ShiroRedissionSerialize.serialize(session),globalSessionTimeout,TimeUnit.SECONDS);
+        log.info("淇敼涓篠essionId:{}",session.getId().toString());
+    }
+
+    /**
+     * 娓呴櫎Session
+     * @param session
+     */
+    @Override
+    public void delete(Session session) {
+        RBucket<String> sessionIdBucket = redissonClient.getBucket(SuperConstant.GROUP_CAS + session.getId().toString());
+        sessionIdBucket.delete();
+        log.info("Session:{}琚竻闄や簡",session);
+    }
+
+    @Override
+    public Collection<Session> getActiveSessions() {
+        return Collections.EMPTY_SET;
+    }
+
+    public RedisSessionDao(Long globalSessionTimeout) {
+        this.globalSessionTimeout = globalSessionTimeout;
+    }
+}
diff --git a/src/main/java/com/whyc/config/ShiroConfig.java b/src/main/java/com/whyc/config/ShiroConfig.java
index 402477a..8c8b1be 100644
--- a/src/main/java/com/whyc/config/ShiroConfig.java
+++ b/src/main/java/com/whyc/config/ShiroConfig.java
@@ -3,17 +3,29 @@
 import com.whyc.filter.KickedOutFilter;
 import com.whyc.filter.RolesOrAuthorizationFilter;
 import com.whyc.properties.PropertiesUtil;
+import com.whyc.properties.RedisProperties;
+import com.whyc.properties.ShiroRedisProperties;
 import com.whyc.realm.CustomRealm;
 import lombok.extern.log4j.Log4j;
 import lombok.extern.log4j.Log4j2;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.session.mgt.SessionManager;
+import org.apache.shiro.session.mgt.eis.SessionDAO;
 import org.apache.shiro.spring.LifecycleBeanPostProcessor;
 import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
 import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
 import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;
 import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
+import org.apache.shiro.web.servlet.SimpleCookie;
+import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.Config;
 import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.DependsOn;
 
@@ -27,17 +39,79 @@
  * 鏆傛椂鎻愪緵鏉冮檺绠$悊,浼氳瘽绠$悊鍚庣画鏇存柊 TODO
  */
 @Configuration
-//@Log4j2
+@Slf4j
+@EnableConfigurationProperties({RedisProperties.class})
 public class ShiroConfig {
 
     @Autowired
     CustomRealm customRealm;
 
+    @Autowired
+    RedisProperties redisProperties;
+
+    /*================Session閲囩敤Redis鍒嗗竷寮廠ession===================*/
+
+    /**
+     * Redisson瀹㈡埛绔�,鍒濆鍖�
+     *//*
+    @Bean(name = "redissonClient4Shiro")
+    public RedissonClient redissonClient(){
+        log.info("======鍒濆鍖杛edissonClient4Shiro======");
+        String[] nodeList = shiroRedisProperties.getNodes().split(",");
+        Config config = new Config();
+        if(nodeList.length==1){
+            config.useSingleServer().setAddress(nodeList[0])
+                .setConnectTimeout(shiroRedisProperties.getConnectTimeout())
+                .setConnectionPoolSize(shiroRedisProperties.getConnectPoolSize())
+                .setConnectionMinimumIdleSize(shiroRedisProperties.getConnectMinIdleSize())
+                .setTimeout(shiroRedisProperties.getTimeout());
+        }else{
+            config.useClusterServers().addNodeAddress(nodeList)
+                .setConnectTimeout(shiroRedisProperties.getConnectTimeout())
+                .setMasterConnectionPoolSize(shiroRedisProperties.getConnectPoolSize())
+                .setMasterConnectionMinimumIdleSize(shiroRedisProperties.getConnectMinIdleSize())
+                .setTimeout(shiroRedisProperties.getTimeout());
+        }
+
+        RedissonClient redissonClient = Redisson.create(config);
+        return redissonClient;
+    }*/
+
+    /**
+     * 鍒濆鍖朢edisSessionDao
+     */
+    @Bean("redisSessionDao")
+    @DependsOn("redisClient")
+    public SessionDAO redisSessionDao(){
+        RedisSessionDao redisSessionDao = new RedisSessionDao(redisProperties.getGlobalSessionTimeout());
+        return redisSessionDao;
+    }
+
+    /**Session绠$悊鍣�*/
+    @Bean("sessionManager")
+    @DependsOn("redisSessionDao")
+    public DefaultWebSessionManager shiroSessionManager(){
+        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
+        //璁剧疆Session鍙傛暟
+        sessionManager.setSessionDAO(redisSessionDao());
+        sessionManager.setSessionValidationSchedulerEnabled(false);
+        sessionManager.setSessionIdCookieEnabled(true);
+
+        SimpleCookie simpleCookie = new SimpleCookie("ShiroSession");
+        sessionManager.setSessionIdCookie(simpleCookie);
+        sessionManager.setGlobalSessionTimeout(redisProperties.getGlobalSessionTimeout());
+        return sessionManager;
+    }
+
+    /*====================鏉冮檺绠$悊=======================*/
+
     /**鏉冮檺绠$悊鍣�*/
     @Bean(name = "securityManager")
+    @DependsOn("sessionManager")
     public DefaultWebSecurityManager defaultWebSecurityManager(){
         DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
         securityManager.setRealm(customRealm);
+        securityManager.setSessionManager(shiroSessionManager());
         return securityManager;
     }
 
diff --git a/src/main/java/com/whyc/constant/SuperConstant.java b/src/main/java/com/whyc/constant/SuperConstant.java
index 59ff5de..1a4a999 100644
--- a/src/main/java/com/whyc/constant/SuperConstant.java
+++ b/src/main/java/com/whyc/constant/SuperConstant.java
@@ -6,12 +6,20 @@
 public class SuperConstant {
 
     /**绠楁硶鍚�*/
-    public static String HASH_ALGORITHM = "SHA-1";
+    public final static String HASH_ALGORITHM = "SHA-1";
 
     /**hash璁$畻娆℃暟*/
-    public static int HASH_INTERATIONS = 112;
+    public final static  int HASH_INTERATIONS = 112;
 
-    public static String SALT ="Yin";
+    public final static String SALT ="Yin";
+
+    /**缂撳瓨閿�煎父閲�*/
+    public final static String GROUP_CAS ="group_shiro:";
+    public final static String ROLE_KEY =GROUP_CAS+"role_key:";
+    public final static String RESOURCE_KEY =GROUP_CAS+"resource_key:";
+    public final static String RESOURCE_KEY_IDS =GROUP_CAS+"resource_key_ids:";
+    public final static String FIND_USER_BY_LOGIN_NAME =GROUP_CAS+"findUserByLoginName";
+
 
 
 
diff --git a/src/main/java/com/whyc/filter/KickedOutFilter.java b/src/main/java/com/whyc/filter/KickedOutFilter.java
index 858a11d..3fb0272 100644
--- a/src/main/java/com/whyc/filter/KickedOutFilter.java
+++ b/src/main/java/com/whyc/filter/KickedOutFilter.java
@@ -2,7 +2,10 @@
 
 import com.whyc.pojo.User;
 import com.whyc.util.ShiroUtil;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
 
+import javax.annotation.Resource;
 import javax.servlet.*;
 import javax.servlet.annotation.WebFilter;
 import javax.servlet.http.HttpServletRequest;
@@ -15,6 +18,9 @@
 @WebFilter(urlPatterns = "/*",filterName = "kickedOutFilter")
 public class KickedOutFilter implements Filter {
 
+    @Autowired
+    RedissonClient redissonClient;
+
     @Override
     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
         HttpSession session = ((HttpServletRequest) request).getSession();
@@ -23,7 +29,7 @@
             User user = ShiroUtil.getUser();
             if (user.getId() != 0) {
                 System.out.println("Filter杩囨护鍣ㄤ腑鑾峰彇鍒扮殑褰撳墠Session鐨凷essionId涓�:" + session.getId());
-                if (!request.getServletContext().getAttribute(user.getName()).equals(session.getId())) {
+                if (!redissonClient.getBucket(user.getName()).get().equals(session.getId())) {
                     //濡傛灉褰撳墠Session鎵�瀵瑰簲鐨凷essionId涓庡叏灞�涓敤鎴峰搴旂殑SessionId涓嶄竴鑷�,鍒欐竻闄ゅ綋鍓峉ession
                     session.invalidate();
                     response.setContentType("text/html;charset=utf-8");
diff --git a/src/main/java/com/whyc/pojo/User.java b/src/main/java/com/whyc/pojo/User.java
index 0370c71..39d5e02 100644
--- a/src/main/java/com/whyc/pojo/User.java
+++ b/src/main/java/com/whyc/pojo/User.java
@@ -1,15 +1,14 @@
 package com.whyc.pojo;
 
-import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.fasterxml.jackson.annotation.JsonFormat;
-import lombok.*;
 import org.apache.ibatis.type.Alias;
 
+import java.io.Serializable;
 import java.util.Date;
 @Alias("User")
 @TableName( schema = "`db_3.5mw_web`",value = "tb_user")
-public class User {
+public class User implements Serializable {
     private Integer id;
     private String name;
     private String password;
diff --git a/src/main/java/com/whyc/properties/RedisClusterProperties.java b/src/main/java/com/whyc/properties/RedisClusterProperties.java
new file mode 100644
index 0000000..0a3d54f
--- /dev/null
+++ b/src/main/java/com/whyc/properties/RedisClusterProperties.java
@@ -0,0 +1,83 @@
+package com.whyc.properties;
+
+public class RedisClusterProperties {
+    private Integer scanInterval;
+
+    private String nodes;
+
+    private String readMode;
+
+    private Integer retryAttempts;
+
+    private Integer failedAttempts;
+
+    private Integer slaveConnectionPoolSize;
+
+    private Integer masterConnectionPoolSize;
+
+    private Integer retryInterval;
+
+    public Integer getScanInterval() {
+        return scanInterval;
+    }
+
+    public void setScanInterval(Integer scanInterval) {
+        this.scanInterval = scanInterval;
+    }
+
+    public String getNodes() {
+        return nodes;
+    }
+
+    public void setNodes(String nodes) {
+        this.nodes = nodes;
+    }
+
+    public String getReadMode() {
+        return readMode;
+    }
+
+    public void setReadMode(String readMode) {
+        this.readMode = readMode;
+    }
+
+    public Integer getRetryAttempts() {
+        return retryAttempts;
+    }
+
+    public void setRetryAttempts(Integer retryAttempts) {
+        this.retryAttempts = retryAttempts;
+    }
+
+    public Integer getFailedAttempts() {
+        return failedAttempts;
+    }
+
+    public void setFailedAttempts(Integer failedAttempts) {
+        this.failedAttempts = failedAttempts;
+    }
+
+    public Integer getSlaveConnectionPoolSize() {
+        return slaveConnectionPoolSize;
+    }
+
+    public void setSlaveConnectionPoolSize(Integer slaveConnectionPoolSize) {
+        this.slaveConnectionPoolSize = slaveConnectionPoolSize;
+    }
+
+    public Integer getMasterConnectionPoolSize() {
+        return masterConnectionPoolSize;
+    }
+
+    public void setMasterConnectionPoolSize(Integer masterConnectionPoolSize) {
+        this.masterConnectionPoolSize = masterConnectionPoolSize;
+    }
+
+    public Integer getRetryInterval() {
+        return retryInterval;
+    }
+
+    public void setRetryInterval(Integer retryInterval) {
+        this.retryInterval = retryInterval;
+    }
+}
diff --git a/src/main/java/com/whyc/properties/RedisPoolProperties.java b/src/main/java/com/whyc/properties/RedisPoolProperties.java
new file mode 100644
index 0000000..6480801
--- /dev/null
+++ b/src/main/java/com/whyc/properties/RedisPoolProperties.java
@@ -0,0 +1,69 @@
+package com.whyc.properties;
+
+
+public class RedisPoolProperties {
+
+    private Integer size;
+    private Integer maxIdle;
+    private Integer minIdle;
+    private Integer maxActive;
+    private Integer maxWait;
+    private Integer connTimeout;
+    private Integer soTimeout;
+
+    public Integer getSize() {
+        return size;
+    }
+
+    public void setSize(Integer size) {
+        this.size = size;
+    }
+
+    public Integer getMaxIdle() {
+        return maxIdle;
+    }
+
+    public void setMaxIdle(Integer maxIdle) {
+        this.maxIdle = maxIdle;
+    }
+
+    public Integer getMinIdle() {
+        return minIdle;
+    }
+
+    public void setMinIdle(Integer minIdle) {
+        this.minIdle = minIdle;
+    }
+
+    public Integer getMaxActive() {
+        return maxActive;
+    }
+
+    public void setMaxActive(Integer maxActive) {
+        this.maxActive = maxActive;
+    }
+
+    public Integer getMaxWait() {
+        return maxWait;
+    }
+
+    public void setMaxWait(Integer maxWait) {
+        this.maxWait = maxWait;
+    }
+
+    public Integer getConnTimeout() {
+        return connTimeout;
+    }
+
+    public void setConnTimeout(Integer connTimeout) {
+        this.connTimeout = connTimeout;
+    }
+
+    public Integer getSoTimeout() {
+        return soTimeout;
+    }
+
+    public void setSoTimeout(Integer soTimeout) {
+        this.soTimeout = soTimeout;
+    }
+}
diff --git a/src/main/java/com/whyc/properties/RedisProperties.java b/src/main/java/com/whyc/properties/RedisProperties.java
new file mode 100644
index 0000000..a409072
--- /dev/null
+++ b/src/main/java/com/whyc/properties/RedisProperties.java
@@ -0,0 +1,87 @@
+package com.whyc.properties;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@ConfigurationProperties(prefix = "redis",ignoreUnknownFields = true)
+public class RedisProperties {
+
+    private String mode;
+
+    private Integer timeout;
+
+    private Long globalSessionTimeout;
+
+    private String password;
+
+    private RedisPoolProperties pool;
+
+    private RedisSingleProperties single;
+
+    private RedisSentinelProperties sentinel;
+
+    private RedisClusterProperties cluster;
+
+    public String getMode() {
+        return mode;
+    }
+
+    public void setMode(String mode) {
+        this.mode = mode;
+    }
+
+    public Integer getTimeout() {
+        return timeout;
+    }
+
+    public void setTimeout(Integer timeout) {
+        this.timeout = timeout;
+    }
+
+    public Long getGlobalSessionTimeout() {
+        return globalSessionTimeout;
+    }
+
+    public void setGlobalSessionTimeout(Long globalSessionTimeout) {
+        this.globalSessionTimeout = globalSessionTimeout;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public RedisPoolProperties getPool() {
+        return pool;
+    }
+
+    public void setPool(RedisPoolProperties pool) {
+        this.pool = pool;
+    }
+
+    public RedisSingleProperties getSingle() {
+        return single;
+    }
+
+    public void setSingle(RedisSingleProperties single) {
+        this.single = single;
+    }
+
+    public RedisSentinelProperties getSentinel() {
+        return sentinel;
+    }
+
+    public void setSentinel(RedisSentinelProperties sentinel) {
+        this.sentinel = sentinel;
+    }
+
+    public RedisClusterProperties getCluster() {
+        return cluster;
+    }
+
+    public void setCluster(RedisClusterProperties cluster) {
+        this.cluster = cluster;
+    }
+}
diff --git a/src/main/java/com/whyc/properties/RedisSentinelProperties.java b/src/main/java/com/whyc/properties/RedisSentinelProperties.java
new file mode 100644
index 0000000..3f2d265
--- /dev/null
+++ b/src/main/java/com/whyc/properties/RedisSentinelProperties.java
@@ -0,0 +1,43 @@
+package com.whyc.properties;
+
+public class RedisSentinelProperties {
+    private String master;
+
+    private String nodes;
+
+    private String masterOnlyWrite;
+
+    private Integer failMax;
+
+    public String getMaster() {
+        return master;
+    }
+
+    public void setMaster(String master) {
+        this.master = master;
+    }
+
+    public String getNodes() {
+        return nodes;
+    }
+
+    public void setNodes(String nodes) {
+        this.nodes = nodes;
+    }
+
+    public String getMasterOnlyWrite() {
+        return masterOnlyWrite;
+    }
+
+    public void setMasterOnlyWrite(String masterOnlyWrite) {
+        this.masterOnlyWrite = masterOnlyWrite;
+    }
+
+    public Integer getFailMax() {
+        return failMax;
+    }
+
+    public void setFailMax(Integer failMax) {
+        this.failMax = failMax;
+    }
+}
diff --git a/src/main/java/com/whyc/properties/RedisSingleProperties.java b/src/main/java/com/whyc/properties/RedisSingleProperties.java
new file mode 100644
index 0000000..2b41c3c
--- /dev/null
+++ b/src/main/java/com/whyc/properties/RedisSingleProperties.java
@@ -0,0 +1,13 @@
+package com.whyc.properties;
+
+public class RedisSingleProperties {
+    private String address;
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+}
diff --git a/src/main/java/com/whyc/properties/ShiroRedisProperties.java b/src/main/java/com/whyc/properties/ShiroRedisProperties.java
new file mode 100644
index 0000000..fb4052f
--- /dev/null
+++ b/src/main/java/com/whyc/properties/ShiroRedisProperties.java
@@ -0,0 +1,79 @@
+package com.whyc.properties;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.io.Serializable;
+
+/**
+ * 灞炴�х被
+ */
+
+@ConfigurationProperties(prefix = "redis")
+public class ShiroRedisProperties implements Serializable {
+
+    /**redis杩炴帴鍦板潃*/
+    private String nodes;
+
+    /**杩炴帴瓒呮椂鏃堕棿*/
+    private int connectTimeout;
+
+    /**杩炴帴姹犲ぇ灏�*/
+    private int connectPoolSize;
+
+    /**鏈�灏忕┖闂茶繛鎺ユ暟*/
+    private int connectMinIdleSize;
+
+    /**鏁版嵁杩斿洖瓒呮椂鏃堕棿*/
+    private int timeout;
+
+    /**鍏ㄥ眬瓒呮椂鏃堕棿*/
+    private long globalSessionTimeout;
+
+    public String getNodes() {
+        return nodes;
+    }
+
+    public void setNodes(String nodes) {
+        this.nodes = nodes;
+    }
+
+    public int getConnectTimeout() {
+        return connectTimeout;
+    }
+
+    public void setConnectTimeout(int connectTimeout) {
+        this.connectTimeout = connectTimeout;
+    }
+
+    public int getConnectPoolSize() {
+        return connectPoolSize;
+    }
+
+    public void setConnectPoolSize(int connectPoolSize) {
+        this.connectPoolSize = connectPoolSize;
+    }
+
+    public int getConnectMinIdleSize() {
+        return connectMinIdleSize;
+    }
+
+    public void setConnectMinIdleSize(int connectMinIdleSize) {
+        this.connectMinIdleSize = connectMinIdleSize;
+    }
+
+    public int getTimeout() {
+        return timeout;
+    }
+
+    public void setTimeout(int timeout) {
+        this.timeout = timeout;
+    }
+
+    public long getGlobalSessionTimeout() {
+        return globalSessionTimeout;
+    }
+
+    public void setGlobalSessionTimeout(long globalSessionTimeout) {
+        this.globalSessionTimeout = globalSessionTimeout;
+    }
+}
diff --git a/src/main/java/com/whyc/service/LoginService.java b/src/main/java/com/whyc/service/LoginService.java
index 0805e52..abcc5b5 100644
--- a/src/main/java/com/whyc/service/LoginService.java
+++ b/src/main/java/com/whyc/service/LoginService.java
@@ -5,13 +5,22 @@
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.authc.UsernamePasswordToken;
 import org.apache.shiro.subject.Subject;
+import org.redisson.api.RBucket;
+import org.redisson.api.RList;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 
 @Service
 public class LoginService {
+
+    @Autowired
+    RedissonClient redissonClient;
 
     public Response login(String userName, String password, HttpServletRequest request) {
         UsernamePasswordToken userToken = new UsernamePasswordToken(userName, password);
@@ -22,10 +31,13 @@
             return new Response<>().set(1,false);
         }
         if (subject.isAuthenticated()){
-            //姣忎釜鐧诲綍鐨勭敤鎴烽兘鏈変竴涓叏灞�鍙橀噺,閲岄潰瀛樼潃瀵瑰簲鐨凷essionId;
+            //姣忎釜鐧诲綍鐨勭敤鎴烽兘鏈変竴涓叏灞�鍙橀噺,閲岄潰瀛樼潃瀵瑰簲鐨凷essionId;redis瀛樺偍,鍒嗗竷寮�,鍚﹀垯浼氭姤閿�
             //鍚屼竴涓处鍙�,鍚庨潰鐧诲綍鐨�,浼氭尋鎺変箣鍓嶇櫥褰曠殑SessionId
-            System.out.println("鍏ㄥ眬瀛樺偍涓綋鍓峉essionId涓�:"+request.getSession().getId());
-            request.getServletContext().setAttribute(userName,request.getSession().getId());
+            //System.out.println("鍏ㄥ眬瀛樺偍涓綋鍓峉essionId涓�:"+request.getSession().getId());
+            //request.getServletContext().setAttribute(userName,request.getSession().getId());
+            RBucket<String> bucket = redissonClient.getBucket(userName);
+            bucket.set(request.getSession().getId());
+
             return new Response<>().set(1,true);
         }
         return new Response<>().set(1,false);
diff --git a/src/main/java/com/whyc/util/EmptyUtil.java b/src/main/java/com/whyc/util/EmptyUtil.java
new file mode 100644
index 0000000..b4a7128
--- /dev/null
+++ b/src/main/java/com/whyc/util/EmptyUtil.java
@@ -0,0 +1,148 @@
+package com.whyc.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Description 鍒ゆ柇瀵硅薄鏄惁涓虹┖鐨勫伐鍏风被
+ */
+public abstract class EmptyUtil {
+
+	/**
+	 * 
+	 * @鏂规硶鍚嶏細瀵逛簬String绫诲瀷鐨勯潪绌哄垽鏂�
+	 * @鍔熻兘璇存槑锛氬浜嶴tring绫诲瀷鐨勯潪绌哄垽鏂�
+	 * @author 鏉熸枃濂�
+	 * @date  Mar 28, 2013 9:26:09 AM
+	 * @param str
+	 * @return boolean true-涓虹┖锛宖alse-涓嶄负绌�
+	 */
+	public static boolean isNullOrEmpty(String str) {
+		if (str == null || "".equals(str.trim()) || "null".equalsIgnoreCase(str.trim()) || "undefined".equalsIgnoreCase(str.trim())) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	/**
+	 * 
+	 * @鏂规硶鍚嶏細瀵逛簬StringBuffer绫诲瀷鐨勯潪绌哄垽鏂�
+	 * @鍔熻兘璇存槑锛氬浜嶴tringBuffer绫诲瀷鐨勯潪绌哄垽鏂�
+	 * @author 鏉熸枃濂�
+	 * @date  Mar 28, 2013 9:26:09 AM
+	 * @param str
+	 * @return boolean true-涓虹┖锛宖alse-涓嶄负绌�
+	 */
+	public static boolean isNullOrEmpty(StringBuffer str) {
+		return (str == null || str.length() == 0);
+	}
+
+	/**
+	 * 
+	 * @鏂规硶鍚嶏細瀵逛簬string鏁扮粍绫诲瀷鐨勯潪绌哄垽鏂�
+	 * @鍔熻兘璇存槑锛氬浜巗tring鏁扮粍绫诲瀷鐨勯潪绌哄垽鏂�
+	 * @author 鏉熸枃濂�
+	 * @date  Mar 28, 2013 9:26:09 AM
+	 * @param str
+	 * @return boolean true-涓虹┖锛宖alse-涓嶄负绌�
+	 */
+	public static boolean isNullOrEmpty(String[] str) {
+		if (str == null || str.length == 0) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	/**
+	 * 
+	 * @鏂规硶鍚嶏細瀵逛簬Object绫诲瀷鐨勯潪绌哄垽鏂�
+	 * @鍔熻兘璇存槑锛氬浜嶰bject绫诲瀷鐨勯潪绌哄垽鏂�
+	 * @author 鏉熸枃濂�
+	 * @date  Mar 28, 2013 9:26:09 AM
+	 * @param obj
+	 * @return boolean true-涓虹┖锛宖alse-涓嶄负绌�
+	 */
+	public static boolean isNullOrEmpty(Object obj) {
+		if (obj == null || "".equals(obj)) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	/**
+	 * 
+	 * @鏂规硶鍚嶏細瀵逛簬Object鏁扮粍绫诲瀷鐨勯潪绌哄垽鏂�
+	 * @鍔熻兘璇存槑锛氬浜嶰bject鏁扮粍绫诲瀷鐨勯潪绌哄垽鏂�
+	 * @author 鏉熸枃濂�
+	 * @date  Mar 28, 2013 9:26:09 AM
+	 * @param obj
+	 * @return boolean true-涓虹┖锛宖alse-涓嶄负绌�
+	 */
+	public static boolean isNullOrEmpty(Object[] obj) {
+		if (obj == null || obj.length == 0) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	/**
+	 * 
+	 * @鏂规硶鍚嶏細瀵逛簬Collection绫诲瀷鐨勯潪绌哄垽鏂�
+	 * @鍔熻兘璇存槑锛氬浜嶤ollection绫诲瀷鐨勯潪绌哄垽鏂�
+	 * @author 鏉熸枃濂�
+	 * @date  Mar 28, 2013 9:26:09 AM
+	 * @param str
+	 * @return boolean true-涓虹┖锛宖alse-涓嶄负绌�
+	 */
+	@SuppressWarnings("rawtypes")
+	public static boolean isNullOrEmpty(Collection collection) {
+		if (collection == null || collection.isEmpty()) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	/**
+	 * @鏂规硶鍚嶏細瀵逛簬Map绫诲瀷鐨勯潪绌哄垽鏂�
+	 * @鍔熻兘璇存槑锛氬浜嶮ap绫诲瀷鐨勯潪绌哄垽鏂�
+	 * @author 鏉熸枃濂�
+	 *@param map
+	 *@return  浼犱汉鍙傛暟
+	 * @throws
+	 */
+	@SuppressWarnings("rawtypes")
+	public static boolean isNullOrEmpty( Map map) {
+		if (map == null || map.isEmpty()) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	/**
+	 * 
+	 * @鏂规硶鍚嶏細removeNullUnit
+	 * @鍔熻兘璇存槑锛� 鍒犻櫎闆嗗悎涓殑绌哄厓绱�
+	 * @author 鏉熸枃濂�
+	 * @date  2014-6-16 涓婂崍8:50:14
+	 * @param xllxList
+	 * @return
+	 */
+	public static <T> List<T> removeNullUnit(List<T> xllxList) {
+		List<T> need = new ArrayList<T>();
+		for (int i = 0; i < xllxList.size(); i++) {
+			if (!isNullOrEmpty(xllxList.get(i))) {
+				need.add(xllxList.get(i));
+			}
+		}
+		return need;
+	}
+
+}
diff --git a/src/main/java/com/whyc/util/ShiroRedissionSerialize.java b/src/main/java/com/whyc/util/ShiroRedissionSerialize.java
new file mode 100644
index 0000000..6f09525
--- /dev/null
+++ b/src/main/java/com/whyc/util/ShiroRedissionSerialize.java
@@ -0,0 +1,78 @@
+package com.whyc.util;
+
+import com.alibaba.druid.util.StringUtils;
+import lombok.extern.log4j.Log4j2;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.*;
+
+/**
+ * @Description锛氳嚜瀹氫箟搴忓垪鍖栧伐鍏�
+ */
+@Slf4j
+public class ShiroRedissionSerialize {
+
+    //搴忓垪鍖栨柟娉�
+    public static String serialize(Object object){
+        //鍒ゆ柇瀵硅薄鏄惁涓虹┖
+        if (EmptyUtil.isNullOrEmpty(object)){
+            return null;
+        }
+        //娴佺殑鎿嶄綔
+        ByteArrayOutputStream bos = null;
+        ObjectOutputStream oos =null;
+        String encodeBase64 = null;
+        bos = new ByteArrayOutputStream();
+        try {
+            oos = new ObjectOutputStream(bos);
+            oos.writeObject(object);
+            //杞崲瀛楃涓�
+            encodeBase64 = EncodesUtil.encodeBase64(bos.toByteArray());
+        } catch (IOException e) {
+            e.printStackTrace();
+            log.error("娴佸啓鍏ュ紓甯革細{}",e);
+        }finally {
+            //鍏抽棴娴�
+            try {
+                bos.close();
+                oos.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+                log.error("娴佸啓鍏ュ紓甯革細{}",e);
+            }
+        }
+        return encodeBase64;
+    }
+
+    //鍙嶅簭鍒楀寲鏂规硶
+    public static Object deserialize(String str){
+        //鍒ゆ柇鏄惁涓虹┖
+        if (EmptyUtil.isNullOrEmpty(str)){
+            return null;
+        }
+        //娴佷粠鎿嶄綔
+        ByteArrayInputStream bis =null;
+        ObjectInputStream ois = null;
+        Object object = null;
+        //杞崲瀵硅薄
+        bis = new ByteArrayInputStream(EncodesUtil.decodeBase64(str));
+        try {
+            ois = new ObjectInputStream(bis);
+            object = ois.readObject();
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error("娴佽鍙栧紓甯革細{}",e);
+        }finally {
+            //鍏抽棴娴�
+            try {
+                bis.close();
+                ois.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+                log.error("娴佽鍙栧紓甯革細{}",e);
+            }
+
+        }
+        return object;
+    }
+}
diff --git a/src/main/resources/config/application.yml b/src/main/resources/config/application.yml
index 1369392..062492b 100644
--- a/src/main/resources/config/application.yml
+++ b/src/main/resources/config/application.yml
@@ -59,3 +59,38 @@
 knife:
   enable: true
 #  enable: fase
+redis:
+  #妯″紡 single/sentinel/cluster
+  model: single
+  timeout: 3000
+  global-session-timeout: 360000
+  password:
+  #杩炴帴姹犻厤缃�
+  pool:
+    size: 10
+    max-idle: 16
+    min-idle: 8
+    max-active: 8
+    max-wait: 3000
+    conn-timeout: 3000
+    so-timeout: 3000
+  #鍗曟満閰嶇疆
+  single:
+    address: redis://localhost:6379
+  #鍝ㄥ叺閰嶇疆
+  sentinel:
+    master: business-master
+    nodes: redis://localhost:6379,redis://localhost:6380
+    master-onlyWrite: true
+    fail-max: 3
+  #闆嗙兢閰嶇疆
+  cluster:
+    scan-interval: 1000
+    nodes: redis://localhost:6379
+    read-mode: SLAVE
+    retry-attempts: 3
+    failed-attempts: 3
+    slave-connection-pool-size: 64
+    master-connection-pool-size: 64
+    retry-interval: 1500
+
diff --git a/src/main/resources/config/authentication.properties b/src/main/resources/config/authentication.properties
index 317c088..32ba9e6 100644
--- a/src/main/resources/config/authentication.properties
+++ b/src/main/resources/config/authentication.properties
@@ -1,5 +1,5 @@
 #dev鎺ュ彛璋冭瘯鏃朵娇鐢�
-/**=anon
+#/**=anon
 
 #闈欐�佽祫婧愪笉鎷︽埅
 /static/**=anon
@@ -19,9 +19,9 @@
 #/resource/**=roles-or[dev,SuperAdmin]
 
 #璁剧疆闇�瑕乸ermission鐨勬嫤鎴�
-/WaterComm/**=perms["water:all"]
+#/WaterComm/**=perms["water:all"]
 #璁剧疆RolesOr鎷︽埅
 #/WaterComm/**=rolesOr["admin","dev"]
 
 #鍏朵粬閾炬帴鏄渶瑕佺櫥褰曠殑
-#/**=authc
+/**=authc

--
Gitblit v1.9.1