Shiro权限控制

作者: 金桔文案 | 来源:发表于2018-09-03 12:21 被阅读103次

    之前写过Shiro的文章,但是当回过头来整理的时候,发现缺了好多东西,今天重新整理一下。

    我们都知道Shiro和secitity都是安全的框架,但是相对于Shiro来说,比较入门简单,所需要的功能基本上都能满足,理解起来也会比较容易。

    Shiro是一个有许多特性的全面的安全框架,下面一幅图进行介绍。

    Shiro权限控制1.png
    可以看出Shiro除了基本的认证、授权、会话管理、加密之外还有许多特性。

    Shiro架构:

    从架构来说,主要包含三个概念,Subject、SecurityManager、Realms(重要),在使用的时候我们都是围绕这三个概念来进行编码和使用


    Shiro权限控制2.png

    Shiro的应用不依赖任何的容器,可以在javaSE下使用也可以在javaEE上使用,下面是一张用户登录的例图:


    Shiro权限控制3.png
    首先理解下面的几个类:

    SecurityManager:

    Shiro的核心是ScurityManager,它是负责安全认证与授权的,Shiro本身已经实现了所有的细节,我们在使用的时候可以完全把它当做黑盒使用。

    SecurityUtils:

    本质上是一个工厂,类似Spring中的ApplicationContext,

    Subject:

    Subject是有点难理解的,有些地方理解为user,其实不然,Subject中文翻译是项目,在下面代码中会表现的很清楚

    Realm:

    在Shiro中,进行的授权和认证就是由它来操作的,我已开始对授权和认证不是很理解,也不是很明白在代码操作的时候命名在认证的时候,可以获取到授权的信息,为什么还要在进行授权的操作,下面对授权和认证做一下解释:所谓的认证,他相当于人的身份证,就是可以证明你身份的证件,在应用中,就是拿着当前登录的用户的名称与数据库中查询,看是当前登录的用户是否在数据库存在,如果存在,好,说明你是你自己。而所谓的授权,就相当于当你购买火车票的时候,如果你买的硬座,你就只能去硬座的车厢,而不能去软卧等其他车厢,这就相当于限制了你的能力,而在应用中也相当于如此,在授权的时候,会从数据库将你的权限信息获取到,交给Shiro,如果此时你要去访问指定的页面的时候,会首先对你的权限进行校验,看你是否有该权限,如果有就可以访问,没有则不可以访问。

    代码讲解:

    准备ehcache的xml配置 ,为什么要设置ehcache,是因为如果不设置,会每次刷新页面的时候都会去访问授权的方法,加上缓存之后,可以有效的制止

    
    <?xml version="1.0" encoding="UTF-8"?>
    <!--add by shanggq 2018/8/31 end-->
    <ehcache name="es">
     
        <diskStore path="java.io.tmpdir"/>
     
        <!--
           name:缓存名称。
           maxElementsInMemory:缓存最大数目
           maxElementsOnDisk:硬盘最大缓存个数。
           eternal:对象是否永久有效,一但设置了,timeout将不起作用。
           overflowToDisk:是否保存到磁盘,当系统当机时
           timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
           timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
           diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
           diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
           diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
           memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
            clearOnFlush:内存数量最大时是否清除。
             memoryStoreEvictionPolicy:
                Ehcache的三种清空策略;
                FIFO,first in first out,这个是大家最熟的,先进先出。
                LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
                LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
        -->
        <defaultCache
                maxElementsInMemory="10000"
                eternal="false"
                timeToIdleSeconds="120"
                timeToLiveSeconds="120"
                overflowToDisk="false"
                diskPersistent="false"
                diskExpiryThreadIntervalSeconds="120"
        />
     
        <!-- 登录记录缓存锁定10分钟 -->
        <cache name="passwordRetryCache"
               maxEntriesLocalHeap="2000"
               eternal="false"
               timeToIdleSeconds="3600"
               timeToLiveSeconds="0"
               overflowToDisk="false"
               statistics="true">
        </cache>
     
    </ehcache>
    <!-- add by zhangcf 2018/8/31 start -->
    

    pom.xml

    
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
     
        <groupId>com.example</groupId>
        <artifactId>springbootshiro</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>
     
        <name>springbootshiro</name>
        <description>Demo project for Spring Boot</description>
     
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.4.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
     
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>1.8</java.version>
        </properties>
     
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <!--<exclusions>-->
                    <!--<exclusion>-->
                        <!--<groupId>org.springframework.boot</groupId>-->
                        <!--<artifactId>spring-boot-starter-tomcat</artifactId>-->
                    <!--</exclusion>-->
                <!--</exclusions>-->
            </dependency>
     
     
            <!--!&#45;&#45;用于编译jsp&ndash;&gt;-->
            <!--&lt;!&ndash; https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-jasper &ndash;&gt;-->
            <!--<dependency>-->
                <!--<groupId>org.apache.tomcat.embed</groupId>-->
                <!--<artifactId>tomcat-embed-jasper</artifactId>-->
            <!--</dependency>-->
     
            <!--&lt;!&ndash;jsp页面使用jstl标签&ndash;&gt;-->
            <!--&lt;!&ndash; https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl &ndash;&gt;-->
            <!--<dependency>-->
                <!--<groupId>javax.servlet.jsp.jstl</groupId>-->
                <!--<artifactId>jstl</artifactId>-->
            <!--</dependency>-->
            <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-configuration-processor -->
            <!-- configuration-processor -->
     
            <!--用来读取配置文件-->
            <!--<dependency>-->
                <!--<groupId>org.springframework.boot</groupId>-->
                <!--<artifactId>spring-boot-configuration-processor</artifactId>-->
                <!--<optional>true</optional>-->
            <!--</dependency>-->
     
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
            <!--jpa 对象持久化,利用该jar包,通过bean直接生成数据库表-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-autoconfigure</artifactId>
            </dependency>
     
            <!-- shiro的依赖 -->
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-spring</artifactId>
                <version>1.3.2</version>
            </dependency>
     
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-ehcache</artifactId>
                <version>1.3.2</version>
            </dependency>
     
            <!--&lt;!&ndash; https://mvnrepository.com/artifact/net.sf.ehcache/ehcache &ndash;&gt;-->
            <!--<dependency>-->
            <!--<groupId>net.sf.ehcache</groupId>-->
            <!--<artifactId>ehcache</artifactId>-->
            <!--<version>2.10.5</version>-->
            <!--</dependency>-->
     
     
            <!--   DRUID是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0、DBCP、PROXOOL等DB池的优点,同时加入了日志监控,
            可以很好的监控DB池连接和SQL的执行情况,可以说是针对监控而生的DB连接池(据说是目前最好的连接池,不知道速度有没有BoneCP快)。-->
            <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.10</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
     
            <!--热部署-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <optional>true</optional>
            </dependency>
            <!--spring boot 整合 mybatis 依赖-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.0</version>
            </dependency>
     
            <!-- json支持 -->
            <dependency>
                <groupId>net.sf.json-lib</groupId>
                <artifactId>json-lib</artifactId>
                <version>2.4</version>
                <classifier>jdk15</classifier>
            </dependency>
            <!-- 包含支持UI模版(Velocity,FreeMarker,JasperReports), 邮件服务, 脚本服务(JRuby), 缓存Cache(EHCache),
                        任务计划Scheduling(uartz)。 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context-support</artifactId>
            </dependency>
            <!-- 单点登录 -->
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-cas</artifactId>
                <version>1.2.4</version>
            </dependency>
        </dependencies>
     
        <build>
            <!--表示最终的项目名,-->
            <finalName>springbootshiro</finalName>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
                <!--用于告诉maven在打包的时候不需要web.xml,否则会报到不到web.xml de错-->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>2.4</version>
                    <configuration>
                        <failOnMissingWebXml>false</failOnMissingWebXml>
                    </configuration>
                </plugin>
            </plugins>
        </build>
     
     
    </project>
    

    下面对代码的讲解,我是按照用户一开始登录,到最后的顺序来讲解,如果按照从数据操作到前端访问开始讲的话,有些地方会比较难理解

    Controller层的数据 -- 前端页面在访问的时候访问的路径

    
    package com.example.springbootshiro.Controller;
     
    import com.example.springbootshiro.service.ILoginService;
    import com.example.springbootshiro.entity.Role;
    import com.example.springbootshiro.entity.User;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.authz.annotation.RequiresPermissions;
    import org.apache.shiro.authz.annotation.RequiresRoles;
    import org.apache.shiro.subject.Subject;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
     
    import java.util.Map;
     
    /**  
      * @author shanggq
      * @date 2018/8/31
      */
    // add by shanggq 2018/8/31  start
    @RestController
    public class LoginResource {
     
    //    //    注入业务层
    //    @Autowired
    //    private ILoginService iLoginService;
    //
        @GetMapping("/login")
        public String login() {
            return "login";
        }
        
    //
        //  POST登录
        @PostMapping("/login")
        public String login(@RequestBody Map map) {
    //        添加用户认证信息
            Subject subject = SecurityUtils.getSubject();
     
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(
                    map.get("username").toString(),
                    map.get("password").toString()
            );
            subject.login(usernamePasswordToken);
            return "login";
        }
    //
        @RequestMapping("/index")
        public String index(){
            return  "index";
        }
    //
    //
        @PostMapping("/error")
        public String error(){
            return  "error";
        }
    //
    //    @RequestMapping("/addUser")
    //    public String addUser(@RequestBody Map<String,Object> map){
    //        User user = iLoginService.addUser(map);
    //        return  "addUser id ok \n"+user;
    //    }
    //
    ////    角色初始化
    //
    //    @RequestMapping("addRole")
    //    public String addRole(@RequestBody Map<String ,Object> map ){
    //        Role role = iLoginService.addRole(map);
    //        return "addRole is ok ! \n" +role;
    //    }
    //
    ////    注解的使用,表示访问该方法需要怎样的权限和角色
    //
    //
    //    @RequiresRoles("admin")
    //    @RequiresPermissions("create")
    //    @RequestMapping("/create")
    //    public  String create(){
    //        return  "Create success!";
    //    }
    }
    // add by shanggq 2018/8/31 endn
    

    上面代码显示,如果当前端按照post的格式进行数据访问login的时候,会请求到login的方法中,接收的参数是一个map,也就是说在页面中进行数据请求的时候,会将登录的用户名和密码或者其他数据进行传递,然后使用@RequetsBody将数据封装到map集合中,然后下面将数据放到了 UsernamePasswordToken(用户名密码认证机制)对象中,然后此时将该对象放到了用 SecurityUtils对象获取到的Subject对象中,SecutityUtils在上面提到过,他相当于Application,本质上是一个工厂类,然后使用该工厂获取到了Subject,在上面的构架图中我们可以看到,Application Code最终是给了Subject,然后Subject却又给了SecutityManager对象,也就是说现在可以理解为页面传递的用户的信息会存储在SecutityManager中。

    Realm的编写(最重要的。进行用户的授权和认证)

    
    package com.example.springbootshiro.shiro;
     
    import com.example.springbootshiro.mapper.UserInfoMapper;
    import com.example.springbootshiro.service.ILoginService;
    import com.example.springbootshiro.entity.Permission;
    import com.example.springbootshiro.entity.Role;
    import com.example.springbootshiro.entity.User;
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authc.SimpleAuthenticationInfo;
    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.apache.shiro.util.ByteSource;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
     
    import javax.annotation.Resource;
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
     
    /**
     * @author shanggq
     * @date 2018/8/31
     */
    // add by shanggq 2018/8/31  start
    @Component
    public class MyShiroRealm extends AuthorizingRealm {
     
        /**
         * 用於数据库的数据的访问,
         *
         * @Resource 按照名称进行数据的注入
         * @Autowired 按照类型进行数据的注入
         */
        @Autowired
        private UserInfoMapper tokentokentoken;
     
        /**
         * 权限信息(授权)
         *
         * @param principals
         * @return 如果用户正常退出,缓存会自动消除
         * 如果用户非正常退出,缓存也会自动消除
         * 如果修改了用户的权限,而用户没有退出系统,修改的权限无法立即生效--需手动实现,放在service中
         * <p>
         * 如果不做缓存,shiro会有自己的时间的间隔机制,时间为2分钟
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
            /*
             * 当没有使用缓存的时候,不断的刷新页面的话,这个代码会不断的执行,其实没有
             * 必要每次都要重新设置权限的信息,所以需要在放到缓存中进行管理,当放到环迅中这样的haunted
             * doGetAuthorizationInfo就会只执行一次,缓存在过期之后再次
             * */
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            User user = (User) principals.getPrimaryPrincipal();
     
            List<Role> list = new ArrayList<>();
            list = tokentokentoken.findRoleListByName(user.getUid());
     
            user.setRoles(list);
     
    //        设置角色,权限,
    //        info.addRole("admin");
    //        info.addStringPermission("query");
     
    //            从数据库中设置角色和权限,分别设置到 SimpleAuthorizationInfo 中返回
     
            for (Role role : user.getRoles()) {
                info.addRole(role.getRolename());
                for (Permission permission : role.getPermissions()) {
                    info.addStringPermission(permission.getPermission());
                }
            }
            return info;
        }
     
        /**
         * 身份认证
         *
         * @param token
         * @return
         * @throws AuthenticationException
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
     
     
    //        获取用户的输入的账号
            String userName = (String) token.getPrincipal();
     
            User user = tokentokentoken.findByUserName(userName);
     
            if (user == null) {
                return null;
            }
    //        加密方式,获取密码在存入的时候,加密的盐
    //       明文。若存在,将此用户存放到登录认证info中,不需要我们自己进行密码的比较,shiro会自动给我们进行比较
            return new SimpleAuthenticationInfo(userName, user.getPassword(), ByteSource.Util.bytes(user.getSalt()), getName());
     
        }
    }
    // add by shanggq 2018/8/31 end
    

    Realm中分为身份认证和授权两个方法,一开始我对这两个方法不理解,因为我的思路是你身份认证完成之后说明你可以进行登录,这样不就完成控制了么,为什么还需要权限认证,当我在继续往下面看的时候,发现并不是这样的。数据全部的操作全部交给SecurityManager对象去操作。

    下面配置核心对象 SecurityManager。在这里我们使用的是spring boot 搭建的工程,所以这里也使用java配置,来完成对象注入到spring容器中。

    
    package com.example.springbootshiro.shiro;
     
    import org.apache.shiro.cache.ehcache.EhCacheManager;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
     
    import java.util.HashMap;
    import java.util.LinkedHashMap;
     
    /**
     * 进行相应的bena的初始化
     *
     * @author shanggq
     * @date 2018/8/31
     */
    // add by shanggq 2018/8/31  start
    @Configuration
    public class ShiroConfiguration {
        //将自己的验证方式加入容器,因为自己的的容器配置了授权和认证的方法
        @Bean
        public MyShiroRealm myShiroRealm() {
            MyShiroRealm myShiroRealm = new MyShiroRealm();
            return myShiroRealm;
        }
     
        /*
        shiro缓存管理器
        * 需要注入其他的实体类中
        * 1,安全管理器。secuityManager  最核心的管理器,但是配置完成之后基本上不会进行操作
        * */
        @Bean
        public EhCacheManager ehCacheManager() {
            System.out.println("ShiroConfiguration.getEhCacheManager()");
            EhCacheManager cacheManager = new EhCacheManager();
    //        指定配置shiro的文件
            cacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
            return cacheManager;
        }
     
        //   权限管理,配置主要是Realm的管理认证
        @Bean(name = "securityManager")
        public SecurityManager securityManager() {
            DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
    //        设置realm
            manager.setRealm(myShiroRealm());
    //        注入缓存
            manager.setCacheManager(ehCacheManager());
            return manager;
        }
        //    Filter  工厂,设置对应的过滤条件和跳转条件
        @Bean
        public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    //        必须要设置的  SecurityManager
            shiroFilterFactoryBean.setSecurityManager(securityManager);
    //        设置的拦截器
    //        HashMap<String, String> hashMap = new HashMap<>();
            LinkedHashMap<String, String> hashMap = new LinkedHashMap<>();
     
            //  配置退出的过滤器,其中的具体的退出代码shiro已经替我们实现了
            hashMap.put("/logout", "logout");
    //        登录页面需要的权限
            hashMap.put("/login", "anon");
     
            //对所有的用户进行认证 当所有的认证都通过的时候才可以访问路径,
            hashMap.put("/**", "authc");
            //登录页
            shiroFilterFactoryBean.setLoginUrl("/login");
            //登录成功之后跳转到首页
            shiroFilterFactoryBean.setSuccessUrl("/index");
            //错误页面。认证不通过的时候跳转
            shiroFilterFactoryBean.setUnauthorizedUrl("/error");
            shiroFilterFactoryBean.setFilterChainDefinitionMap(hashMap);
            return shiroFilterFactoryBean;
        }
     
        //    加入注解的使用,不加入这个注解不生效
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
            advisor.setSecurityManager(securityManager);
            return advisor;
        }
    }
    // add by shanggq 2018/8/31 end
    

    首先创建你继承了 AuthorizingRealm的 对象类,将该对象创建出来使用@Bean放到spring的容器中,然后再创建 EhCacheManager 对象,为什么要创建该对象的呢,我们在权限控制的代码中已经加了说明,是因为现权限在开发中一般很少去发生改变,如果我们每次在刷新页面的时候都要去数据库中获取数据,判断当前用户有没有当前的权限,会加大数据库的访问,所以我们可以将数据放在缓存中,这样在每次刷新页面的时候,不会都去访问该授权的代码,而首先是去缓存中查询数据,当缓存过期之后,才会去访问授权部分的代码。

    然后在创建核心的对象SecutityManager对象,将继承身份认证的对象和缓存的对象都放到SecutityManager对象中,然后返回。然后创建下面的 ShiroFilterFactoryBean 对象,该对象在使用传统的配置文件的时候,也需要配置该类,目的是为了进行数据的拦截。将拦截的数据传递给上面创建的对象,然后完成身份和权限的校验,不知道在这里读者有没有在脑海中出现一条思路,也就是说,用户在将数据提交的时候,Subject会接收到数据,然后将数据会传递给SecutityManager对象,这里又有疑问了,数据是怎么传递给SecutityManager对象的呢,所以我就去查看源码,结果找到了下面的代码


    控制4.png

    也就是说,subject会将前端接收到的数据给SecutityManager,然而Realm返回的数据和 EhCacheManager缓存对象添加到SecutityManager对象中,但是该对象需要被谁给触发呢,所以就到了最后面的拦截器,ShiroFilterFactoryBean,那我们是不是可以理解为,当有请求过来的时候,会触发拦截器,而拦截器回去调用SecutityManager对象,而SecutityManager对象再去分别调用Realm和EhcacheManager对象,分别获取数据,此时用户的身份,权限都已经获取到,就到了下面的权限的设置,我们将全部的权限信息放到了 LinkedHashMap 集合中,而且还可以使用 ShiroFilterFactoryBean 对象设置登录、失败、首页所需要跳转的页面,然后将集合放到 ShiroFilterFactoryBean 对象中。下面对权限的信息进行说明(常用的五种)

      Anon:表示可以不用登录直接访问
    
      Authc:表示需要登录之后才可以访问
    
      Perms:表示权限
    
      Roles:表示角色
    
      User:表示用户
    
    AuthorizationAttributeSourceAdvisor对象表示的是开启对方法上的注解的扫描,因为有些方法是在当具有一定的权限的时候才可以访问的,如果不初始化该类的实例,方法上的注解是不起作用的,原因如下
    

    是因为,代理的 方式,应该都知道,java的代理方式,一种是传统的代理方式,当有接口的时候才会使用,一种是cglib代理的方式,传统的代理方式是针对接口而言的,由于此时接口上是没有shiro的注解的,所以此时的注解是不起作用的,所以需要对上面的对象进行实例化,当然也可以改用cglib代理的方式,选择代理的方式是如果有接口就是用传统的代理方式,如果没有接口则使用cglib代理的方式。

    文章来源:https://blog.csdn.net/weixin_38297879/article/details/82258119
    推荐阅读:https://www.roncoo.com/course/list.html?courseName=Shiro

    相关文章

      网友评论

        本文标题:Shiro权限控制

        本文链接:https://www.haomeiwen.com/subject/mdubwftx.html