shiro+SSM

权限概述

什么是权限管理

权限管理实现对用户访问系统的控制
用户可以访问而且只能访问自己被授权的资源
只要有用户和密码的系统,权限管理几乎都会出现

举例
给张三赋予“人力资源经理”角色,
“人力资源经理”具有“查询员工”、“添加员工”、“修改员工”和“删除员工”权限。
此时张三能够进入系统,则可以进行这些操作;

权限管理

  1. 认证
    对于需要访问控制的资源用户首先经过身份认证
    判断一个用户是否为合法用户的处理过程
  2. 授权
    认证通过后用户具有资源的访问权限-方可访问
    控制能够访问哪些资源

shiro概述

Apache Shiro是Java的一个安全框架
Shiro是一个强大的简单易用的Java安全框架,主要用来更便捷的认证、授权、加密、会话管理、与Web集成、缓存等
Shiro使用起来小而简单
spring中有spring security ,是一个权限框架,它和spring依赖过于紧密,没有shiro使用简单。
shiro不依赖于spring,shiro不仅可以实现web应用的权限管理,还可以实现c/s系统,分布式系统权限管理,
shiro属于轻量框架,越来越多企业项目开始使用shiro.

shiro核心概念

核心类

整体类图
在这里插入图片描述

  1. Authentication
    身份认证/登录,验证用户是不是拥有相应的身份;
  2. Authorization
    授权,即权限验证,验证某个已认证的用户是否拥有某个权限;
  3. Session Manager
    会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;
  4. Cryptography
    加密,保护数据的安全性
  5. Web Support
    Web支持,可以非常容易的集成到Web环境;
  6. Caching
    缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;
  7. Concurrency
    shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
  8. Testing
    提供测试支持;
  9. Run As
    允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
  10. Remember Me
    记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。

主要概念

Subject

当前的操作用户
可以是人
爬虫
当前跟软件交互的东西
在shiro当中我们可以统称"用户"
在代码的任何地方,你都能轻易的获得Shiro Subject。
一旦获得Subject,你就可以立即获得你希望用Shiro为当前用户做的90%的事情:登录、退、访问会话、执行授权检查等

SecurityManager

SecurityManager则管理所有用户的安全操作
引用了多个内部嵌套安全组件,是Shiro框架的核心
你可以把它看成DispatcherServlet前端控制器。
用于调度各种Shiro框架的服务

Realms

Realms则是用户的信息认证器和用户的权限认证器
执行认证(登录)和授权(访问控制)时,Shiro会从应用配置的Realm中查找很多内容
Realm 可以理解为读取用户信息、角色及权限的 DAO
SecurityManager要验证用户身份与权限,那么它需要从Realm获取相应的信息进行比较以确定用户身份是否合法;
可以把Realm看成DataSource,即安全数据源。

Shiro架构

整体架构图
在这里插入图片描述

  1. subject:主体
    主体可以是用户也可以是程序,主体要访问系统,系统需要对主体进行认证、授权。
  2. securityManager:安全管理器
    主体进行认证和授权都是通过securityManager进行。
  3. authenticator: 认证器
    主体进行认证最终通过authenticator进行的。
  4. authorizer: 授权器
    主体进行授权最终通过authenticator进行的。
  5. sessionManager:会话管理
    web应用中一般是用web容器对session进行管理,shiro也提供一套session管理的方式。
  6. sessionDao:
    通过sessionDao管理session数据,
  7. cacheManager: 缓存管理器
    主要对session和授权数据进行缓存,比如将授权数据通过cacheManager进行缓存管理,和 ehcache整合对缓存数据进行管理。
  8. realm: 领域
    相当于数据源,通过realm存取认证、授权相关数据。
  9. cryptography: 密码管理
    提供了一套加密/解密的组件,方便开发。比如 提供常用的散列、加/解密等功能。

认证

什么是认证

身份认证,就是判断一个用户是否为合法用户的处理过程
通过核对用户输入的用户名和口令,看其是否与系统中存储的该用户的用户名和口令一致,来判断用户身份是否正确

