shiro(5)权限控制案例

权限控制

自定义Shiro Filter过滤器

  • 背景知识:

    • /admin/order= roles["admin, root"] ,表示 /admin/order 这个接口需要用户同时具备 admin 与 root 角色才可访问, 相当于hasAllRoles() 这个判断方法
  • 我们的需求:

    • 订单信息,可以由角色 普通管理员 admin 或者 超级管理员 root 查看

    • 只要用户具备其中一个角色即可(shiro不能满足该条件)

// mappedValue -》roles[admin,root]
public class CustomRolesOrAuthorizationFilter extends AuthorizationFilter {  

  @Override  
  protected boolean isAccessAllowed(ServletRequest req, ServletResponse resp, Object mappedValue) throws Exception {  

      Subject subject = getSubject(req, resp);

      //获取当前访问路径所需要的角色集合  
      String[] rolesArray = (String[]) mappedValue;  

        //没有角色限制,有权限访问  
      if (rolesArray == null || rolesArray.length == 0) { 
          return true;  
      }  

      //当前subject是rolesArray中的任何一个,则有权限访问  
      for (int i = 0; i < rolesArray.length; i++) {  
          if (subject.hasRole(rolesArray[i])) { 
              return true;  
          }  
      }  

      return false;  
  }  
}

FactoryBean配置

Map<String, Filter> filtersMap = new LinkedHashMap<>();
filtersMap.put("roleOrFilter",new CustomRolesOrAuthorizationFilter());
filterChainDefinitionMap.put("/admin/**","roleOrFilter[admin,root]");
shiroFilterFactoryBean.setFilters(filtersMap);

自定义Shiro Filter过滤器验证

  • 配置不同的角色,验证自定义过滤器是否有效

    登录(post)
    localhost:8080/pub/login
    
    管理员查看后台信息(get)
    localhost:8080/admin/video/order
    

 

 

存在问题:每次权限校验都会查询DB

 

 

性能提升之Redis整合CacheManager

  • 使用原因?

    • 授权的时候每次都去查询数据库,对于频繁访问的接口,性能和响应速度比较慢,所以使用缓存

1、业务方法中加缓存

2、本实例的方法

  • 步骤

    • 加依赖
    <!-- shiro+redis缓存插件 -->
       <dependency>
            <groupId>org.crazycake</groupId>
            <artifactId>shiro-redis</artifactId>
            <version>3.1.0</version>
        </dependency>
    
    
    • 配置bean
        //使用自定义的cacheManager
       securityManager.setCacheManager(cacheManager());
    
        /**
         * 配置redisManager
         *
         */
        public RedisManager getRedisManager(){
            RedisManager redisManager = new RedisManager();
            redisManager.setHost("localhost");
            redisManager.setPort(6379);
            return redisManager;
        }
    
        /**
         * 配置具体cache实现类
         * @return
         */
        public RedisCacheManager cacheManager(){
            RedisCacheManager redisCacheManager = new RedisCacheManager();
            redisCacheManager.setRedisManager(getRedisManager());
             //设置过期时间,单位是秒,20s,
            redisCacheManager.setExpire(20);
    
            return redisCacheManager;
        }
    
    
    • 安装redis (如何不会使用redis,则参考网上的博客文章)

    • 建议本地安装,默认是不能外网访问的,然后不是守护进程方式

    • https://www.cnblogs.com/it-cen/p/4295984.html

    • 原有的问题

    • redis缓存key  要知名redis的唯一标示key

    class java.lang.String must has getter for field: authCacheKey or id\nWe need a field to identify this Cache Object in Redis. So you need to defined an id field which you can get unique id to identify this principal. For example, if you use UserInfo as Principal class, the id field maybe userId, userName, email, etc. For example, getUserId(), getUserName(), getEmail(), etc.\nDefault value is authCacheKey or id, that means your principal object has a method called \"getAuthCacheKey()\" or \"getId()\""
    
    • 改造原有的逻辑,修改缓存的唯一key

    • doGetAuthorizationInfo 方法
      原有:
      String username = (String)principals.getPrimaryPrincipal();
      User user = userService.findAllUserInfoByUsername(username);
      
      改为
      
      User newUser = (User)principals.getPrimaryPrincipal();
        User user = userService.findAllUserInfoByUsername(newUser.getUsername());
      
      doGetAuthenticationInfo方法
      原有:
      return new SimpleAuthenticationInfo(username, user.getPassword(), this.getClass().getName());
      
      改为
      return new SimpleAuthenticationInfo(user, user.getPassword(), this.getClass().getName());
      

修改redis缓存中key的过期时间

 public RedisCacheManager redisCacheManager(){

        RedisCacheManager redisCacheManager=new RedisCacheManager();
        redisCacheManager.setRedisManager(getRedisManager());
        //设置过期时间 单位秒
        redisCacheManager.setExpire(30);
        return redisCacheManager;
    }

 

Redis整合SessionManager,管理Session会话

  • 为啥session也要持久化?

    • 重启应用,用户无感知,可以继续以原先的状态继续访问(通过sessionId的有无来判断是否登录过(服务端内存中存储))

session不能那样,权限校验的时候能在redis中存储,但是session要持久化

重启之后内存中但数据丢失(session要持久化 持久化到redis/mysql)

定时任务实现sessionId的保活

 

  • 怎么持久化?

    
     //配置session持久化
     customSessionManager.setSessionDAO(redisSessionDAO());
    
    /**
       * 自定义session持久化
       * @return
       */
      public RedisSessionDAO redisSessionDAO(){
          RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
          redisSessionDAO.setRedisManager(getRedisManager());
          return redisSessionDAO;
      }
    
    

    注意点:

    • DO对象需要实现序列化接口 Serializable  domain

    • logout接口和以前一样调用,请求logout后会删除redis里面的对应的key,即删除对应的token

​ 

ShiroConfig常用bean 介绍

  • LifecycleBeanPostProcessor

    • 作用:管理shiro一些bean的生命周期 即bean初始化 与销毁
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }
    
  • AuthorizationAttributeSourceAdvisor

    • 作用:加入注解的使用,不加入这个AOP注解不生效(shiro的注解 例如 @RequiresGuest)类似于@RequeststParam
    @Bean
     public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
      AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
            authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
            return authorizationAttributeSourceAdvisor;
    }
    
  */
    @PostMapping("/login")
    @RequiresGuest
    public  JsonData login(@RequestBody UserQuery userQuery, HttpServletRequest request, HttpServletResponse response){
        Subject subject=SecurityUtils.getSubject();
        Map<String,Object> info=new HashMap<>();
  • DefaultAdvisorAutoProxyCreator

    • 作用: 用来扫描上下文寻找所有的Advistor(通知器), 将符合条件的Advisor应用到切入点的Bean中,需要在LifecycleBeanPostProcessor创建后才可以创建
    •  
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public  DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
            DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
            defaultAdvisorAutoProxyCreator.setUsePrefix(true);
            return defaultAdvisorAutoProxyCreator;
    }

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智达教育‍

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值