• 【狂神说:笔记】安全框架:shiro(入门)


    目录

    shiro

    1、简介

    1.1、什么是shiro

    • Apache Shiro 是 Java 的一个安全(权限)框架
    • Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在 JavaSE 环境,也可以用在 JavaEE 环境

    1.2、功能

    在这里插入图片描述

    • Authentication :认证、验证
    • Authorization :授权
    • Session Management :会话管理
    • Crytography :加密机制

    1.3、shiro架构

    在这里插入图片描述

    Subject

    • 应用代码直接交互的对象是Subject,也就是说Shiro的对外API 核心就是Subject
    • Subject 代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等
    • Subject 其实是一个门面,SecurityManager才是实际的执行者
    • 与Subject 的所有交互都会委托给SecurityManager

    SecurityManager

    • 安全管理器
    • 所有与安全有关的操作都会与SecurityManager交互,且其管理着所有Subject
    • 它是Shiro的核心,它负责与Shiro的其他组件进行交互,它相当于SpringMVC中DispatcherServlet的角色

    Realm

    • Shiro从Realm 获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm 获取相应的用户进行比较以确定用户身份是否合法
    • 也需要从Realm 得到用户相应的角色/权限进行验证用户是否能进行操作,可以把Realm 看成DataSource

    总结:

    • 应用代码通过Subject来进行认证和授权,而Subject又委托给SecurityManager
    • 我们需要给Shiro的SecurityManager注入Realm,从而让SecurityManager能得到合法的用户及其权限进行判断

    2、案例分析

    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.*;
    import org.apache.shiro.config.IniSecurityManagerFactory;
    import org.apache.shiro.mgt.SecurityManager;
    import org.apache.shiro.session.Session;
    import org.apache.shiro.subject.Subject;
    import org.apache.shiro.util.Factory;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class Quickstart {
    
      private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);
    
      public static void main(String[] args) {
        // 工厂模式,通过shiro.ini 配置文件中的信息,生成一个工厂实例
        Factory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);
    
        // 通过SecurityUtils 获取当前执行的用户Subject:
        Subject currentUser = SecurityUtils.getSubject();
    
        //通过当前用户拿到Shiro的Session 可以脱离web存值取值
        Session session = currentUser.getSession();
        // 使用session存值取值
        session.setAttribute("someKey", "aValue");
        String value = (String) session.getAttribute("someKey");
        if (value.equals("aValue")) {
          log.info("Retrieved the correct value! [" + value + "]");
        }
    
        // 让我们登录当前用户,以便我们可以检查角色和权限:
        // 这里和SpringSecurity 使用了类似的代码,判断用户是否被认证
        if (!currentUser.isAuthenticated()) {
          //如果被认证,就可以获得一个令牌(token )
          //通过用户的账号密码生成一个令牌
          UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
          //设置记住我功能
          token.setRememberMe(true);
          try {
            //执行登录操作
            currentUser.login(token);
          } catch (UnknownAccountException uae) {
            //如果用户名不存在
            log.info("There is no user with username of " + token.getPrincipal());
          } catch (IncorrectCredentialsException ice) {
            // 如果密码不正确
            log.info("Password for account " + token.getPrincipal() + " was incorrect!");
          } catch (LockedAccountException lae) {
            //用户被锁定,如密码输出过多,则被锁住
            log.info("The account for username " + token.getPrincipal() + " is locked.  " +"Please contact your administrator to unlock it.");
          }
          // ... 在此处捕获更多异常
          catch (AuthenticationException ae) {
            //意外情况?错误?
          }
        }
    
        //currentUser些用法
        //打印其标识主体(在这种情况下,为用户名) :
        log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
    
        // 检查角色是否存在
        if (currentUser.hasRole("schwartz")) {
          log.info("May the Schwartz be with you!");
        } else {
          log.info("Hello, mere mortal.");
        }
    
        //粗粒度
        if (currentUser.isPermitted("lightsaber:wield")) {
          log.info("You may use a lightsaber ring.  Use it wisely.");
        } else {
          log.info("Sorry, lightsaber rings are for schwartz masters only.");
        }
    
        //细粒度
        if (currentUser.isPermitted("winnebago:drive:eagle5")) {
          log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'." +"Here are the keys - have fun!");
        } else {
          log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
        }
    
        //注销
        currentUser.logout();
    
        //结束
        System.exit(0);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91

    主要流程:

    //获取当前对象
    Subject currentUser = SecurityUtils.getSubject();
    //根据当前对象获取对应的Session
    Session session = currentUser.getSession();
    //判断用户是否被认证,根据用户名和密码生成令牌
    UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
    //设置记住我功能
    token.setRememberMe(true);
    //拿到令牌进行登录
    currentUser.login(token);
    //打印其标识主体
    currentUser.getPrincipal()
    //注销
    currentUser.logout();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3、动手实践

    3.1、自定义Realm配置类

    package com.mtf.config;
    
    import org.apache.shiro.authc.AuthenticationException;
    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    
    public class Realm extends AuthorizingRealm {
      @Override
      protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了授权方法!");
    
    
        return null;
      }
    
      @Override
      protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了认证方法!");
    
    
        return null;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 继承AuthorizingRealm 重写里面的“认证”和“授权”方法

    3.2、自定义shiro配置类

    package com.mtf.config;
    
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class ShiroConfig {
        @Bean(name = "shiroFilterFactoryBean")
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
            return shiroFilterFactoryBean;
        }
    
        @Bean(name = "defaultWebSecurityManager")
        public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRemal") UserRealm userRealm){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            securityManager.setRealm(userRealm);
            return securityManager;
        }
    
        @Bean(name = "userRealm")
        public UserRealm getUserRealm(){
            return new UserRealm();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 执行顺序:UserRealm-》DefaultWebSecurityManager-》ShiroFilterFactoryBean

    3.3、认证和授权

    请求拦截

    //在配置类中添加shiro内置过滤器
    //添加shiro内置过滤器
    Map filterMap = new LinkedHashMap<>();
    /*
                anon : 无需认证,就可以访问
                authc : 必须认证,才能访问
                user : 必须拥有 “记住我”功能才能用
                perms : 拥有对某个资源的权限才能访问
                role : 拥有某个角色权限才能访问
            */
    filterMap.put("/functions/*","authc");
    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
    
    //设置拦截后要跳转的页面,一般是登录页面
    shiroFilterFactoryBean.setLoginUrl("/toLogin");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    用户认证(与数据库交互判断登录的用户名账号密码是否正确)

    //Controller
    //用户认证
    @RequestMapping("/login")
    public String Login(String username, String password, Model model){
      //获取当前对象
      Subject subject = SecurityUtils.getSubject();
    
      UsernamePasswordToken token = new UsernamePasswordToken(username,password);
      token.setRememberMe(true);
    
      try {
        if (!subject.isAuthenticated()){
          subject.login(token);
          return "index";
        }
      } catch (UnknownAccountException e) {
        model.addAttribute("msg","用户名错误!");
        return "login";
      }catch (IncorrectCredentialsException e){
        model.addAttribute("msg","密码错误!");
        return "login";
      }
      return "index";
    }
    
    
    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
      System.out.println("执行了认证方法!");
    
      UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
      User user = userService.queryByName(token.getUsername());
      if (user==null){
        return null;
      }
    
      return new SimpleAuthenticationInfo("",user.getPassword(),"");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    用户授权

    //权限设置
    filterMap.put("/functions/*","perms[functions:*]");
    
    
    //通过关键字段来判断用户权限
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
      System.out.println("执行了授权方法!");
      SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    
      Subject subject = SecurityUtils.getSubject();
      User user = (User) subject.getPrincipal();
      info.addStringPermission(user.getPerms());
      return info;
    }
    
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
      System.out.println("执行了认证方法!");
    
      UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
      User user = userService.queryByName(token.getUsername());
      if (user==null){
        return null;
      }
    
      return new SimpleAuthenticationInfo(user,user.getPassword(),"");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    shiro和thymeleaf整合

    // 整合ShiroDialect:用来整合shiro-thymeleaf
    @Bean
    public ShiroDialect getShiroDialect(){
      return new ShiroDialect();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    如何读LVS报告
    ASP.NET Core Web API Action方法参数
    分享几种稳定靠谱的副业,从而增加你的额外收入
    EF Core学习笔记:额外的外键属性 / 单项导航属性
    《30天吃掉那只 TensorFlow2.0》 2-3 自动微分机制
    【Leetcode】664. Strange Printer(配数学证明)
    (Transfer Learning)迁移学习在IMDB上训练情感分析模型
    [附源码]java毕业设计某互联网公司人力资源管理系统
    阿里云国际站:阿里云Linux系统磁盘扩容操作实例
    【机器学习基础】多元线性回归(适合初学者的保姆级文章)
  • 原文地址:https://blog.csdn.net/hjseo_seg/article/details/126616228