关键对象

  1. Subject:主体
    用户
  2. Principal:身份信息
    是主体(subject)进行身份认证的标识,标识必须具有唯一性,如用户名、手机号、邮箱地址等
  3. credential:凭证信息
    是只有主体自己知道的安全信息,如密码、证书等。

使用ini完成认证

  1. 在Maven中添加依赖jar包
    <dependency>  
        <groupId>org.apache.shiro</groupId>  
        <artifactId>shiro-core</artifactId>  
        <version>1.4.0</version>  
    </dependency>  
  1. 添加shiro.ini配置文件
    首先准备一些用户身份/凭据(shiro.ini):
[users]  
itlike=1234
my=1234
  1. 登录与退出

1.构建securityManager工厂
2.通过工厂创建securityManager
3.将securityManager设置到运行环境中
4.创建一个Subject实例
5.创建token令牌
6.用户登录
7.用户退出
在这里插入图片描述

		/*1.构建securityManager工厂*/
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        /*2.通过工厂创建securityManager*/
        SecurityManager securityManager = factory.getInstance();
        /*3.将securityManager设置到运行环境中*/
        SecurityUtils.setSecurityManager(securityManager);
        /*4.创建一个Subject实例*/
        Subject subject = SecurityUtils.getSubject();
        /*5.创建token令牌  用户名和密码*/
        UsernamePasswordToken token = new UsernamePasswordToken("itlike", "1234");
        /*6.用户登陆*/
        try {
            subject.login(token);
        } catch (UnknownAccountException e) {
            System.out.println("用户名不存在");
            e.printStackTrace();
        }catch (IncorrectCredentialsException e){
            System.out.println("密码错误");
            e.printStackTrace();
        }
        System.out.println("是否认证"+subject.isAuthenticated());
        /*7.用户退出*/
        subject.logout();
        System.out.println("是否认证"+subject.isAuthenticated());

认证流程

在这里插入图片描述
认证代码执行流程

  1. 调用subject.login方法进行登录,其会自动委托给securityManager.login方法进行登录;
    在这里插入图片描述

  2. securityManager通过Authenticator(认证器)进行认证;
    在这里插入图片描述

3.Authenticator的实现ModularRealmAuthenticator调用realm从ini配置文件取用户真实的账号和密码
在这里插入图片描述

  1. IniRealm先根据token中的账号去ini中找该账号,如果找不到则给ModularRealmAuthenticator返回null,如果找到则匹配密码,匹配密码成功则认证通过。
    在这里插入图片描述

  2. 最后调用Subject.logout进行退出操作。

自定义realm

  1. 创建一个类继承AuthorizingRealm
  2. 覆盖doGetAuthenticationInfo方法,在此方法当中数据库获取用户,交有验证器去验证
    在这里插入图片描述
  3. 在ini文件当中进行配置
myRealm=MyRealm
securityManager.realms=$myRealm

散列密码

概述

散列算法一般用于生成数据的摘要信息,是一种不可逆的算法 一般适合存储密码之类的数据,常见的散列算法如MD5、SHA等

使用shiro进行散列密码
Md5Hash
SimpleHash
在这里插入图片描述

 Md5Hash md5Hash = new Md5Hash("itlike");
        System.out.println(md5Hash);
        /*通过加盐的方式来对密码进一步保护*/
        Md5Hash md5Hash2 = new Md5Hash("itlike","myxq");
        System.out.println(md5Hash2);
        /*可进行二次散列*/
        Md5Hash md5Hash3 = new Md5Hash("itlike","myxq",2);
        System.out.println(md5Hash3);
        /*使用SimpleHash*/
        SimpleHash simpleHash = new SimpleHash(
                "md5",
                "itlike",
                "myxq",
                2);
        System.out.println(simpleHash);

realm中配置散列
在ini文件当中进行散列
在这里插入图片描述

