SpringBootラーニング-(25)SpringBoot統合Shiro(詳細)


統合の内容は次のとおりです.
  • カスタムrealm、認証と認可
  • を実現
  • カスタム暗号化、パスワード暗号化検証
  • を実現
  • Cachemanager、Cacheをカスタマイズし、Shiroのcache管理を実現し、redisに
  • 保存する.
  • SessionManager、SessionDao、SessionIdCookieをカスタマイズし、Shiroのsession管理を実現し、redsiに
  • 保存する
  • RememberMeManager、RemeberMeCookieをカスタマイズし、Shiroが私の機能を記憶することを実現する
  • maven依存の追加
    
    
    <dependency>
        <groupId>org.apache.shirogroupId>
        <artifactId>shiro-springartifactId>
        <version>1.3.2version>
    dependency>
    
    
    <dependency>
        <groupId>redis.clientsgroupId>
        <artifactId>jedisartifactId>
    dependency>
    
    
    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
    dependency>

    Shiro構成
    package com.ahut.config;
    
    import com.ahut.shiro.MyRealm;
    import com.ahut.shiro.RedisShiroCacheManager;
    import com.ahut.shiro.RedisShiroSessionDao;
    import com.ahut.utils.ShiroUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.session.mgt.SessionManager;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.CookieRememberMeManager;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.apache.shiro.web.servlet.SimpleCookie;
    import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @author cheng
     * @className: ShiroConfig
     * @description: shiro  
     * @dateTime 2018/4/18 15:38
     */
    @Configuration
    @Slf4j
    public class ShiroConfig {
    
    }

    Shiroツール類
    package com.ahut.utils;
    
    import com.ahut.entity.User;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.crypto.hash.Md5Hash;
    import org.apache.shiro.session.Session;
    import org.apache.shiro.subject.Subject;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * @author cheng
     * @className: ShiroUtil
     * @description:   shiro session    
     * @dateTime 2018/4/19 10:15
     */
    public class ShiroUtil {
    
        /**
         *     
         */
        private static Logger log = LoggerFactory.getLogger(ShiroUtil.class);
        /**
         *     
         */
        private static final String CURRENT_USER = "CURRENT_USER";
        /**
         * shiro    
         */
        public static final String HASH_ALGORITHM_NAME = "md5";
        /**
         *     
         */
        public static final int HASH_ITERATIONS = 2;
        /**
         *   session    
         */
        public static final int GLOBAL_SESSION_TIMEOUT = 60000;
        /**
         *    shiro session cookie  
         */
        public static final String SESSIONID_COOKIE_NAME = "SHIRO_SESSION_ID";
        /**
         *    remeber me cookie  
         */
        public static final String REMEBER_ME_COOKIE_NAME = "REMEBER_ME";
        /**
         * shiro session  
         */
        public static final String SHIRO_SESSION_PREFIX = "shiro_session:";
        /**
         * shiro cache  
         */
        public static final String SHIRO_CACHE_PREFIX = "shiro_cache:";
        /**
         * shiro session    - 
         */
        public static final int EXPIRE_SECONDS = 60;
    
        /**
         * @description:        
         * @author cheng
         * @dateTime 2018/4/19 10:15
         */
        private ShiroUtil() {
        }
    
        /**
         * @description:   session
         * @author cheng
         * @dateTime 2018/4/19 10:38
         */
        public static Session getSession() {
            Session session = null;
            try {
                Subject currentUser = SecurityUtils.getSubject();
                session = currentUser.getSession();
            } catch (Exception e) {
                log.warn("  shiro     session      ", e);
                throw e;
            }
            return session;
        }
    
        /**
         * @description:      shiro session 
         * @author cheng
         * @dateTime 2018/4/19 10:45
         */
        public static void setAttribute(Object key, Object value) {
            try {
                Session session = getSession();
                session.setAttribute(key, value);
            } catch (Exception e) {
                log.warn("       Shiro Session       ", e);
                throw e;
            }
        }
    
        /**
         * @description:   shiro session    
         * @author cheng
         * @dateTime 2018/4/19 10:48
         */
        public static Object getAttribute(Object key) {
            Object value = null;
            try {
                Session session = getSession();
                value = session.getAttribute(key);
            } catch (Exception e) {
                log.warn("  shiro session          ", e);
                throw e;
            }
            return value;
        }
    
        /**
         * @description:   shiro session    
         * @author cheng
         * @dateTime 2018/4/19 10:51
         */
        public static void removeAttribute(Object key) {
            try {
                Session session = getSession();
                session.removeAttribute(key);
            } catch (Exception e) {
                log.warn("  shiro session          ", e);
                throw e;
            }
        }
    
        /**
         * @description:       
         * @author cheng
         * @dateTime 2018/4/19 10:59
         */
        public static void setCurrentUser(Object user) {
            setAttribute(CURRENT_USER, user);
        }
    
        /**
         * @description:       
         * @author cheng
         * @dateTime 2018/4/19 10:59
         */
        public static User getCurrentUser() {
            User user = (User) getAttribute(CURRENT_USER);
            return user;
        }
    
        /**
         * @description:      
         * @author cheng
         * @dateTime 2018/4/19 10:59
         */
        public static void removeCurrentUser() {
            removeAttribute(CURRENT_USER);
        }
    
        /**
         * @description:     
         * @author cheng
         * @dateTime 2018/4/23 15:01
         */
        public static String encrypt(String password, String salt) {
            Md5Hash md5Hash = new Md5Hash(password, salt, HASH_ITERATIONS);
            return md5Hash.toString();
        }
    
    }

    redisを構成するには、このブログを参照してください:springboot統合redis redisツールクラス
    package com.ahut.utils;
    
    import org.apache.commons.lang3.ArrayUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.util.CollectionUtils;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    
    import java.util.Set;
    
    /**
     * @author cheng
     * @className: RedisUtil
     * @description: redis     
     * @dateTime 2018/4/23 16:12
     */
     //        JedisPool    spring  ,          IOC  
    @Component
    public class RedisUtil {
    
        /**
         * jedisPool
         */
        private static JedisPool jedisPool;
    
        /**
         * @description:     ,   set  jedispool
         * @author cheng
         * @dateTime 2018/4/24 9:45
         */
        @Autowired
        public void setJedisPool(JedisPool jedisPool) {
            RedisUtil.jedisPool = jedisPool;
        }
    
        /**
         * @description:        
         * @author cheng
         * @dateTime 2018/4/23 16:12
         */
        private RedisUtil() {
        }
    
        /**
         * @description:   jedis
         * @author cheng
         * @dateTime 2018/4/24 9:47
         */
        public static Jedis getJedis() {
            return jedisPool.getResource();
        }
    
        /**
         * @description:    redis
         * @author cheng
         * @dateTime 2018/4/24 10:04
         */
        public static void set(byte[] key, byte[] value) {
            Jedis jedis = getJedis();
            try {
                jedis.set(key, value);
            } finally {
                jedis.close();
            }
        }
    
        /**
         * @description:  redis   
         * @author cheng
         * @dateTime 2018/4/24 10:11
         */
        public static byte[] get(byte[] key) {
            Jedis jedis = getJedis();
            try {
                return jedis.get(key);
            } finally {
                jedis.close();
            }
        }
    
        /**
         * @description:  redis   
         * @author cheng
         * @dateTime 2018/4/24 10:17
         */
        public static void del(byte[] key) {
            Jedis jedis = getJedis();
            try {
                jedis.del(key);
            } finally {
                jedis.close();
            }
        }
    
        /**
         * @description:       key
         * @author cheng
         * @dateTime 2018/4/24 16:48
         */
        public static void delByPrefix(String keyPrefix) {
            keyPrefix = keyPrefix + "*";
            Jedis jedis = getJedis();
            try {
                Set<byte[]> keyByteArraySet = jedis.keys(keyPrefix.getBytes());
                for (byte[] keyByteArray : keyByteArraySet) {
                    jedis.del(keyByteArray);
                }
            } finally {
                jedis.close();
            }
        }
    
        /**
         * @description:   redis    
         * @author cheng
         * @dateTime 2018/4/24 10:21
         */
        public static void expire(byte[] key, int seconds) {
            Jedis jedis = getJedis();
            try {
                jedis.expire(key, seconds);
            } finally {
                jedis.close();
            }
        }
    
        /**
         * @description:  redis        key
         * @author cheng
         * @dateTime 2018/4/24 10:25
         */
        public static Set<byte[]> keys(String shiroSessionPrefix) {
            shiroSessionPrefix = shiroSessionPrefix + "*";
            Jedis jedis = getJedis();
            try {
                return jedis.keys(shiroSessionPrefix.getBytes());
            } finally {
                jedis.close();
            }
        }
    }

    カスタムRealm
    package com.ahut.shiro;
    
    import com.ahut.common.ApiResponse;
    import com.ahut.entity.User;
    import com.ahut.enums.UserStatusEnum;
    import com.ahut.service.UserService;
    import com.ahut.utils.ShiroUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.shiro.authc.*;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.crypto.hash.Md5Hash;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.apache.shiro.util.ByteSource;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    
    /**
     * @author cheng
     * @className: MyRealm
     * @description:    realm
     * @dateTime 2018/4/18 15:40
     */
    @Slf4j
    public class MyRealm extends AuthorizingRealm {
    
        /**
         *       ,     spring     ,
         *   MyRealm      IOC   ,     userService null
         */
        @Autowired
        private UserService userService;
    
        /**
         * @description:     
         * @author cheng
         * @dateTime 2018/4/18 15:42
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            UsernamePasswordToken newToken = (UsernamePasswordToken) token;
            //       
            String userAccount = newToken.getUsername();
            log.info("  {}    ", userAccount);
            //           
            ApiResponse apiResponse = userService.selectByUserAccount(userAccount);
            //      
            if (ApiResponse.FAIL_TYPE.equals(apiResponse.getType())) {
                throw new UnknownAccountException();
            }
            List userList = (List) apiResponse.getData();
            User user = userList.get(0);
            //       
            int userStatus = user.getUserStatus();
            //       
            String userPassword = user.getUserPassword();
            //     
            if (userStatus == UserStatusEnum.LOCKED_ACCOUNT.getCode()) {
                throw new LockedAccountException();
            }
            //     
            if (userStatus == UserStatusEnum.DISABLED_ACCOUNT.getCode()) {
                throw new DisabledAccountException();
            }
            //  
            String salt = user.getId();
            //          shiro session 
            ShiroUtil.setCurrentUser(user);
            //  UsernamePasswordToken(userAccount, userPassword)    
            //       Shiro  ,       
            //      Shiro   ,   UsernamePasswordToken(userAccount, userPassword)        ,
            //   SimpleAuthenticationInfo(userAccount, userPassword, ByteSource.Util.bytes(salt), this.getName())        
            return new SimpleAuthenticationInfo(userAccount, userPassword, ByteSource.Util.bytes(salt), this.getName());
        }
    
        /**
         * @description:     
         * @author cheng
         * @dateTime 2018/4/18 15:42
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            //       
            // String userAccount = (String) principals.getPrimaryPrincipal();
            //                  
    
            log.info("      ");
    
            //   
            List roles = new ArrayList<>();
            roles.add("admin");
            roles.add("user");
            //   
            List permissions = new ArrayList<>();
            permissions.add("admin:select");
            permissions.add("admin:delete");
    
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            simpleAuthorizationInfo.addStringPermissions(permissions);
            simpleAuthorizationInfo.addRoles(roles);
            return simpleAuthorizationInfo;
        }
    
    }

    ShiroConfigに構成を追加する
        /**
         * @description:   realm
         * @author cheng
         * @dateTime 2018/4/18 15:44
         */
        @Bean
        public MyRealm createMyRealm() {
            MyRealm myRealm = new MyRealm();
            log.info("   realm");
            return myRealm;
        }

    カスタム暗号化
    ユーザーの保存時のユーザーパスワード->暗号化->データベースに保存する暗号化方法
        /**
         *     
         */
        public static final int HASH_ITERATIONS = 2;
    
        /**
         * @description:     
         * @author cheng
         * @dateTime 2018/4/23 15:01
         */
        public static String encrypt(String password, String salt) {
            Md5Hash md5Hash = new Md5Hash(password, salt, HASH_ITERATIONS);
            return md5Hash.toString();
        }

    ユーザ認証時のユーザパスワード->暗号化->認証修正ShiroConfigでのカスタムRealm構成
        /**
         * @description:   realm
         * @author cheng
         * @dateTime 2018/4/18 15:44
         */
        @Bean
        public MyRealm createMyRealm() {
            //     
            HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
            //     
            hashedCredentialsMatcher.setHashAlgorithmName(ShiroUtil.HASH_ALGORITHM_NAME);
            //     
            hashedCredentialsMatcher.setHashIterations(ShiroUtil.HASH_ITERATIONS);
            MyRealm myRealm = new MyRealm();
            myRealm.setCredentialsMatcher(hashedCredentialsMatcher);
            log.info("   realm");
            return myRealm;
        }

    カスタムキャッシュ管理
    カスタムCache
    package com.ahut.shiro;
    
    import com.ahut.utils.RedisUtil;
    import com.ahut.utils.ShiroUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.shiro.cache.Cache;
    import org.apache.shiro.cache.CacheException;
    import org.springframework.util.SerializationUtils;
    
    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;
    import java.util.Set;
    
    /**
     * @author cheng
     * @className: RedisShiroCache
     * @description: redis  shiro  
     * @dateTime 2018/4/24 16:04
     */
    @Slf4j
    public class RedisShiroCache<K, V> implements Cache<K, V> {
    
        /**
         * @description:       key     
         * @author cheng
         * @dateTime 2018/4/24 9:57
         */
        private byte[] getKey(Object key) {
            return (ShiroUtil.SHIRO_CACHE_PREFIX + key).getBytes();
        }
    
        /**
         * @description:         
         * @author cheng
         * @dateTime 2018/4/24 16:09
         */
        @Override
        public Object get(Object key) throws CacheException {
            if (key == null) {
                return null;
            }
            //     
            byte[] keyByteArray = getKey(key);
            //  redis     
            byte[] valueByteArray = RedisUtil.get(keyByteArray);
            log.info("        ");
            //        
            return valueByteArray == null ? null : SerializationUtils.deserialize(valueByteArray);
        }
    
        /**
         * @description:   shiro   redis
         * @author cheng
         * @dateTime 2018/4/24 16:13
         */
        @Override
        public Object put(Object key, Object value) throws CacheException {
            if (key == null || value == null) {
                return null;
            }
            //    
            byte[] keyByteArray = getKey(key);
            byte[] valueByteArray = SerializationUtils.serialize((Serializable) value);
            RedisUtil.set(keyByteArray, valueByteArray);
            log.info("  shiro   redis");
            //       
            return SerializationUtils.deserialize(valueByteArray);
        }
    
        /**
         * @description:  redis   
         * @author cheng
         * @dateTime 2018/4/24 16:19
         */
        @Override
        public Object remove(Object key) throws CacheException {
            if (key == null) {
                return null;
            }
            //    
            byte[] keyByteArray = getKey(key);
            byte[] valueByteArray = RedisUtil.get(keyByteArray);
            //   
            RedisUtil.del(keyByteArray);
            log.info(" redis   ");
            //        
            return SerializationUtils.deserialize(valueByteArray);
        }
    
        /**
         * @description:        
         * @author cheng
         * @dateTime 2018/4/24 16:25
         */
        @Override
        public void clear() throws CacheException {
            log.info("       ");
            RedisUtil.delByPrefix(ShiroUtil.SHIRO_CACHE_PREFIX);
        }
    
        /**
         * @description:     
         * @author cheng
         * @dateTime 2018/4/24 16:56
         */
        @Override
        public int size() {
            Set keyByteArraySet = RedisUtil.keys(ShiroUtil.SHIRO_CACHE_PREFIX);
            log.info("      ");
            return keyByteArraySet.size();
        }
    
        /**
         * @description:      key
         * @author cheng
         * @dateTime 2018/4/24 16:59
         */
        @Override
        public Set keys() {
            Set keyByteArraySet = RedisUtil.keys(ShiroUtil.SHIRO_CACHE_PREFIX);
            log.info("       key");
            return keyByteArraySet;
        }
    
        /**
         * @description:      value
         * @author cheng
         * @dateTime 2018/4/24 16:59
         */
        @Override
        public Collection values() {
            Set keySet = this.keys();
            List valueList = new ArrayList<>(16);
            for (Object key : keySet) {
                byte[] keyByteArray = SerializationUtils.serialize(key);
                byte[] valueByteArray = RedisUtil.get(keyByteArray);
                valueList.add(SerializationUtils.deserialize(valueByteArray));
            }
            log.info("       value");
            return valueList;
        }
    
    }

    カスタムCacheManager
    package com.ahut.shiro;
    
    import org.apache.shiro.cache.Cache;
    import org.apache.shiro.cache.CacheException;
    import org.apache.shiro.cache.CacheManager;
    
    /**
     * @author cheng
     * @className: RedisShiroCacheManager
     * @description: redis shiro      
     * @dateTime 2018/4/24 15:58
     */
    public class RedisShiroCacheManager implements CacheManager {
    
        /**
         * @description:
         * @author cheng
         * @dateTime 2018/4/24 16:05
         */
        @Override
        public  Cache getCache(String name) throws CacheException {
            return new RedisShiroCache();
        }
    }

    ShiroConfigに構成を追加する
        /**
         * @description:         
         * @author cheng
         * @dateTime 2018/4/24 15:59
         */
        public RedisShiroCacheManager createCacheManager() {
            RedisShiroCacheManager redisShiroCacheManager = new RedisShiroCacheManager();
            log.info("   CacheManager");
            return redisShiroCacheManager;
        }

    カスタムセッション管理
    カスタムセッションDao
    package com.ahut.shiro;
    
    import com.ahut.utils.RedisUtil;
    import com.ahut.utils.ShiroUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.shiro.session.Session;
    import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
    import org.springframework.util.SerializationUtils;
    
    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;
    import java.util.Set;
    
    /**
     * @author cheng
     * @className: RedisShiroSessionDao
     * @description:   redis  shiro session
     * @dateTime 2018/4/24 9:26
     */
    @Slf4j
    public class RedisShiroSessionDao extends EnterpriseCacheSessionDAO {
    
        /**
         * @description:       key     
         * @author cheng
         * @dateTime 2018/4/24 9:57
         */
        private byte[] getKey(String key) {
            return (ShiroUtil.SHIRO_SESSION_PREFIX + key).getBytes();
        }
    
        /**
         * @description:     ;           /    /      /          
         * @author cheng
         * @dateTime 2018/4/24 9:32
         */
        @Override
        public void doUpdate(Session session) {
            //   session
            if (session != null && session.getId() != null) {
                byte[] key = getKey(session.getId().toString());
                //    session
                byte[] value = SerializationUtils.serialize(session);
                //  session     redis 
                RedisUtil.set(key, value);
                log.info("  session:{}", session);
            }
        }
    
        /**
         * @description:     ;     /    (      )   
         * @author cheng
         * @dateTime 2018/4/24 9:31
         */
        @Override
        protected void doDelete(Session session) {
            //   session
            if (session != null && session.getId() != null) {
                byte[] key = getKey(session.getId().toString());
                //  redis   session
                RedisUtil.del(key);
                log.info("  session:{}", session);
            }
        }
    
        /**
         * @description:  DefaultSessionManager    session       ;
         *          /    /NoSQL   ;           ;
         *     ID;       ID.equals(session.getId());
         * @author cheng
         * @dateTime 2018/4/24 9:32
         */
        @Override
        public Serializable doCreate(Session session) {
            //   session
            if (session != null) {
                //   sessionId
                Serializable sessionId = super.doCreate(session);
                byte[] key = getKey(sessionId.toString());
                //    session
                byte[] value = SerializationUtils.serialize(session);
                //  session     redis 
                RedisUtil.set(key, value);
                //       
                RedisUtil.expire(key, ShiroUtil.EXPIRE_SECONDS);
                log.info("  session:{}", session);
                return sessionId;
            }
            return null;
        }
    
        /**
         * @description:     ID    
         * @author cheng
         * @dateTime 2018/4/24 9:32
         */
        @Override
        public Session doReadSession(Serializable sessionId) {
            if (sessionId != null) {
                byte[] key = getKey(sessionId.toString());
                byte[] value = RedisUtil.get(key);
                //     session
                Session session = (Session) SerializationUtils.deserialize(value);
                log.info("  session:{}", session);
                return session;
            }
            return null;
        }
    
        /**
         * @description:           ,             
         * @author cheng
         * @dateTime 2018/4/24 9:32
         */
        @Override
        public Collection getActiveSessions() {
            List sessionList = new ArrayList<>(16);
            //  redis   
            Set<byte[]> keyByteArraySet = RedisUtil.keys(ShiroUtil.SHIRO_SESSION_PREFIX);
            for (byte[] keyByteArray : keyByteArraySet) {
                //     
                Session session = (Session) SerializationUtils.deserialize(keyByteArray);
                sessionList.add(session);
            }
            return sessionList;
        }
    
    }

    ShiroConfigでSessionDaoを設定する
        /**
         * @description:    sessionDao
         * @author cheng
         * @dateTime 2018/4/24 10:47
         */
        public RedisShiroSessionDao createRedisShiroSessionDao() {
            RedisShiroSessionDao sessionDao = new RedisShiroSessionDao();
            //        
            sessionDao.setCacheManager(createCacheManager());
            log.info("   sessionDao");
            return sessionDao;
        }

    ShiroConfigでShiroセッションクッキー情報をカスタマイズ
        /**
         * @description:    shiro session cookie
         * @author cheng
         * @dateTime 2018/4/24 11:09
         */
        public SimpleCookie createSessionIdCookie() {
            SimpleCookie simpleCookie = new SimpleCookie(ShiroUtil.SESSIONID_COOKIE_NAME);
            //                   
            simpleCookie.setHttpOnly(true);
            //   Cookie     ,    ,     -1       , Cookie  
            simpleCookie.setMaxAge(-1);
            log.info("   SessionIdCookie");
            return simpleCookie;
        }

    ShiroConfigでSessionManagerを構成する
        /**
         * @description:    sessionManager
         * @author cheng
         * @dateTime 2018/4/24 10:37
         */
        public SessionManager createMySessionManager() {
            DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
            //    sessionDao
            sessionManager.setSessionDAO(createRedisShiroSessionDao());
            // session     ,     
            sessionManager.setGlobalSessionTimeout(ShiroUtil.GLOBAL_SESSION_TIMEOUT);
            //      session
            sessionManager.setDeleteInvalidSessions(true);
            //    session    id   Cookie  ,     Cookie     
            sessionManager.setSessionIdCookie(createSessionIdCookie());
            //   sessionIdCookie           
            sessionManager.setSessionIdCookieEnabled(true);
            log.info("  sessionManager");
            return sessionManager;
        }

    カスタム記憶
    ShiroConfigでカスタマイズして私のクッキーを覚えてください
        /**
         * @description:    cookie
         * @author cheng
         * @dateTime 2018/4/24 15:39
         */
        public SimpleCookie createRemeberMeCookie() {
            SimpleCookie simpleCookie = new SimpleCookie(ShiroUtil.REMEBER_ME_COOKIE_NAME);
            //                   
            simpleCookie.setHttpOnly(true);
            //   Cookie     ,    ,     -1       , Cookie  
            simpleCookie.setMaxAge(2592000);
            log.info("   RemeberMeCookie");
            return simpleCookie;
        }

    ShiroConfigでRememberMeManagerを構成する
        /**
         * @description:       
         * @author cheng
         * @dateTime 2018/4/24 15:35
         */
        public CookieRememberMeManager createRememberMeManager() {
            CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
            //       cookie
            cookieRememberMeManager.setCookie(createRemeberMeCookie());
            log.info("  RemeberMeManager");
            return cookieRememberMeManager;
        }

    ログイン時、私を覚えてください.
    package com.ahut.serviceImpl;
    
    import com.ahut.common.ApiResponse;
    import com.ahut.entity.User;
    import com.ahut.service.LoginService;
    import com.ahut.service.UserService;
    import com.ahut.utils.ShiroUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.*;
    import org.apache.shiro.subject.Subject;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    import java.util.Date;
    
    /**
     * @author cheng
     * @className: LoginServiceImpl
     * @description:
     * @dateTime 2018/4/19 9:21
     */
    @Service
    @Transactional
    @Slf4j
    public class LoginServiceImpl implements LoginService {
    
        /**
         *       
         */
        @Autowired
        private UserService userService;
    
        /**
         * @description:   
         * @author cheng
         * @dateTime 2018/4/19 9:21
         */
        @Override
        public ApiResponse login(String userAccount, String userPassword) {
            //       
            Subject subject = SecurityUtils.getSubject();
            //       
            UsernamePasswordToken token = new UsernamePasswordToken(userAccount, userPassword);
            //         
            User user = null;
            //     
            String msg = null;
            try {
                //    
                token.setRememberMe(true);
                subject.login(token);
                //       ,      
                user = ShiroUtil.getCurrentUser();
                //          
                //       
                user.setLastLoginTime(new Date());
                userService.updateUser(user);
                msg = "      ";
                return ApiResponse.createSuccessResponse(msg, user);
            } catch (UnknownAccountException e) {
                msg = "       ";
                log.warn(msg, e);
            } catch (LockedAccountException e) {
                msg = "       ";
                log.warn(msg, e);
            } catch (DisabledAccountException e) {
                msg = "       ";
                log.warn(msg, e);
            } catch (IncorrectCredentialsException e) {
                msg = "      ";
                log.warn(msg, e);
            }
            //       ,      
            ShiroUtil.removeCurrentUser();
            return ApiResponse.createFailResponse(msg);
        }
    
    }

    完全なShiroConfig構成
    package com.ahut.config;
    
    import com.ahut.shiro.MyRealm;
    import com.ahut.shiro.RedisShiroCacheManager;
    import com.ahut.shiro.RedisShiroSessionDao;
    import com.ahut.utils.ShiroUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.session.mgt.SessionManager;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.CookieRememberMeManager;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.apache.shiro.web.servlet.SimpleCookie;
    import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @author cheng
     * @className: ShiroConfig
     * @description: shiro  
     * @dateTime 2018/4/18 15:38
     */
    @Configuration
    @Slf4j
    public class ShiroConfig {
    
        /**
         * @description:   realm
         * @author cheng
         * @dateTime 2018/4/18 15:44
         */
        @Bean
        public MyRealm createMyRealm() {
            //     
            HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
            //     
            hashedCredentialsMatcher.setHashAlgorithmName(ShiroUtil.HASH_ALGORITHM_NAME);
            //     
            hashedCredentialsMatcher.setHashIterations(ShiroUtil.HASH_ITERATIONS);
            MyRealm myRealm = new MyRealm();
            myRealm.setCredentialsMatcher(hashedCredentialsMatcher);
            log.info("   realm");
            return myRealm;
        }
    
        /**
         * @description:    sessionDao
         * @author cheng
         * @dateTime 2018/4/24 10:47
         */
        public RedisShiroSessionDao createRedisShiroSessionDao() {
            RedisShiroSessionDao sessionDao = new RedisShiroSessionDao();
            //        
            sessionDao.setCacheManager(createCacheManager());
            log.info("   sessionDao");
            return sessionDao;
        }
    
        /**
         * @description:    shiro session cookie
         * @author cheng
         * @dateTime 2018/4/24 11:09
         */
        public SimpleCookie createSessionIdCookie() {
            SimpleCookie simpleCookie = new SimpleCookie(ShiroUtil.SESSIONID_COOKIE_NAME);
            //                   
            simpleCookie.setHttpOnly(true);
            //   Cookie     ,    ,     -1       , Cookie  
            simpleCookie.setMaxAge(-1);
            log.info("   SessionIdCookie");
            return simpleCookie;
        }
    
    
        /**
         * @description:    sessionManager
         * @author cheng
         * @dateTime 2018/4/24 10:37
         */
        public SessionManager createMySessionManager() {
            DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
            //    sessionDao
            sessionManager.setSessionDAO(createRedisShiroSessionDao());
            // session     ,     
            sessionManager.setGlobalSessionTimeout(ShiroUtil.GLOBAL_SESSION_TIMEOUT);
            //      session
            sessionManager.setDeleteInvalidSessions(true);
            //    session    id   Cookie  ,     Cookie     
            sessionManager.setSessionIdCookie(createSessionIdCookie());
            //   sessionIdCookie           
            sessionManager.setSessionIdCookieEnabled(true);
            log.info("  sessionManager");
            return sessionManager;
        }
    
        /**
         * @description:    cookie
         * @author cheng
         * @dateTime 2018/4/24 15:39
         */
        public SimpleCookie createRemeberMeCookie() {
            SimpleCookie simpleCookie = new SimpleCookie(ShiroUtil.REMEBER_ME_COOKIE_NAME);
            //                   
            simpleCookie.setHttpOnly(true);
            //   Cookie     ,    ,     -1       , Cookie  
            simpleCookie.setMaxAge(2592000);
            log.info("   RemeberMeCookie");
            return simpleCookie;
        }
    
        /**
         * @description:       
         * @author cheng
         * @dateTime 2018/4/24 15:35
         */
        public CookieRememberMeManager createRememberMeManager() {
            CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
            //       cookie
            cookieRememberMeManager.setCookie(createRemeberMeCookie());
            log.info("  RemeberMeManager");
            return cookieRememberMeManager;
        }
    
        /**
         * @description:         
         * @author cheng
         * @dateTime 2018/4/24 15:59
         */
        public RedisShiroCacheManager createCacheManager() {
            RedisShiroCacheManager redisShiroCacheManager = new RedisShiroCacheManager();
            log.info("   CacheManager");
            return redisShiroCacheManager;
        }
    
        /**
         * @description:        SecurityManager org.apache.shiro.mgt.SecurityManager,      
         * @author cheng
         * @dateTime 2018/4/18 15:48
         */
        public SecurityManager createSecurityManager() {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            //    realm
            securityManager.setRealm(createMyRealm());
            //    sessionManager
            securityManager.setSessionManager(createMySessionManager());
            //    rememberMeManager
            securityManager.setRememberMeManager(createRememberMeManager());
            //    cacheManager
            securityManager.setCacheManager(createCacheManager());
            log.info("  rsecurityManager");
            return securityManager;
        }
    
        /**
         * @description: shiro web   
         * @author cheng
         * @dateTime 2018/4/18 15:50
         */
        @Bean
        public ShiroFilterFactoryBean createShiroFilter() {
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            shiroFilterFactoryBean.setSecurityManager(createSecurityManager());
            //             Web       "/login.jsp"  
            shiroFilterFactoryBean.setLoginUrl("/v1/toLoginPage");
    
            //    
            Map filterChainDefinitionMap = new HashMap<>();
            //                
            //       ,        ,   /**     
            //         
            filterChainDefinitionMap.put("/v1/users/", "anon");
            //        
            filterChainDefinitionMap.put("/v1/toLoginPage", "anon");
            //      
            filterChainDefinitionMap.put("/v1/login", "anon");
            //            
            // anon:  url        
            filterChainDefinitionMap.put("/static/**", "anon");
    
            // authc:  url            
            filterChainDefinitionMap.put("/**", "anon");
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
            return shiroFilterFactoryBean;
        }
    
    }