Shiro权限控制

我们都知道Shiro和secitity都是安全的框架,但是相对于Shiro来说,比较入门简单,所需要的功能基本上都能满足,理解起来也会比较容易。

Shiro是一个有许多特性的全面的安全框架,下面一幅图进行介绍。

Shiro权限控制1.png

可以看出Shiro除了基本的认证、授权、会话管理、加密之外还有许多特性。

Shiro架构:

从架构来说,主要包含三个概念,Subject、SecurityManager、Realms(重要),在使用的时候我们都是围绕这三个概念来进行编码和使用


Shiro权限控制2.png

Shiro的应用不依赖任何的容器,可以在javaSE下使用也可以在javaEE上使用,下面是一张用户登录的例图:


Shiro权限控制3.png

首先理解下面的几个类:

SecurityManager:

Shiro的核心是ScurityManager,它是负责安全认证与授权的,Shiro本身已经实现了所有的细节,我们在使用的时候可以完全把它当做黑盒使用。

SecurityUtils:

本质上是一个工厂,类似Spring中的ApplicationContext,

Subject:

Subject是有点难理解的,有些地方理解为user,其实不然,Subject中文翻译是项目,在下面代码中会表现的很清楚

Realm:

在Shiro中,进行的授权和认证就是由它来操作的,我已开始对授权和认证不是很理解,也不是很明白在代码操作的时候命名在认证的时候,可以获取到授权的信息,为什么还要在进行授权的操作,下面对授权和认证做一下解释:所谓的认证,他相当于人的身份证,就是可以证明你身份的证件,在应用中,就是拿着当前登录的用户的名称与数据库中查询,看是当前登录的用户是否在数据库存在,如果存在,好,说明你是你自己。而所谓的授权,就相当于当你购买火车票的时候,如果你买的硬座,你就只能去硬座的车厢,而不能去软卧等其他车厢,这就相当于限制了你的能力,而在应用中也相当于如此,在授权的时候,会从数据库将你的权限信息获取到,交给Shiro,如果此时你要去访问指定的页面的时候,会首先对你的权限进行校验,看你是否有该权限,如果有就可以访问,没有则不可以访问。

代码讲解:

准备ehcache的xml配置 ,为什么要设置ehcache,是因为如果不设置,会每次刷新页面的时候都会去访问授权的方法,加上缓存之后,可以有效的制止


<?xml version="1.0" encoding="UTF-8"?>
<!--add by shanggq 2018/8/31 end-->
<ehcache name="es">
<span class="hljs-tag">&lt;<span class="hljs-name">diskStore</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"java.io.tmpdir"</span>/&gt;</span>

<span class="hljs-comment">&lt;!--
   name:缓存名称。
   maxElementsInMemory:缓存最大数目
   maxElementsOnDisk:硬盘最大缓存个数。
   eternal:对象是否永久有效,一但设置了,timeout将不起作用。
   overflowToDisk:是否保存到磁盘,当系统当机时
   timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
   timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
   diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
   diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
   diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
   memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
    clearOnFlush:内存数量最大时是否清除。
     memoryStoreEvictionPolicy:
        Ehcache的三种清空策略;
        FIFO,first in first out,这个是大家最熟的,先进先出。
        LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
        LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
--&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">defaultCache</span>
        <span class="hljs-attr">maxElementsInMemory</span>=<span class="hljs-string">"10000"</span>
        <span class="hljs-attr">eternal</span>=<span class="hljs-string">"false"</span>
        <span class="hljs-attr">timeToIdleSeconds</span>=<span class="hljs-string">"120"</span>
        <span class="hljs-attr">timeToLiveSeconds</span>=<span class="hljs-string">"120"</span>
        <span class="hljs-attr">overflowToDisk</span>=<span class="hljs-string">"false"</span>
        <span class="hljs-attr">diskPersistent</span>=<span class="hljs-string">"false"</span>
        <span class="hljs-attr">diskExpiryThreadIntervalSeconds</span>=<span class="hljs-string">"120"</span>
/&gt;</span>