[main]
#定义凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#散列算法
credentialsMatcher.hashAlgorithmName=md5
#散列次数
credentialsMatcher.hashIterations=3
#指定realm
myRealm=com.itlike.MyRealm
#配置散列
myRealm.credentialsMatcher=$credentialsMatcher
#配置自定义散列
securityManager.realms=$myRealm

要保证数据库中的密码是经过散列之后的
在这里插入图片描述
在这里插入图片描述

授权

什么是授权

授权,即访问控制,控制谁能访问哪些资源。
主体进行身份认证后需要分配权限,方可访问系统的资源,对于某些资源没有权限是无法访问的。

使用ini形式配置权限信息

在ini文件中用户、角色、权限的配置规则
用户名=密码,角色1,角色2...
首先根据用户名找角色,再根据角色找权限,角色是权限集合。

权限字符串的规则

“资源标识符:操作:资源实例标识符”
对哪个资源的哪个实例具有什么操作
:”是资源/操作/实例的分割符
权限字符串也可以使用*通配符
示例在这里插入图片描述

[users]
#用户itlike的密码是1234,此用户具有role1和role2两个角色
itlike=1234,role1,role2
myxq=1234,role2
[roles]
#角色role1对资源user拥有create、update权限
role1=user:create,user:update
#角色role2对资源user拥有create、delete权限
role2=user:create,user:delete
#角色role3对资源user拥有create权限
role3=user:create

自定义Realm形式权限
在这里插入图片描述

/*获取身份信息*/
        Object principal = principals.getPrimaryPrincipal();
        /*根据用户名查询该用户的角色和权限*/
        List<String> roles = new ArrayList();
        roles.add("role1");
        roles.add("role2");
        List<String> permissions = new ArrayList();
        permissions.add("user:create");
        permissions.add("user:delete");
        /*把角色和权限与subject关联在一起,返回*/
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addRoles(roles);
        info.addStringPermissions(permissions);

shiro.ini方式使用流程

  1. 创建maven工程
    在这里插入图片描述
    在这里插入图片描述
  2. 在Maven中添加依赖jar包. shiro核心jar&&依赖jar
    在这里插入图片描述
 <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.4.0</version>
    </dependency>
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.2</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-nop</artifactId>
      <version>1.7.30</version>
      <scope>test</scope>
    </dependency>
  1. 创建shiro.ini文件
    在这里插入图片描述
  2. 认证代码
    在这里插入图片描述
    在这里插入图片描述
public static void main( String[] args ){
        /**
         * 1.构建securityManager工厂
         * 2.通过工厂创建securityManager
         * 3.将securityManager设置到运行环境中
         * 4.创建一个Subject实例
         * 5.创建token令牌
         * 6.用户登录
         * 7.用户退出
         */

        //1.构建securityManager工厂
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        //2.通过工厂创建securityManager
        SecurityManager securityManager = factory.getInstance();
        //3.将securityManager设置到运行环境中
        SecurityUtils.setSecurityManager(securityManager);
        //4.创建一个Subject实例
        Subject subject = SecurityUtils.getSubject();
        //5.创建token令牌
        UsernamePasswordToken token = new UsernamePasswordToken("joker", "1234");
        // 6.用户登录
        try {
            subject.login(token);
        }catch (UnknownAccountException e){
            /*账号不存在*/
            System.out.println("账号不存在");

        }catch (IncorrectCredentialsException e){
            /*密码错误*/
            System.out.println("密码错误");
        }
        System.out.println("是否认证成功"+subject.isAuthenticated());
        //7.用户退出
        subject.logout();
        System.out.println("是否认证成功"+subject.isAuthenticated());
    }

自定义realm

  1. 创建一个类继承AuthorizingRealm
    在这里插入图片描述
  2. 自定义认证
    在这里插入图片描述
/*认证AuthenticationInfo*/
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        /*判断用户名密码是否存在*/
        /*获取用户名*/
        String username=(String) token.getPrincipal();
        /*从数据库中查询密码*/
        String name="joker";
        String password="1234";
        if(!name.equals(username)){
            return null;
        }

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, this.getName());
        return info;
    }
  1. 在ini文件配置realm
    在这里插入图片描述
