• springboot+shiro登录校验及权限验证


    shiro所需要的包
    <dependency> 
              <groupId>org.apache.shiro</groupId> 
              <artifactId>shiro-cas</artifactId> 
              <version>1.2.4</version> 
            </dependency> 
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-spring</artifactId>
                <version>1.4.0</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-ehcache -->
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-ehcache</artifactId>
                <version>1.4.0</version>
            </dependency>
    public class AuthRealm extends AuthorizingRealm {
        
        @Autowired
        private ISysAdminService adminService;
        
        @Autowired
        private ISysAdminRoleService adminRoleService;
        
        @Autowired
        private ISysRolePermService rolePermService;
        
        //认证.登录
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            System.out.println("-----------------认证.登录-------------------");
            UsernamePasswordToken utoken = (UsernamePasswordToken) token;//获取用户输入的token
            String username = utoken.getUsername();
            //处理session
            SessionsSecurityManager securityManager = (SessionsSecurityManager) SecurityUtils.getSecurityManager();
            DefaultSessionManager sessionManager = (DefaultSessionManager) securityManager.getSessionManager();
          //获取当前已登录的用户session列表
            Collection<Session> sessions = sessionManager.getSessionDAO().getActiveSessions();
            for (Session session : sessions) {
                //清除该用户以前登录时保存的session
    //            IotdUserEntity en=(IotdUserEntity)(session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY));
    //            String phone=en.getPhone();
                //如果和当前session是同一个session,则不剔除
                if (SecurityUtils.getSubject().getSession().getId().equals(session.getId()))
                    break;
                
                SysAdmin admin = (SysAdmin) (session.getAttribute("sysAdmin"));
                if (admin != null) {
                    String adminName = admin.getLoginName();
                    if (username.equals(adminName)) {
                        System.out.println(username + "已登录,剔除中...........");
                        sessionManager.getSessionDAO().delete(session);
                    }
                }
            }
            //获取用户信息
            SysAdmin sysAdmin = adminService.getByLoginName(username);
            if(sysAdmin == null) {
                throw new UnknownAccountException();
            }
            if(sysAdmin.getIsLock() == 1) {//被锁定
                throw new LockedAccountException();
            }
            if(sysAdmin.getIsEnable() == 1) {//该账号未被启用
                throw new DisabledAccountException();
            }
            //放入shiro.调用CredentialsMatcher检验密码
            SimpleAuthenticationInfo rst = new SimpleAuthenticationInfo(sysAdmin, sysAdmin.getPassword(), this.getClass().getName());
            return rst;
        }
    
        //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            SysAdmin admin = (SysAdmin) principal.fromRealm(this.getClass().getName()).iterator().next();//获取session中的用户
            //获取该用户的所有角色
            List<Integer> listId = adminRoleService.getRoleIdByAdminId(admin.getSysAdminId());
            //查询该用户的权限
            List<String> list = rolePermService.getAuthCodeListByRoles(listId);
            info.addStringPermissions(list);
            return info;
        }
    
    
    }
    /**
     * shiro配置类
     * @author Administrator
     *
     */
    
    @Configuration
    public class ShiroConfiguration {
        
        /**
         * 创建ShiroFilterFactoryBean
         */
        @Bean(name="shiroFilter")
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            
            /**
             * shiro常用拦截器
             *     anon: 无需认证就可访问
             *     authc: 需要认证才能访问
             *  user :使用rememberMe的功能可直接访问
             *  perms: 必须有资源的权限才可以访问
             *     role : 该资源必须得到角色的权限才可以访问
             */
            //设置安全管理器
            shiroFilterFactoryBean.setSecurityManager(securityManager);
            
            return shiroFilterFactoryBean;
        }
        
    
    
        //配置核心安全事务管理器
        @Bean(name="securityManager")
        public DefaultWebSecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm) {
            System.err.println("--------------shiro已经加载----------------");
            DefaultWebSecurityManager manager=new DefaultWebSecurityManager();
            manager.setRealm(authRealm);
            manager.setSessionManager(sessionManager());
            // <!-- 用户授权/认证信息Cache, 采用EhCache 缓存 -->
            manager.setCacheManager(ehCacheManager());
            //注入记住我管理器;
            manager.setRememberMeManager(rememberMeManager());
            return manager;
        }
    
        @Bean(name = "sessionManager")
        public DefaultWebSessionManager sessionManager() {
            DefaultWebSessionManager sessionManager=new DefaultWebSessionManager();
            return sessionManager;
        }
        
        //配置自定义的权限登录器
        @Bean(name="authRealm")
        public AuthRealm authRealm(@Qualifier("credentialsMatcher") CredentialsMatcher matcher) {
            AuthRealm authRealm=new AuthRealm();
            authRealm.setCredentialsMatcher(matcher);
            return authRealm;
        }
        
        //配置自定义的密码比较器
        @Bean(name="credentialsMatcher")
        public CredentialsMatcher credentialsMatcher() {
            return new CredentialsMatcher(ehCacheManager());
        }
        
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager manager) {
            AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor();
            advisor.setSecurityManager(manager);
            return advisor;
        }
    
        //----------------------------------------------- 
        /**
         * LifecycleBeanPostProcessor,这是个DestructionAwareBeanPostProcessor的子类,
         * 负责org.apache.shiro.util.Initializable类型bean的生命周期的,初始化和销毁。
         * 主要是AuthorizingRealm类的子类,以及EhCacheManager类。
         *
         * @return
         */
        @Bean(name = "lifecycleBeanPostProcessor")
        public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
            return new LifecycleBeanPostProcessor();
        }
    
        /**
         * ShiroRealm,这是个自定义的认证类,继承自AuthorizingRealm, 负责用户的认证和权限的处理
         *
         * @return
         */
        @Bean(name = "myShiroRealm")
        @DependsOn("lifecycleBeanPostProcessor")
        public AuthRealm myShiroRealm() {
            AuthRealm myShiroRealm = new AuthRealm();
            return myShiroRealm;
        }
    
        /**
         * EhCacheManager,缓存管理,用户登陆成功后,把用户信息和权限信息缓存起来,
         * 然后每次用户请求时,放入用户的session中,如果不设置这个bean,每个请求都会查询一次数据库。
         *
         * @return
         */
        @Bean(name = "ehCacheManager")
        @DependsOn("lifecycleBeanPostProcessor")
        public EhCacheManager ehCacheManager() {
            EhCacheManager cacheManager = new EhCacheManager();
            cacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
            return cacheManager;
        }
    
        /**
         * 自定义shiroSession的cookie,如果不设置默认JSESSIONID,
         * 会与tomcat等默认cookie名重复,sessionIdCookie用于保存sessionId标识
         *
         * @return
         */
        @Bean(name = "rememberMeCookie")
        public SimpleCookie rememberMeCookie() {
            // 这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
            SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
            // setcookie的httponly属性如果设为true的话,会增加对xss防护的安全系数。它有以下特点:
            // 设为true后,只能通过http访问,javascript无法访问
            // 防止xss读取cookie
            simpleCookie.setHttpOnly(true);
            // <!-- 记住我cookie生效时间30天 ,单位秒;-->
            simpleCookie.setMaxAge(259200);
            return simpleCookie;
        }
    
        /**
         * cookie管理对象;
         * 记住我的配置
         * @return
         */
        @Bean(name = "rememberMeManager")
        public CookieRememberMeManager rememberMeManager() {
            CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
            cookieRememberMeManager.setCookie(rememberMeCookie());
            return cookieRememberMeManager;
        }
    
        /**
         * DefaultAdvisorAutoProxyCreator,Spring的一个bean,由Advisor决定对哪些类的方法进行AOP代理。
         *
         * @return
         */
        @Bean
        @DependsOn("lifecycleBeanPostProcessor")
        public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
            DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
            daap.setProxyTargetClass(true);
            return daap;
        }
    
        /**
         * thymeleaf模板使用shiro注解
         * @return
         */
        @Bean
        public ShiroDialect getShiroDialect(){
            return new ShiroDialect();
        }
        
    }
    /**
     * 自定义密码比较
     * @author Administrator
     * 
     *
     */
    public class CredentialsMatcher extends SimpleCredentialsMatcher {
        
         @Autowired
         private ISysAdminService adminService;
        
         private Cache<String, AtomicInteger> passwordRetryCache;
         
         public CredentialsMatcher(CacheManager cacheManager) {
             passwordRetryCache = cacheManager.getCache("passwordRetryCache");
        }
        
        @Override
        public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
            
            // 获取登录用户的用户名
            String username = (String)token.getPrincipal();
            // 获取用户登录次数
            AtomicInteger retryCount = passwordRetryCache.get(username);
            if (retryCount == null) {
                // 如果用户没有登陆过,登陆次数加1 并放入缓存
                retryCount = new AtomicInteger(0);
                passwordRetryCache.put(username, retryCount);
            }
            if (retryCount.incrementAndGet() > 3) {
                // 如果用户登陆失败次数大于3次 抛出锁定用户异常  并修改数据库字段
                SysAdmin admin = adminService.getByLoginName(username);
                if (admin != null && admin.getIsLock() == 0){
                    // 数据库字段 默认为 0  就是未锁定状态 所以 要改为1
                    // 修改数据库的状态字段为锁定
                    admin.setIsLock((byte) 1);
                    adminService.updateById(admin);
                }
                // 抛出用户锁定异常
                throw new LockedAccountException();
            }
            // 判断用户账号和密码是否正确
            boolean matches = super.doCredentialsMatch(token, info);
            if (matches) {
                // 如果正确,从缓存中将用户登录计数 清除
                passwordRetryCache.remove(username);
            }
            return matches;
        }
        
        /**
         * 根据用户名 解锁用户
         * @param username
         * @return
         */
        public void unlockAccount(String username){
            passwordRetryCache.remove(username);
        }
    }
    /**
         * 生成验证码
         */
        @RequestMapping(value = "/getVerify")
        public void getVerify(HttpServletRequest request, HttpServletResponse response) {
            try {
                response.setContentType("image/jpeg");// 设置相应类型,告诉浏览器输出的内容为图片
                response.setHeader("Pragma", "No-cache");// 设置响应头信息,告诉浏览器不要缓存此内容
                response.setHeader("Cache-Control", "no-cache");
                response.setDateHeader("Expire", 0);
                RandomValidateCodeUtil randomValidateCode = new RandomValidateCodeUtil();
                randomValidateCode.getRandcode(request, response);// 输出验证码图片方法
            } catch (Exception e) {
                result(HTTP_VALID,"获取验证码失败",ICON_ERROR);
            }
        }
        
        /**
         * 登录校验
         * @param admin
         * @return
         * @throws Exception 
         */
        @RequestMapping(value="/checkLogin" ,method=RequestMethod.POST)
        @ResponseBody
    //    @OperLog(operModul="登录",operType="checkLogin",operDesc="验证用户名密码")
        public AjaxResult checkLogin(HttpSession session ,SysAdmin admin,String captcha){
            try {
    //            String random = (String) session.getAttribute("RANDOMVALIDATECODEKEY");
    //            if(captcha.equals("") || !random.equals(captcha)) {
    //                return result(HTTP_VALID,"验证码错误",ICON_EXIST);
    //            }
                /**
                 * shiro 认证操作
                 */
                //1.获取Subject对象
                Subject subject = SecurityUtils.getSubject();
                //2.封装用户数量
                
                UsernamePasswordToken token = new UsernamePasswordToken(admin.getLoginName(), DesAesUtil.encryptDES(admin.getPassword()));
                //3.执行登录方法
            
                subject.login(token);
                SysAdmin loginAdmin = (SysAdmin)SecurityUtils.getSubject().getPrincipal();
                session.setAttribute("sysAdmin", loginAdmin);
                JSONObject json = new JSONObject();
                json.put("url", "/Bmc/sys-menu/menu");
                return result(HTTP_SUCCESS , MSG_SUCCESS , ICON_SUCCESS , json);
            }catch (UnknownAccountException e) {
                return result(HTTP_VALID , "用户名不存在" , ICON_EXIST);
            }catch(IncorrectCredentialsException e) {
                return result(HTTP_VALID , "密码不正确" , ICON_EXIST);
            }catch(NullPointerException e) {
                return result(HTTP_VALID , "验证码过期" , ICON_EXIST);
            }catch(LockedAccountException e) {
                return result(HTTP_VALID , "该账号由于登录次数过多已被锁定" , ICON_EXIST);
            }catch(DisabledAccountException e) {
                return result(HTTP_VALID , "该账号未被启用" , ICON_EXIST);
            }catch(Exception e) {
                return result(HTTP_VALID , "该账号存在异常" , ICON_EXIST);
            } 
        }
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
             updateCheck="false">
        <defaultCache
                eternal="false"
                maxElementsInMemory="1000"
                overflowToDisk="false"
                diskPersistent="false"
                timeToIdleSeconds="0"
                timeToLiveSeconds="600"
                memoryStoreEvictionPolicy="LRU" />
                
     
    
        <!-- 登录失败次数缓存
            注意 timeToLiveSeconds 设置为300秒 也就是5分钟
             可以根据自己的需求更改
         -->
        <cache name="passwordRetryCache"
               maxEntriesLocalHeap="2000"
               eternal="false"
               timeToIdleSeconds="0"
               timeToLiveSeconds="300"
               overflowToDisk="false"
               statistics="true">
        </cache>
    </ehcache>
  • 相关阅读:
    用U3D寻找看电视的感觉!!
    MipMap
    什么是 A 轮融资?有 B轮 C轮么?
    Java写的斗地主游戏源码
    sqlserver sp_spaceused用法
    SQL中的全局变量和局部变量(@@/@)
    SQL2008数据库导出到SQL2000全部步骤过程
    生成Insert语句的存储过程
    物理机连接虚拟机数据库
    配置sql server 2000以允许远程访问
  • 原文地址:https://www.cnblogs.com/ch94/p/16385465.html
Copyright © 2020-2023  润新知