前言:前段时间在搭建公司框架安全验证的时候,就想到之前web最火的shiro框架,所以就在空闲时间学习并总结一些搭建流程和解析,这里给大家出个简单的教程说明吧。
shiro的基本介绍这里就不再说了,可以自行百度相关的shiro教程,对于第一次接触shiro的小伙伴,博主推荐你可以先阅读该篇文章Shiro,对shiro进行初步的了解,以及它的核心原理。
一、什么是shiro?
shiro是apache的一个开源框架,是一个权限管理的框架,实现 用户认证、用户授权。spring中有spring security (原名Acegi),是一个权限框架,它和spring依赖过于紧密,没有shiro使用简单。shiro不依赖于spring,shiro不仅可以实现 web应用的权限管理,还可以实现c/s系统,分布式系统权限管理,shiro属于轻量框架,越来越多企业项目开始使用shiro。使用shiro实现系统 的权限管理,有效提高开发效率,从而降低开发成本。
1.1 shiro内部结构框架 官网架构说明
1.2 外部看shiro架构
api | 说明 |
Subject | 主体,代表当前‘用户’ 。这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;即一个抽象概念;所有Subject都绑定到SecurityManager,与Subject的所有交互都会委派给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者 |
SecurityManager | 安全管理器;即所有与安全有关的操作都会与SecurityManager交互且它管理者所有Subject;可以看出它是Shiro的核心,它负责与后面介绍的其它组件进行交互以把它看成DispathcherServlet前端控制器 |
Realm | 域,Shiro从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。 |
1.3 shiro认证流程
二、添加shiro相关依赖
<!--验证码 用于登录安全校验-->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>${kaptcha.version}</version>
</dependency>
<!--Shiro核心框架 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>${shiro.version}</version>
</dependency>
<!-- Shiro使用Srping框架 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency>
<!-- Shiro使用EhCache缓存框架 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>
<!-- thymeleaf模板引擎和shiro框架的整合 -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>${thymeleaf.extras.shiro.version}</version>
</dependency>
三、添加相关配置类
在这里,博主先使用ehcache对用户登录信息做缓存管理(推荐使用reids做缓存好些,可解决分布式架构下session共享问题,可参考分布式架构中shiro的实现)
ehcache-shiro.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="layduo" updateCheck="false">
<!-- 磁盘缓存位置 -->
<diskStore path="java.io.tmpdir"/>
<!-- maxEntriesLocalHeap:堆内存中最大缓存对象数,0没有限制 -->
<!-- maxElementsInMemory: 在内存中缓存的element的最大数目。-->
<!-- eternal:elements是否永久有效,如果为true,timeouts将被忽略,element将永不过期 -->
<!-- timeToIdleSeconds:失效前的空闲秒数,当eternal为false时,这个属性才有效,0为不限制 -->
<!-- timeToLiveSeconds:失效前的存活秒数,创建时间到失效时间的间隔为存活时间,当eternal为false时,这个属性才有效,0为不限制 -->
<!-- overflowToDisk: 如果内存中数据超过内存限制,是否要缓存到磁盘上 -->
<!-- statistics:是否收集统计信息。如果需要监控缓存使用情况,应该打开这个选项。默认为关闭(统计会影响性能)。设置statistics="true"开启统计 -->
<!-- 默认缓存 -->
<defaultCache
maxEntriesLocalHeap="1000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
overflowToDisk="false">
</defaultCache>
<!-- 登录记录缓存 锁定10分钟 -->
<cache name="loginRecordCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="600"
timeToLiveSeconds="0"
overflowToDisk="false"
statistics="true">
</cache>
<!-- 系统活跃用户缓存 -->
<cache name="sys-userCache"
maxEntriesLocalHeap="10000"
overflowToDisk="false"
eternal="false"
diskPersistent="false"
timeToLiveSeconds="0"
timeToIdleSeconds="0"
statistics="true">
</cache>
<!-- 系统会话缓存 -->
<cache name="shiro-activeSessionCache"
maxElementsInMemory="10000"
overflowToDisk="true"
eternal="true"
timeToLiveSeconds="0"
timeToIdleSeconds="0"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="600">
</cache>
</ehcache>
application.yml中shiro相关配置参数
#shiro
shiro:
user:
#登录地址
loginUrl: /login
#权限认证失败地址
unauthorizedUrl: /unauth
#首页地址
indexUrl: /index
#验证码开关
captchaEnabled: true
#验证码类型: math数据计算、char字符检验
captchaType: math
cookie:
#设置cookie的域名 默认为空,即当前访问的域名
domain:
#设置cookie的有效访问路径
path: /
#设置HttpOnly属性
httpOnly: true
#设置cookie的过期时间,单位为天
maxAge: 30
session:
#session超时时间,-1代表永不过期(默认为30分钟)
expireTime: 30
#同步session到数据库的周期(默认1分钟)
dbSyncPeriod: 1
#相隔多久检查一次session的有效性,默认10分钟
validationInterval: 10
#同一个用户最大会话数,比如1的意思是同一个账号允许最多同时一个人登录(默认-1不限制)
maxSession: 1
#踢出之前登录的/之后登录的用户,默认踢出之前登陆的用户
kickoutAfter: false
shiro配置类 -- ShiroConfig.class
package com.layduo.framework.config;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.Filter;
import org.apache.commons.io.IOUtils;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.config.ConfigurationException;
import org.apache.shiro.io.ResourceUtils;
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.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.layduo.common.utils.StringUtils;
import com.layduo.framework.shiro.realm.UserRealm;
import com.layduo.framework.shiro.web.filter.Log