myRealm=com.dj.myRealm
securityManager.realms=$myRealm

散列密码加盐
配置散列信息
在这里插入图片描述
在这里插入图片描述
4. 授权
在 shiro-permission.ini配置文件配置
在这里插入图片描述

[users]
#用户itlike的密码是1234,此用户具有role1和role2两个角色
itlike=1234,role1,role2
myxq=1234,role2

[roles]
#角色role1对资源user拥有create、update权限
role1=user:create,user:update
#角色role2对资源user拥有create、delete权限
role2=user:create,user:delete
#角色role3对资源user拥有create权限
role3=user:create

在这里插入图片描述

		 System.out.println("是否认证成功"+subject.isAuthenticated());
        //在认证成功之后才去授权
        //判断当前用户是否有某个角色和
        System.out.println(subject.hasRole("role1"));
        /*判断当前用户是否有多个角色*/
        System.out.println(subject.hasAllRoles(Arrays.asList("role1", "role2")));

        /*判断使用有某个权限*/
        System.out.println(subject.isPermitted("user:update"));
        /*判断是否具备多个权限*/
        System.out.println(subject.isPermittedAll("user:create", "user:delete"));

自定义Realm形式权限
在这里插入图片描述

 /*授权AuthorizationInfo*/
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        /*获取身份信息*/
        Object principal = principals.getPrimaryPrincipal();
        /*根据用户名查询该用户的角色和权限*/  //从数据库查
        List<String> roles = new ArrayList();
        roles.add("role1");
        roles.add("role2");
        List<String> permissions = new ArrayList();
        permissions.add("user:create");
        permissions.add("user:delete");
        /*把角色和权限与subject关联在一起,返回*/
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addRoles(roles);
        info.addStringPermissions(permissions);
        return info;
    }

SSM整合shiro

在这里插入图片描述

  1. 添加依赖
<dependencies>
    <!--Junit-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
    </dependency>
    <!--数据库驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.46</version>
    </dependency>
    <!-- 数据库连接池 -->
    <dependency>
      <groupId>com.mchange</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.5.2</version>
    </dependency>

    <!--Servlet - JSP -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.2</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>

    <!--Mybatis-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.1</version>
    </dependency>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>2.0.2</version>
    </dependency>
    <!-- druid -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.0.14</version>
    </dependency>
    <!--Spring-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.0.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.1.9.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.16.10</version>
    </dependency>
    <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>5.1.10</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.8</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.8</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.8</version>
    </dependency>
    <dependency>
      <groupId>org.codehaus.jackson</groupId>
      <artifactId>jackson-mapper-asl</artifactId>
      <version>1.9.13</version>
    </dependency>
    <!-- joda-time -->
    <dependency>
      <groupId>joda-time</groupId>
      <artifactId>joda-time</artifactId>
      <version>2.9.6</version>
    </dependency>
    <!--shiro-->
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.2</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-nop</artifactId>
      <version>1.7.24</version>
    </dependency>
    <dependency>
      <groupId>commons-collections</groupId>
      <artifactId>commons-collections</artifactId>
      <version>3.2.1</version>
    </dependency>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.4.0</version>
    </dependency>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-web</artifactId>
      <version>1.4.0</version>
    </dependency>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-ehcache</artifactId>
      <version>1.4.0</version>
    </dependency>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-spring</artifactId>
      <version>1.4.0</version>
    </dependency>
  </dependencies>
  1. 在web.xml当中配置过滤器拦截所有请求,进行处理
 <!-- 拦截到所有请求,使用spring一个bean来进行处理 -->
    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <!-- 是否filter中的init和 destroy-->
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

