1. 程式人生 > >springboot +shiro 詳細(ehcache快取)

springboot +shiro 詳細(ehcache快取)

1      匯入maven座標

  •   <!--shiro start-->
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-ehcache</artifactId>
                <version>1.3.2</version>
            </dependency>
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-spring</artifactId>
                <version>1.3.2</version>
            </dependency>
            <!--shiro end-->
            <!-- https://mvnrepository.com/artifact/net.sf.ehcache/ehcache-core -->
            <!--本地快取+shiro-->
            <dependency>
                <groupId>net.sf.ehcache</groupId>
                <artifactId>ehcache-core</artifactId>
                <version>2.6.11</version>
            </dependency>
    

    2   resouce 下的ehcache.xml檔案

  • <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    
        <!-- 配置快取資料夾
            預設:path="java.io.tmpdir"
             eternal="true":ture為設定快取永不過期
             通過註解當進行增刪改時清除快取,這樣就會是同步資料庫的快取了
        -->
        <diskStore path="D:\\temp"/>
    
        <defaultCache
                maxElementsInMemory="10000"
                eternal="true"
                maxElementsOnDisk="10000000"
                diskExpiryThreadIntervalSeconds="120"
                memoryStoreEvictionPolicy="LRU">
            <persistence strategy="localTempSwap"/>
        </defaultCache>
        <cache
                name="LL"
                maxElementsInMemory="10000"
                eternal="true"
                maxElementsOnDisk="10000000"
                diskExpiryThreadIntervalSeconds="120"
                memoryStoreEvictionPolicy="LRU">
            <persistence strategy="localTempSwap"/>
        </cache>
    
    </ehcache>
    

    3   shiro 配置類shiroconfig

  • package com.czxy.web.config;
    import com.czxy.web.shiro.BosCredentialsMatcher;
    import com.czxy.web.shiro.BosRealm;
    import org.apache.shiro.authc.credential.CredentialsMatcher;
    import org.apache.shiro.cache.ehcache.EhCacheManager;
    import org.apache.shiro.realm.Realm;
    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.mgt.SecurityManager;
    import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.LinkedHashMap;
    import java.util.Map;
    
    /**
     * 在ShiroConfig中做什麼事情呢?
     * 1 配置shiro安全管理器,向安全管理器中注入Realm域
     * 2 配置Realm域:注入密碼比較器
     * 3 配置密碼比較器
     * 4 配置攔截路徑和放行路徑
     */
    @Configuration
    public class ShiroConfig {
        /**
         * 配置安全管理器,並且注入Realm域
         *
         * @param realm
         * @return
         */
        @Bean
        public SecurityManager securityManager(Realm realm) {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            securityManager.setRealm(realm);
            securityManager.setCacheManager(ehCacheManager());//這個如果呼叫多次是同一個物件
            return securityManager;
        }
    
        /**
         * Credentials:憑證/證書 ---
         * <p>
         * 配置Realm域,注入密碼比較器
         *
         * @param credentialsMatcher
         * @return
         */
        @Bean
        public BosRealm realm(CredentialsMatcher credentialsMatcher) {
            BosRealm bosRealm = new BosRealm();
            bosRealm.setCredentialsMatcher(credentialsMatcher);
            return bosRealm;
        }
    
        /**
         * 密碼比較器
         *
         * @return
         */
        @Bean
        public CredentialsMatcher credentialsMatcher() {
    //    return new HashedCredentialsMatcher("MD5");
            return new BosCredentialsMatcher();
        }
    
        /**
         * 配置攔截路徑和放行路徑
         *
         * @param securityManager
         * @return
         */
        @Bean
        public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
            System.out.println("ShiroConfiguration.shirFilter()");
            // shiro過濾器工廠類
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    
            // 必須設定 SecurityManager
            shiroFilterFactoryBean.setSecurityManager(securityManager);
    
            //攔截器----Map集合
            Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
    
            //配置退出 過濾器,其中的具體的退出程式碼Shiro已經替我們實現了
            filterChainDefinitionMap.put("/login*", "anon");
            filterChainDefinitionMap.put("/user/login*", "anon");
            filterChainDefinitionMap.put("/validatecode.jsp*", "anon");
            filterChainDefinitionMap.put("/css/**", "anon");
            filterChainDefinitionMap.put("/js/**", "anon");
            filterChainDefinitionMap.put("/images/**", "anon");
            filterChainDefinitionMap.put("/data/**", "anon");
    //        許可權控制 粗粒度對頁面進行控制
    // (放入角色也可以控制權限)
            filterChainDefinitionMap.put("/pages/base/area**", "roles[base]");
    // (放入許可權也可以控制權限)
            filterChainDefinitionMap.put("/pages/base/courier**", "perms[courier:add]");
    
            //   /** 匹配所有的路徑
            //  通過Map集合組成了一個攔截器鏈 ,自頂向下過濾,一旦匹配,則不再執行下面的過濾
            //  如果下面的定義與上面衝突,那按照了誰先定義誰說了算
            //  /** 一定要配置在最後
            filterChainDefinitionMap.put("/**", "authc");
    
            // 將攔截器鏈設定到shiro中
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    
    
            // 如果不設定預設會自動尋找Web工程根目錄下的"/login.jsp"頁面
            shiroFilterFactoryBean.setLoginUrl("/login.html");
            // 登入成功後要跳轉的連結
            shiroFilterFactoryBean.setSuccessUrl("/index.html");
            //未授權介面;
            shiroFilterFactoryBean.setUnauthorizedUrl("/unauthority.html");
    
    
            return shiroFilterFactoryBean;
        }
    
        /**
         * 開啟shiro aop註解支援
         * 使用代理方式;所以需要開啟程式碼支援
         *
         * @param securityManager
         * @return
         */
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
            authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
            return authorizationAttributeSourceAdvisor;
        }
    
    
        /**
         * 開啟cglib代理
         *
         * @return
         */
        @Bean
        public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
            DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
            creator.setProxyTargetClass(true);
            return creator;
        }
    
        /**
         * ehcache 快取
         *
         * @return
         */
        @Bean
        public EhCacheManager ehCacheManager() {
            System.out.println("ShiroConfiguration.getEhCacheManager()");
            EhCacheManager cacheManager = new EhCacheManager();
            cacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
            return cacheManager;
        }
    
    }

    4 自定義ream域

  • package com.czxy.web.shiro;
    
    import com.czxy.domain.system.Permission;
    import com.czxy.domain.system.Role;
    import com.czxy.domain.system.User;
    import com.czxy.service.system.PermisionService;
    import com.czxy.service.system.RoleService;
    import com.czxy.service.system.UserService;
    import org.apache.shiro.authc.*;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import java.util.List;
    
    public class BosRealm extends AuthorizingRealm {
        @Autowired
        private UserService userService;
        @Autowired
        private RoleService roleService;
        @Autowired
        private PermisionService permission;
        //授權
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            System.out.println("授權");
            SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
            //通過shiro 中獲的使用者名稱
            User primaryPrincipal = (User) principals.getPrimaryPrincipal();
            //通過使用者名稱進行角色的查詢
            List<Role> byUserId = roleService.findByUserId(primaryPrincipal);
            for (Role role : byUserId) {
                authorizationInfo.addRole(role.getKeyword());
            }
            //通過使用者名稱進行查詢許可權
            List<Permission> permission = this.permission.findPermission(primaryPrincipal);
            for (Permission permission1 : permission) {
                authorizationInfo.addStringPermission(permission1.getKeyword());
            }
            return authorizationInfo;
        }
        //認證
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            System.out.println("認證");
          UsernamePasswordToken upToken= (UsernamePasswordToken)token;
           User user = userService.QueryUserByUpToken(upToken.getUsername());
    
           if(user!=null){
               //Object principal, Object credentials, String realmName
            return new SimpleAuthenticationInfo(user,user.getPassword(),this.getName());
           }
           //表示不存在
            return null;
        }
    }
    

    5.密碼比較器

  • package com.czxy.web.shiro;
    
    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
    import org.apache.shiro.crypto.hash.Sha256Hash;
    
    
    public class BosCredentialsMatcher extends SimpleCredentialsMatcher {
        @Override
        public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
            System.out.println("密碼比較器");
            UsernamePasswordToken upUptoken = (UsernamePasswordToken) token;
            //獲取頁面輸入的密碼
            String pwd = new String(upUptoken.getPassword());
            //對頁面密碼進行加密  upUptoken.getUsername撒鹽
            String Rpwd = new Sha256Hash(pwd, upUptoken.getUsername(), 3).toString();
            System.out.println(Rpwd);
            //獲取資料庫中的密碼
            String dbpwd = info.getCredentials().toString();
            return equals(Rpwd, dbpwd);
    
        }
    }
    

    6認證controller

  • package com.czxy.web.system;
    
    import com.czxy.domain.system.User;
    import com.czxy.service.system.UserService;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.servlet.http.HttpSession;
    
    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @GetMapping("/login")
        public ResponseEntity<String> LoginIn(User user, HttpSession httpSession) {
            try {
                // 通過shiro進行使用者登入
                SecurityUtils.getSubject().login(new UsernamePasswordToken(user.getUsername(), user.getPassword()));
                //登入成功把使用者名稱儲存到session中
                User loginUser = (User) SecurityUtils.getSubject().getPrincipal();
                httpSession.setAttribute("loginUser", loginUser);
                return  new ResponseEntity<>("登入成功", HttpStatus.OK);
            } catch (Exception e) {
                return new ResponseEntity<>("登入失敗",HttpStatus.INTERNAL_SERVER_ERROR);
            }
    
        }
        @GetMapping("/logout")
        public ResponseEntity<String> Loginout( HttpSession httpSession) {
            httpSession.removeAttribute("loginUser");
            SecurityUtils.getSubject().logout();
        return  new ResponseEntity<>(HttpStatus.OK);
        }
    
    }
    

    7 授權controller

  • package com.czxy.web.system;
    
    import com.czxy.domain.system.Menu;
    import com.czxy.domain.system.User;
    import com.czxy.domain.vo.DataGridResult;
    import com.czxy.service.system.MenuService;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.subject.Subject;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.List;
    
    @RestController
    @RequestMapping("/menu")
    public class ShowMenuController {
        @Autowired
        private MenuService menuService;
    
    
        @GetMapping
        @RequestMapping("/showMenu")
        public ResponseEntity<List<Menu>> showMent(){
          User user = (User) SecurityUtils.getSubject().getPrincipal();
           List<Menu> list= menuService.findMenuByUser(user);
           return new ResponseEntity<>(list,HttpStatus.OK);
        }
    }