<span class="hljs-comment">&lt;!-- 登录记录缓存锁定10分钟 --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">cache</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"passwordRetryCache"</span>
       <span class="hljs-attr">maxEntriesLocalHeap</span>=<span class="hljs-string">"2000"</span>
       <span class="hljs-attr">eternal</span>=<span class="hljs-string">"false"</span>
       <span class="hljs-attr">timeToIdleSeconds</span>=<span class="hljs-string">"3600"</span>
       <span class="hljs-attr">timeToLiveSeconds</span>=<span class="hljs-string">"0"</span>
       <span class="hljs-attr">overflowToDisk</span>=<span class="hljs-string">"false"</span>
       <span class="hljs-attr">statistics</span>=<span class="hljs-string">"true"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">cache</span>&gt;</span>

</ehcache>
<!-- add by zhangcf 2018/8/31 start -->

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
<span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.example<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>springbootshiro<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">packaging</span>&gt;</span>jar<span class="hljs-tag">&lt;/<span class="hljs-name">packaging</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>springbootshiro<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">description</span>&gt;</span>Demo project for Spring Boot<span class="hljs-tag">&lt;/<span class="hljs-name">description</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">parent</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.0.4.RELEASE<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">relativePath</span>/&gt;</span> <span class="hljs-comment">&lt;!-- lookup parent from repository --&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">parent</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">properties</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">project.build.sourceEncoding</span>&gt;</span>UTF-8<span class="hljs-tag">&lt;/<span class="hljs-name">project.build.sourceEncoding</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">project.reporting.outputEncoding</span>&gt;</span>UTF-8<span class="hljs-tag">&lt;/<span class="hljs-name">project.reporting.outputEncoding</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">java.version</span>&gt;</span>1.8<span class="hljs-tag">&lt;/<span class="hljs-name">java.version</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">properties</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-comment">&lt;!--&lt;exclusions&gt;--&gt;</span>
            <span class="hljs-comment">&lt;!--&lt;exclusion&gt;--&gt;</span>
                <span class="hljs-comment">&lt;!--&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;--&gt;</span>
                <span class="hljs-comment">&lt;!--&lt;artifactId&gt;spring-boot-starter-tomcat&lt;/artifactId&gt;--&gt;</span>
            <span class="hljs-comment">&lt;!--&lt;/exclusion&gt;--&gt;</span>
        <span class="hljs-comment">&lt;!--&lt;/exclusions&gt;--&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>


    <span class="hljs-comment">&lt;!--!&amp;#45;&amp;#45;用于编译jsp&amp;ndash;&amp;gt;--&gt;</span>
    <span class="hljs-comment">&lt;!--&amp;lt;!&amp;ndash; https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-jasper &amp;ndash;&amp;gt;--&gt;</span>
    <span class="hljs-comment">&lt;!--&lt;dependency&gt;--&gt;</span>
        <span class="hljs-comment">&lt;!--&lt;groupId&gt;org.apache.tomcat.embed&lt;/groupId&gt;--&gt;</span>
        <span class="hljs-comment">&lt;!--&lt;artifactId&gt;tomcat-embed-jasper&lt;/artifactId&gt;--&gt;</span>
    <span class="hljs-comment">&lt;!--&lt;/dependency&gt;--&gt;</span>

    <span class="hljs-comment">&lt;!--&amp;lt;!&amp;ndash;jsp页面使用jstl标签&amp;ndash;&amp;gt;--&gt;</span>
    <span class="hljs-comment">&lt;!--&amp;lt;!&amp;ndash; https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl &amp;ndash;&amp;gt;--&gt;</span>
    <span class="hljs-comment">&lt;!--&lt;dependency&gt;--&gt;</span>
        <span class="hljs-comment">&lt;!--&lt;groupId&gt;javax.servlet.jsp.jstl&lt;/groupId&gt;--&gt;</span>
        <span class="hljs-comment">&lt;!--&lt;artifactId&gt;jstl&lt;/artifactId&gt;--&gt;</span>
    <span class="hljs-comment">&lt;!--&lt;/dependency&gt;--&gt;</span>
    <span class="hljs-comment">&lt;!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-configuration-processor --&gt;</span>
    <span class="hljs-comment">&lt;!-- configuration-processor --&gt;</span>

    <span class="hljs-comment">&lt;!--用来读取配置文件--&gt;</span>
    <span class="hljs-comment">&lt;!--&lt;dependency&gt;--&gt;</span>
        <span class="hljs-comment">&lt;!--&lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;--&gt;</span>
        <span class="hljs-comment">&lt;!--&lt;artifactId&gt;spring-boot-configuration-processor&lt;/artifactId&gt;--&gt;</span>
        <span class="hljs-comment">&lt;!--&lt;optional&gt;true&lt;/optional&gt;--&gt;</span>
    <span class="hljs-comment">&lt;!--&lt;/dependency&gt;--&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>mysql<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mysql-connector-java<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>runtime<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-comment">&lt;!--jpa 对象持久化,利用该jar包,通过bean直接生成数据库表--&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-data-jpa<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-autoconfigure<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- shiro的依赖 --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.shiro<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>shiro-spring<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.3.2<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.shiro<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>shiro-ehcache<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.3.2<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>

    <span class="hljs-comment">&lt;!--&amp;lt;!&amp;ndash; https://mvnrepository.com/artifact/net.sf.ehcache/ehcache &amp;ndash;&amp;gt;--&gt;</span>
    <span class="hljs-comment">&lt;!--&lt;dependency&gt;--&gt;</span>
    <span class="hljs-comment">&lt;!--&lt;groupId&gt;net.sf.ehcache&lt;/groupId&gt;--&gt;</span>
    <span class="hljs-comment">&lt;!--&lt;artifactId&gt;ehcache&lt;/artifactId&gt;--&gt;</span>
    <span class="hljs-comment">&lt;!--&lt;version&gt;2.10.5&lt;/version&gt;--&gt;</span>
    <span class="hljs-comment">&lt;!--&lt;/dependency&gt;--&gt;</span>


    <span class="hljs-comment">&lt;!--   DRUID是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0、DBCP、PROXOOL等DB池的优点,同时加入了日志监控,
    可以很好的监控DB池连接和SQL的执行情况,可以说是针对监控而生的DB连接池(据说是目前最好的连接池,不知道速度有没有BoneCP快)。--&gt;</span>
    <span class="hljs-comment">&lt;!-- https://mvnrepository.com/artifact/com.alibaba/druid --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.alibaba<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>druid<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.1.10<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-test<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>test<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>

    <span class="hljs-comment">&lt;!--热部署--&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-devtools<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">optional</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">optional</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-comment">&lt;!--spring boot 整合 mybatis 依赖--&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.mybatis.spring.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mybatis-spring-boot-starter<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.3.0<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- json支持 --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>net.sf.json-lib<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>json-lib<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.4<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">classifier</span>&gt;</span>jdk15<span class="hljs-tag">&lt;/<span class="hljs-name">classifier</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- 包含支持UI模版(Velocity,FreeMarker,JasperReports), 邮件服务, 脚本服务(JRuby), 缓存Cache(EHCache),
                任务计划Scheduling(uartz)。 --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-context-support<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- 单点登录 --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.shiro<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>shiro-cas<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.2.4<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">build</span>&gt;</span>
    <span class="hljs-comment">&lt;!--表示最终的项目名,--&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">finalName</span>&gt;</span>springbootshiro<span class="hljs-tag">&lt;/<span class="hljs-name">finalName</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">plugins</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-maven-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span>
        <span class="hljs-comment">&lt;!--用于告诉maven在打包的时候不需要web.xml,否则会报到不到web.xml de错--&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>maven-war-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.4<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">configuration</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">failOnMissingWebXml</span>&gt;</span>false<span class="hljs-tag">&lt;/<span class="hljs-name">failOnMissingWebXml</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">plugins</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">build</span>&gt;</span>