web.xml

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0"
         metadata-complete="false">
  <absolute-ordering/>
  <display-name>web</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

  <!--配置前端控制器-->
  <servlet>
    <servlet-name>SpringMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <!--加载的主配置文件-->
      <param-value>classpath*:applicationContext.xml</param-value>
    </init-param>
    <!-- 项目启动就加载框架 -->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>SpringMVC</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>


  <!-- 拦截到所有请求,使用spring一个bean来进行处理 -->
  <filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <!-- 是否filter中的init和 destroy-->
    <init-param>
      <param-name>targetFilterLifecycle</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

application-mvc.xml

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context.xsd
	http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
	">

    <mvc:annotation-driven />
    <!--静态资源处理 -->
    <mvc:default-servlet-handler/>
    <!--视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".jsp" />
    </bean>


</beans>

application-mybatis.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
     http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
">

    <!--spring-Mybatis整合-->
    <!--加载数据库属性文件-->
    <context:property-placeholder location="classpath:db.properties"/>
    <!--连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}" />
        <!--属性文件当中的名称不能和name名称一样-->
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>
    <!-- 配置事务管理器 -->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 数据源 -->
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!-- 开启注解事务 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    <!-- Mybatis的工厂 -->
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!-- 核心配置文件的位置 -->
        <property name="configLocation" value="classpath:sqlMapConfig.xml"/>
        <!--配置mapper映射文件的路径-->
        <property name="mapperLocations" value="classpath*:com/dj/mapper/*mapper.xml"/>
    </bean>

    <!-- 配置Mapper接口扫描 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 配置Mapper扫描包 -->
        <property name="basePackage" value="com.dj.mapper" />
    </bean>

</beans>

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
     http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
">
    <!--注解扫描-->
    <context:component-scan base-package="com.dj"/>
    <!--导入mybatis-->
    <import resource="classpath:application-mybatis.xml"/>

    <!--导入springMVC-->
    <import resource="classpath:application-mvc.xml"/>
    <!--导入shiro-->
    <import resource="classpath:application-shiro.xml"/>

</beans>

db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/permission?characterEncoding=utf-8
jdbc.username=root
jdbc.password=123456

sqlMapConfig.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--<settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>-->
    <typeAliases>
        <!-- 批量别名定义,扫描整个包下的类,别名为类名(大小写不敏感) -->
        <package name="com.dj.domain" />
    </typeAliases>
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
        </plugin>
    </plugins>
</configuration>
  1. 在spring当中配置shiro过滤器和安全管理器 application-shiro.xml
    在这里插入图片描述
  2. 配置登录认证的路径
<!-- 配置登录认证的路径 -->
<property name="loginUrl" value="/login" />

在这里插入图片描述
5. 创建自定义realm
在这里插入图片描述

 /*认证*/
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("来到了认证");
        String username=(String)token.getPrincipal();
        System.out.println(username);
        /*到数据中查询有没有当前用户*/
        employee employee = service.getEmployeeWithUsername(username);
        System.out.println(employee);
        if(employee==null){
            return null;
        }
        /*认证*/
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(employee,employee.getPassword(),this.getName());
        return info;
  1. 配置realm
    在这里插入图片描述
  2. 创建表单提交的过滤器 继承FormAuthenticationFilter
    在这里插入图片描述
public class MyFormFilter extends FormAuthenticationFilter {
    /*认证成功会调用*/
    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
        response.setCharacterEncoding("UTF-8");
        /*响应给浏览器*/
        System.out.println("认证成功");
        AjaxRes ajaxRes = new AjaxRes(true, "登录成功");
        /*把对象转成json字符串*/
        String jsonString = new ObjectMapper().writeValueAsString(ajaxRes);
        response.getWriter().print(jsonString);
        return false;
    }
    /*认证失败 会调用*/
    @Override
    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
        /*响应给浏览器*/
        System.out.println("认证失败");
        return false;
    }
}
  1. 配置表单监听过滤器
    在这里插入图片描述
  2. 跳转首页
    在这里插入图片描述
  3. 认证失败
    在这里插入图片描述
  /*认证失败 会调用*/
    @Override
    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
        /*响应给浏览器*/
         response.setCharacterEncoding("UTF-8");
        if(e!=null){
            /*获取异常名称*/
            String name = e.getClass().getName();
            AjaxRes ajaxRes=null;
            if(name.equals(UnknownAccountException.class.getName())){
                /*账号不存在*/
                ajaxRes = new AjaxRes(false, "账号不存在");
            }else if(name.equals(IncorrectCredentialsException.class.getName())){
                /*密码错误*/
                 ajaxRes = new AjaxRes(false, "密码错误");
            }else {
                /*未知异常*/
                 ajaxRes = new AjaxRes(false, "未知异常");
            }
            String jsonString = null;
            try {
                jsonString = new ObjectMapper().writeValueAsString(ajaxRes);
                response.getWriter().print(jsonString);
            } catch (IOException ex) {
                ex.printStackTrace();
            }

        }

        return false;
    }

