shiro整合springboot

Shiro

1.什么是

  • 安全权限框架
  • 功能:授权,认证

2.quickstart

public class Tutorial {
    private static final transient Logger log = LoggerFactory.getLogger(Tutorial.class);

    public static void main(String[] args) {
        log.info("My First Apache Shiro Application");
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);
        // get the currently executing user:
        //获取当前的用户对象:subject,调用SecurityUtils.getSubject();
        Subject currentUser = SecurityUtils.getSubject();

        // Do some stuff with a Session (no need for a web or EJB container!!!)
        //测试使用session
        //获取session currentUser.getSession();
        Session session = currentUser.getSession();
        session.setAttribute("someKey", "aValue");
        String value = (String) session.getAttribute("someKey");
        if (value.equals("aValue")) {
            log.info(" --- >Retrieved the correct value! [" + value + "]");//
        }

        // let's login the current user so we can check against roles and permissions:
        //测试当前的用户是否已经被认证,即是否已经登录
        //调用Subject的isAuthenticated()
        if (!currentUser.isAuthenticated()) {
            //把用户名和密码封装为token:令牌
            UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
            //rememberme
            token.setRememberMe(true);
            try {
                //执行登录操作
                currentUser.login(token);
            }
            //若没有指定的账户,则shiro抛出异常UnknownAccountException
            catch (UnknownAccountException uae) {
                log.info("There is no user with username of " + token.getPrincipal());
            }
            //若账户存在,密码不匹配,则shiro抛出 IncorrectCredentialsException异常
            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 more exceptions here (maybe custom ones specific to your application?
            //所有异常的父类
            catch (AuthenticationException ae) {
                //unexpected condition?  error?
            }
        }

        //say who they are:
        //print their identifying principal (in this case, a username):
        log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");

        //test a role:
        if (currentUser.hasRole("schwartz")) {
            log.info("May the Schwartz be with you!");
        } else {
            log.info("Hello, mere mortal.");
        }

        //test a typed permission (not instance-level)  粗粒度
        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.");
        }

        //a (very powerful) Instance Level permission:  细粒度
        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!");
        }

        //注销
        //all done - log out!
        currentUser.logout();

        //结束系统
        System.exit(0);
    }
}

quickstart这三行是固定的

Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);

集成springboot

shior核心对象

  • Subject:用户
  • SecurityManager:管理所有用户
  • Realm:连接数据

导入shiro整合springboot整合依赖

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.8.0</version>
</dependency>

这两个依赖在后面会用到

<!--thymeleaf-->
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
  • 编写配置类 ShiroConfig。配置类添加@Configuration注解!!!切记

    • ShiroFilterFactoryBean
    • DefaultWebSecurityManager
    • 创建realm对象,需要自定义类
    • 以上三点对应shiro三大对象,从下向上配置
  • 自定义的userRealm

    • extends AuthorizingRealm

    • 重写两个方法 1.授权 2.认证

      public class UserRealm 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;
          }
      }
      
  • 将UserRealm对象配置进spirng

    //创建UserRealm,对象
    @Bean(name = "userRealm")
    public UserRealm userRealm(){
        return new UserRealm();
    }
    
  • 配置DafaultWebSecurityManager

    //DefaultWebSecurityManager
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联UserRealm
        securityManager.setRealm(userRealm);
        return securityManager;
    }
    
  • 创建ShiroFilterFactoryBean

    //ShiroFilterFactoryBean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);
        return bean;
    }
    

如何实现对用户的授权操作

  • 在ShiroFilterFactoryBean中添加shiro的内置过滤器

    • anno:无需认证就可以访问

    • authc:必须认证了才能访问

    • user: 必须拥有 记住我功能才能访问

    • perms:拥有对某个资源的权限才能访问

    • role:拥有某个角色才能访问

      //ShiroFilterFactoryBean
      @Bean
      public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
          ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
          //设置安全管理器
          bean.setSecurityManager(defaultWebSecurityManager);
          //如何实现对用户的授权操作
          //在ShiroFilterFactoryBean中添加shiro的内置过滤器
          Map<String,String> filterMap = new LinkedHashMap<>();
          // /user/add /update 为定义接口
          filterMap.put("/user/add","authc");
          filterMap.put("/user/update","authc");
      
          bean.setFilterChainDefinitionMap(filterMap);
          System.err.println("[debug]   shiro");
          return bean;
      }
      

      通过以上代码可以通过shiro拦截所有的请求

    • 设置登录拦截,在上面的代码中添加。(/toLogin为登陆界面)

      bean.setLogUrl(/toLogin);
      

用户认证操作,放在UserRealm中

登录controller中

  • 获取当前的用户

    Subject subject = SecurityUtils.getSubject();
    
  • 封装用户的登录数据 (封装username和password)-- > Token令牌

    //封装用户登录数据
    UsernamePasswordToken token = new UsernamePasswordToken(username, password);
    
  • subject.login(token);//执行登录方法,没有异常说明ok

  • 捕获上一步的异常

    try {
        //执行登录方法
        subject.login(token);
        return "index";
    }
    catch (UnknownAccountException uae) {//用户名不存在
        model.addAttribute("msg","用户名不存在");
        return "login";
    }
    catch (IncorrectCredentialsException ice) {//密码错误
        model.addAttribute("msg","密码错误");
        return "login";
    }
    
  • UserRealm

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了=>认证");
        //用户名,密码  ,正常应从数据库中取。这里为了方便,在这里伪造数据
        String username = "root";
        String password = "123456";
        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
    
        if(!token.getUsername().equals(username)){
            return null;//return null 抛出异常,UnknownAccountExecption
        }
        return new SimpleAuthenticationInfo("",passsword,"");
    }
    
posted @ 2021-12-16 13:28  贾博文  阅读(85)  评论(0)    收藏  举报