</project>

下面对代码的讲解,我是按照用户一开始登录,到最后的顺序来讲解,如果按照从数据操作到前端访问开始讲的话,有些地方会比较难理解

Controller层的数据 -- 前端页面在访问的时候访问的路径


package com.example.springbootshiro.Controller;

import com.example.springbootshiro.service.ILoginService;
import com.example.springbootshiro.entity.Role;
import com.example.springbootshiro.entity.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

/**

  • @author shanggq
  • @date 2018/8/31
    */
    // add by shanggq 2018/8/31 start
    @RestController
    public class LoginResource {

// // 注入业务层
// @Autowired
// private ILoginService iLoginService;
//
@GetMapping("/login")
public String login() {
return “login”;
}

//
// POST登录
@PostMapping("/login")
public String login(@RequestBody Map map) {
// 添加用户认证信息
Subject subject = SecurityUtils.getSubject();

    UsernamePasswordToken usernamePasswordToken = <span class="hljs-keyword">new</span> UsernamePasswordToken(
            map.get(<span class="hljs-string">"username"</span>).toString(),
            map.get(<span class="hljs-string">"password"</span>).toString()
    );
    subject.login(usernamePasswordToken);
    <span class="hljs-keyword">return</span> <span class="hljs-string">"login"</span>;
}

//
@RequestMapping("/index")
public String index(){
return “index”;
}
//
//
@PostMapping("/error")
public String error(){
return “error”;
}
//
// @RequestMapping("/addUser")
// public String addUser(@RequestBody Map<String,Object> map){
// User user = iLoginService.addUser(map);
// return “addUser id ok \n”+user;
// }
//
角色初始化
//
// @RequestMapping(“addRole”)
// public String addRole(@RequestBody Map<String ,Object> map ){
// Role role = iLoginService.addRole(map);
// return “addRole is ok ! \n” +role;
// }
//
注解的使用,表示访问该方法需要怎样的权限和角色
//
//
// @RequiresRoles(“admin”)
// @RequiresPermissions(“create”)
// @RequestMapping("/create")
// public String create(){
// return “Create success!”;
// }
}
// add by shanggq 2018/8/31 endn

