SpringBoot与Shiro整合权限管理实战

  • 2019 年 10 月 3 日
  • 笔记

SpringBoot与Shiro整合权限管理实战

作者 : Stanley 罗昊

转载请注明出处和署名,谢谢!

*观看本文章需要有一定SpringBoot整合经验*

Shiro框架简介

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码学和会话管理。使用Shiro的易于理解的API,可以快速、轻松地获得任何应用程序,

从最小的移动应用程序到最大的网络和企业应用程序。

分析Shiro的核心API

其实,Shiro的核心类有三个,分别是:

1.Subject:这个类呢,我们称之当前用户的主体,这个用户的主体包含了登陆、注销等等的一些方法,还有一些判断授权的一些方法;

2.SecurityManager:这个名称翻译过来就是,安全管理器的意思;

3.Realm:这个Realm呢其实我们Shiro去链接数据库的一个桥梁,因为,我们的程序需要去操作数据库去获取一些用户的信息,这些操作都需要Realm去完成;

这个三个API呢,都存在一些关系,比如.SecurityManager是需要去关联我们的Realm,Subject是需要把操作交给我们的SecurityManager,总结下来就是,Subject是需要去管理我们的SecurityManager,而SecurityManager去关联我们的Realm;

以上就是对Shiro的核心API进行的一些分析;

分析完之后,我们接下来就直接用SpringBoot与Shiro的整合,我们来看下它整合的关键步骤

SpringBoot整合Shiro

那么这个整合首先第一步需要导入Shiro的依赖;

【因为我用的是Gradle,所以仅展示Gradle用法】

1.修改.gradle文件,添加以下依赖

//Thymeleaf模板引擎,因为我用模板引擎所以我添加了此依赖          compile group: 'org.thymeleaf', name: 'thymeleaf', version: '3.0.11.RELEASE'          //Shiro          compile group: 'org.apache.shiro', name: 'shiro-web', version: '1.4.0'          compile group: 'org.apache.shiro', name: 'shiro-core', version: '1.4.0'          // https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring          compile group: 'org.apache.shiro', name: 'shiro-spring', version: '1.4.0'

2.编写Shiro的配置类

配置类需要三样API,分别是:

 /**       * 创建ShiroFilterFactoryBean       * shiro过滤bean       */    /**       * 创建DefaultWebSecurityManager       */        /**       * 创建Realm       */

如图:

3.自定义Realm类

因为我们需要在配置类中创建出Realm对象,所以我们需要建一个名为Realm的类:

创建后,需要继承一个方法,这个方法是Shiro提供的:

/**   * 自定义Realm   */  public class UserRealm extends AuthorizingRealm {      //执行授权逻辑      @Override      protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {            return null;      }        //执行认证逻辑      @Override      protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {            return null;        }

4.在配置类中new出Realm

 

Shiro配置配置类

package com.lh.shiroStudy.shiro;      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;    import java.util.LinkedHashMap;  import java.util.Map;      /**   * Shiro配置类   */  //@Configuration,声明本类是一个配置类  @Configuration  public class ShiroConfig {        /**       * 创建ShiroFilterFactoryBean       * shiro过滤bean       */      @Bean      public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){          ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();          //设置安全管理器          shiroFilterFactoryBean.setSecurityManager(securityManager);          //添加Shiro过滤器          /**           * Shiro内置过滤器,可以实现权限相关的拦截器           *  常用的过滤器:           *      anon: 无需认证(登录)可以访问           *      authc: 必须认证才可以访问           *      user: 如果使用rememberMe功能可以直接访问           *      perms: 该资源必须得到资源权限才可以访问           *      role: 该资源必须得到角色权限才可以访问           */            Map<String,String>filterMap = new LinkedHashMap<String, String>();          //左边编写拦截路径          filterMap.put("/add","authc");          filterMap.put("/update","authc");          filterMap.put("/testThymeleaf","authc");          //授权过滤器          //注意:当前授权拦截后,shiro会自动跳转未授权页面          filterMap.put("/add","perms[user:add]");            //修改跳转的登陆页面          shiroFilterFactoryBean.setLoginUrl("/toLogin");            //转跳至未授权页面【友好提示】          shiroFilterFactoryBean.setUnauthorizedUrl("/aaaaaa");//懒省事所以没有aaaa这个页面,如果需要,请在Contoller中添加            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);          return shiroFilterFactoryBean;      }          /**       * 创建DefaultWebSecurityManager       */      @Bean(name = "securityManager")      public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("UserRealm") UserRealm userRealm){          DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();          securityManager.setRealm(userRealm);          return securityManager;      }            /**       * 创建Realm       */      @Bean(name = "UserRealm")      public UserRealm getRealm(){          return new UserRealm();      }    }

Realm类

package com.lh.shiroStudy.shiro;    import org.apache.shiro.authc.*;  import org.apache.shiro.authz.AuthorizationInfo;  import org.apache.shiro.authz.SimpleAuthorizationInfo;  import org.apache.shiro.realm.AuthorizingRealm;  import org.apache.shiro.subject.PrincipalCollection;      /**   * 自定义Realm   */  public class UserRealm extends AuthorizingRealm {      //执行授权逻辑      @Override      protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {            //给资源进行授权          SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();            //添加资源的授权字符串          //info.addStringPermission("user:add");            //到数据库查询当前登陆用户的授权字符串          /**           * <!-演示状态-!>           *     获取当前用户           *     Subject subject = SecurityUtils.getSubject();           *     User user = (User)subject.getPrincipal();           *     User dbUser = userService.findById(id)           *     info.addStringPermission(dbUser.getPerms());           * </!-演示状态-!>           */          System.out.println("执行授权逻辑");          return null;      }        //执行认证逻辑      @Override      protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {          System.out.println("执行认证逻辑");          //假设数据库账号与密码是如下          String username = "admin";          String password = "123456";          /**           * 编写Shiro判断逻辑,比对用户名和密码           */          //1.判断用户名          UsernamePasswordToken token =(UsernamePasswordToken)arg0;            //User user = userService.findByName(token.getUsername());            if (user == null){              //用户名不存在              return null;//如果返回null,Shiro底层会抛出UnknowAccountException          }          //2.判断密码          /**           * 有三个参数           * 1.需要返回给login           * 2.是数据库的密码,将数据库密码返回,Shiro会自动判断           * 3.是Shiro的名字           */          return new SimpleAuthenticationInfo(user,password,"");        }  }