在这里插入图片描述
11. 设置注销url
在这里插入图片描述
12. 授权注解
在这里插入图片描述
配置支持shiro注解

在这里插入图片描述

<!--
    配置为true即使用cglib继承的方式,
    false为jdk的接口动态代理   控制器没有实现接口
    -->
    <aop:config proxy-target-class="true" ></aop:config>
    <!-- 使用第三方去扫描shiro的注解 -->
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor ">
        <property name="securityManager" ref="securityManager"></property>
    </bean>
  1. 授权realm
    在这里插入图片描述
    /*授权*/
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
        System.out.println("来到了授权");
        employee employee = (employee)principal.getPrimaryPrincipal();
        List<String> roles=service.getroleById(employee.getId());
        List<String> permission=service.getpermission(employee.getId());
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addRoles(roles);
        info.addStringPermissions(permission);
        return info;
    }
  1. 授权标签
<shiro:hasPermission name=""></shiro:hasPermission>
<shiro:hasRole name=""></shiro:hasRole>
  1. 散列加密
    在这里插入图片描述
    在这里插入图片描述
<!-- 凭证匹配器 -->
	<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
		<!-- 散列算法 -->
		<property name="hashAlgorithmName" value="md5"/>
		<!-- 散列次数 -->
		<property name="hashIterations" value="2"></property>
	</bean>


	<!--自定义realm-->
	<bean id="employeeRealm" class="com.dj.web.realm.EmplyeeRealm">
		<property name="credentialsMatcher" ref="credentialsMatcher"/>
	</bean>
  1. 权限缓存 shiro-ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
    <defaultCache
            maxElementsInMemory="1000"
            maxElementsOnDisk="10000000"
            eternal="false"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>

在这里插入图片描述
shiro.xml
在这里插入图片描述
17. 菜单权限

/*获取树形菜单数据*/
    @RequestMapping("/getTreeData")
    @ResponseBody
    public List<menu> getTreeData(){
        List<menu> treeData = service.getTreeData();
        System.out.println(treeData);
        /*判断权限
        如果没有就移除
        * */
        /*获取用户*/
        Subject subject = SecurityUtils.getSubject();
        /*当前用户*/
        employee employee =(employee) subject.getPrincipal();
        if(!employee.getAdmin()){
            /*不是管理员 校验权限*/
            chePermission(treeData);
        }
        return treeData;
    }
    /*校验权限*/
    public void chePermission(List<menu> menus){
        Subject subject = SecurityUtils.getSubject();
        /*遍历所有菜单 及子菜单*/
        Iterator<menu> iterator = menus.iterator();
        while (iterator.hasNext()) {
            menu m = iterator.next();
            if(m.getPermission()!=null){
                /*判断当前菜单是否有权限  没有就移除*/
                String presources = m.getPermission().getPresources();
                if(!subject.isPermitted(presources)){
                    /*没有 从菜单集合 移除*/
                    iterator.remove();
                    continue;
                }
            }
            /*判断是否有子菜单 如果有 继续做校验*/
            if(m.getChildren().size()>0){
                chePermission(m.getChildren());
            }

        }
    }
原文地址:https://www.cnblogs.com/joker-dj/p/13388734.html