上面代码显示,如果当前端按照post的格式进行数据访问login的时候,会请求到login的方法中,接收的参数是一个map,也就是说在页面中进行数据请求的时候,会将登录的用户名和密码或者其他数据进行传递,然后使用@RequetsBody将数据封装到map集合中,然后下面将数据放到了 UsernamePasswordToken(用户名密码认证机制)对象中,然后此时将该对象放到了用 SecurityUtils对象获取到的Subject对象中,SecutityUtils在上面提到过,他相当于Application,本质上是一个工厂类,然后使用该工厂获取到了Subject,在上面的构架图中我们可以看到,Application Code最终是给了Subject,然后Subject却又给了SecutityManager对象,也就是说现在可以理解为页面传递的用户的信息会存储在SecutityManager中。

Realm的编写(最重要的。进行用户的授权和认证)


package com.example.springbootshiro.shiro;

import com.example.springbootshiro.mapper.UserInfoMapper;
import com.example.springbootshiro.service.ILoginService;
import com.example.springbootshiro.entity.Permission;
import com.example.springbootshiro.entity.Role;
import com.example.springbootshiro.entity.User;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**

  • @author shanggq

  • @date 2018/8/31
    */
    // add by shanggq 2018/8/31 start
    @Component
    public class MyShiroRealm extends AuthorizingRealm {

    /**

    • 用於数据库的数据的访问,
    • @Resource 按照名称进行数据的注入
    • @Autowired 按照类型进行数据的注入
      */
      @Autowired
      private UserInfoMapper tokentokentoken;

    /**

    • 权限信息(授权)

    • @param principals

    • @return 如果用户正常退出,缓存会自动消除

    • 如果用户非正常退出,缓存也会自动消除

    • 如果修改了用户的权限,而用户没有退出系统,修改的权限无法立即生效–需手动实现,放在service中

    • <p>

    • 如果不做缓存,shiro会有自己的时间的间隔机制,时间为2分钟
      /
      @Override
      protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
      /

      • 当没有使用缓存的时候,不断的刷新页面的话,这个代码会不断的执行,其实没有
      • 必要每次都要重新设置权限的信息,所以需要在放到缓存中进行管理,当放到环迅中这样的haunted
      • doGetAuthorizationInfo就会只执行一次,缓存在过期之后再次
      • */
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        User user = (User) principals.getPrimaryPrincipal();

      List<Role> list = new ArrayList<>();
      list = tokentokentoken.findRoleListByName(user.getUid());

      user.setRoles(list);

// 设置角色,权限,
// info.addRole(“admin”);
// info.addStringPermission(“query”);

// 从数据库中设置角色和权限,分别设置到 SimpleAuthorizationInfo 中返回

    <span class="hljs-keyword">for</span> (Role role : user.getRoles()) {
        info.addRole(role.getRolename());
        <span class="hljs-keyword">for</span> (Permission permission : role.getPermissions()) {
            info.addStringPermission(permission.getPermission());
        }
    }
    <span class="hljs-keyword">return</span> info;
}

<span class="hljs-comment">/**
 * 身份认证
 *
 * <span class="hljs-doctag">@param</span> token
 * <span class="hljs-doctag">@return</span>
 * <span class="hljs-doctag">@throws</span> AuthenticationException
 */</span>
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">protected</span> AuthenticationInfo <span class="hljs-title">doGetAuthenticationInfo</span><span class="hljs-params">(AuthenticationToken token)</span> <span class="hljs-keyword">throws</span> AuthenticationException </span>{

// 获取用户的输入的账号
String userName = (String) token.getPrincipal();

    User user = tokentokentoken.findByUserName(userName);

    <span class="hljs-keyword">if</span> (user == <span class="hljs-keyword">null</span>) {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
    }

// 加密方式,获取密码在存入的时候,加密的盐
// 明文。若存在,将此用户存放到登录认证info中,不需要我们自己进行密码的比较,shiro会自动给我们进行比较
return new SimpleAuthenticationInfo(userName, user.getPassword(), ByteSource.Util.bytes(user.getSalt()), getName());

}

}
// add by shanggq 2018/8/31 end

Realm中分为身份认证和授权两个方法,一开始我对这两个方法不理解,因为我的思路是你身份认证完成之后说明你可以进行登录,这样不就完成控制了么,为什么还需要权限认证,当我在继续往下面看的时候,发现并不是这样的。数据全部的操作全部交给SecurityManager对象去操作。

下面配置核心对象 SecurityManager。在这里我们使用的是spring boot 搭建的工程,所以这里也使用java配置,来完成对象注入到spring容器中。


package com.example.springbootshiro.shiro;

import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.LinkedHashMap;

/**

  • 进行相应的bena的初始化

  • @author shanggq

  • @date 2018/8/31
    */
    // add by shanggq 2018/8/31 start
    @Configuration
    public class ShiroConfiguration {
    //将自己的验证方式加入容器,因为自己的的容器配置了授权和认证的方法
    @Bean
    public MyShiroRealm myShiroRealm() {
    MyShiroRealm myShiroRealm = new MyShiroRealm();
    return myShiroRealm;
    }

    /*
    shiro缓存管理器

    • 需要注入其他的实体类中
    • 1,安全管理器。secuityManager 最核心的管理器,但是配置完成之后基本上不会进行操作
    • */
      @Bean
      public EhCacheManager ehCacheManager() {
      System.out.println(“ShiroConfiguration.getEhCacheManager()”);
      EhCacheManager cacheManager = new EhCacheManager();
      // 指定配置shiro的文件
      cacheManager.setCacheManagerConfigFile(“classpath:ehcache-shiro.xml”);
      return cacheManager;
      }

    // 权限管理,配置主要是Realm的管理认证
    @Bean(name = “securityManager”)
    public SecurityManager securityManager() {
    DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
    // 设置realm
    manager.setRealm(myShiroRealm());
    // 注入缓存
    manager.setCacheManager(ehCacheManager());
    return manager;
    }
    // Filter 工厂,设置对应的过滤条件和跳转条件
    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    // 必须要设置的 SecurityManager
    shiroFilterFactoryBean.setSecurityManager(securityManager);
    // 设置的拦截器
    // HashMap<String, String> hashMap = new HashMap<>();
    LinkedHashMap<String, String> hashMap = new LinkedHashMap<>();

     <span class="hljs-comment">//  配置退出的过滤器,其中的具体的退出代码shiro已经替我们实现了</span>
     hashMap.put(<span class="hljs-string">"/logout"</span>, <span class="hljs-string">"logout"</span>);
    

// 登录页面需要的权限
hashMap.put("/login", “anon”);

    <span class="hljs-comment">//对所有的用户进行认证 当所有的认证都通过的时候才可以访问路径,</span>
    hashMap.put(<span class="hljs-string">"/**"</span>, <span class="hljs-string">"authc"</span>);
    <span class="hljs-comment">//登录页</span>
    shiroFilterFactoryBean.setLoginUrl(<span class="hljs-string">"/login"</span>);
    <span class="hljs-comment">//登录成功之后跳转到首页</span>
    shiroFilterFactoryBean.setSuccessUrl(<span class="hljs-string">"/index"</span>);
    <span class="hljs-comment">//错误页面。认证不通过的时候跳转</span>
    shiroFilterFactoryBean.setUnauthorizedUrl(<span class="hljs-string">"/error"</span>);
    shiroFilterFactoryBean.setFilterChainDefinitionMap(hashMap);
    <span class="hljs-keyword">return</span> shiroFilterFactoryBean;
}

<span class="hljs-comment">//    加入注解的使用,不加入这个注解不生效</span>
<span class="hljs-meta">@Bean</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> AuthorizationAttributeSourceAdvisor <span class="hljs-title">authorizationAttributeSourceAdvisor</span><span class="hljs-params">(SecurityManager securityManager)</span> </span>{
    AuthorizationAttributeSourceAdvisor advisor = <span class="hljs-keyword">new</span> AuthorizationAttributeSourceAdvisor();
    advisor.setSecurityManager(securityManager);
    <span class="hljs-keyword">return</span> advisor;
}

}
// add by shanggq 2018/8/31 end

首先创建你继承了 AuthorizingRealm的 对象类,将该对象创建出来使用@Bean放到spring的容器中,然后再创建 EhCacheManager 对象,为什么要创建该对象的呢,我们在权限控制的代码中已经加了说明,是因为现权限在开发中一般很少去发生改变,如果我们每次在刷新页面的时候都要去数据库中获取数据,判断当前用户有没有当前的权限,会加大数据库的访问,所以我们可以将数据放在缓存中,这样在每次刷新页面的时候,不会都去访问该授权的代码,而首先是去缓存中查询数据,当缓存过期之后,才会去访问授权部分的代码。

然后在创建核心的对象SecutityManager对象,将继承身份认证的对象和缓存的对象都放到SecutityManager对象中,然后返回。然后创建下面的 ShiroFilterFactoryBean 对象,该对象在使用传统的配置文件的时候,也需要配置该类,目的是为了进行数据的拦截。将拦截的数据传递给上面创建的对象,然后完成身份和权限的校验,不知道在这里读者有没有在脑海中出现一条思路,也就是说,用户在将数据提交的时候,Subject会接收到数据,然后将数据会传递给SecutityManager对象,这里又有疑问了,数据是怎么传递给SecutityManager对象的呢,所以我就去查看源码,结果找到了下面的代码


控制4.png

也就是说,subject会将前端接收到的数据给SecutityManager,然而Realm返回的数据和 EhCacheManager缓存对象添加到SecutityManager对象中,但是该对象需要被谁给触发呢,所以就到了最后面的拦截器,ShiroFilterFactoryBean,那我们是不是可以理解为,当有请求过来的时候,会触发拦截器,而拦截器回去调用SecutityManager对象,而SecutityManager对象再去分别调用Realm和EhcacheManager对象,分别获取数据,此时用户的身份,权限都已经获取到,就到了下面的权限的设置,我们将全部的权限信息放到了 LinkedHashMap 集合中,而且还可以使用 ShiroFilterFactoryBean 对象设置登录、失败、首页所需要跳转的页面,然后将集合放到 ShiroFilterFactoryBean 对象中。下面对权限的信息进行说明(常用的五种)

  Anon:表示可以不用登录直接访问

Authc:表示需要登录之后才可以访问

Perms:表示权限

Roles:表示角色

User:表示用户

AuthorizationAttributeSourceAdvisor对象表示的是开启对方法上的注解的扫描,因为有些方法是在当具有一定的权限的时候才可以访问的,如果不初始化该类的实例,方法上的注解是不起作用的,原因如下

是因为,代理的 方式,应该都知道,java的代理方式,一种是传统的代理方式,当有接口的时候才会使用,一种是cglib代理的方式,传统的代理方式是针对接口而言的,由于此时接口上是没有shiro的注解的,所以此时的注解是不起作用的,所以需要对上面的对象进行实例化,当然也可以改用cglib代理的方式,选择代理的方式是如果有接口就是用传统的代理方式,如果没有接口则使用cglib代理的方式。

文章来源:https://blog.csdn.net/weixin_38297879/article/details/82258119
推荐阅读:https://www.roncoo.com/course/list.html?courseName=Shiro

      </div>
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页