Shiro 三大核心组件:
1.Subject
2.Security Manager (核心)
3.Realm
3.Realm 进行用户账号密码校验(可以去数据库 或者 shiro.ini 文件)
工作原理:
1:用户通过账号密码登录,账号信息包装在Subject中去请求 SecurityManager
2:SecurityManager 将账号信息通过Realm进行认证(Realm直接取数据库或 文件的 数据)
3: SecurityManager 校验通过将进行授权,授权后的数据再次封装在Subject中
4:也就是说Subject最后封装的是用户信息和权限信息,全局直接取就行
***javaEE项目核心展示: *******
首先目录结构
pom:**********************************
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.1</version>
</dependency>
</dependencies>
main:**********************************
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入账号:");
String username= sc.nextLine();
System.out.println("请输入密码:");
String password= sc.nextLine();
// 1. 创建安全管理器
DefaultSecurityManager securityManager = new DefaultSecurityManager();
//2.创建Realm
IniRealm iniRealm = new IniRealm("classpath:shiro.ini");//Realm 的数据
//3.将Realm 设置给安全管理器
securityManager.setRealm(iniRealm);
//4.将Realm 设置给SecurityUtis工具类
SecurityUtils.setSecurityManager(securityManager);
//5.通过SecurityUtis工具类获取subject对象
Subject subject = SecurityUtils.getSubject();
//【认证流程】
//a.将认证账号和密码封装到token对象中
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
//b.通过subject对象调用login方法进行认证申请
boolean b =false;
try {
subject.login(token);
b=true;
}catch (IncorrectCredentialsException e){//账号密码错误
b=false;
}
System.out.println(b?"登陆成功":"登陆失败");
//【授权流程】
// 检查用户是否有这个角色
System.out.println(subject.hasRole("seller"));
//判断是否有某个权限
boolean pemitted = subject.isPermitted("order-del");
System.out.println(pemitted);
}
shiro.ini ***********************
[users]
zhangsan=123456,seller
lisi=666666,ckmgr
admin=123123,admin
[roles]
admin=*
seller=order-add,order-del,order-list
ckmgr=ck-add,ck-del,ck-list
五.基于javaSE应用-Shiro基本使用
1.创建maven项目
2.导入Shiro依赖库
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.1</version>
</dependency>
</dependencies>
3.创建Shiro配置文件
在resource下创建shiro.ini文件
在文件中完成用户,角色及权限的配置
[users]
zhangsan=123456,seller
lisi=666666,ckmgr
admin=123123,admin
[roles]
admin=*
seller=order-add,order-del,order-list
ckmgr=ck-add,ck-del,ck-list
六.Shiro的基本使用
核心应用:
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入账号:");
String username= sc.nextLine();
System.out.println("请输入密码:");
String password= sc.nextLine();
// 1. 创建安全管理器
DefaultSecurityManager securityManager = new DefaultSecurityManager();
//2.创建Realm
IniRealm iniRealm = new IniRealm("classpath:shiro.ini");//Realm 的数据
//3.将Realm 设置给安全管理器
securityManager.setRealm(iniRealm);
//4.将Realm 设置给SecurityUtis工具类
SecurityUtils.setSecurityManager(securityManager);
//5.通过SecurityUtis工具类获取subject对象
Subject subject = SecurityUtils.getSubject();
//【认证流程】
//a.将认证账号和密码封装到token对象中
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
//b.通过subject对象调用login方法进行认证申请
boolean b =false;
try {
subject.login(token);
b=true;
}catch (IncorrectCredentialsException e){//账号密码错误
b=false;
}
System.out.println(b?"登陆成功":"登陆失败");
//【授权流程】
// 检查用户是否有这个角色
System.out.println(subject.hasRole("seller"));
//判断是否有某个权限
boolean pemitted = subject.isPermitted("order-del");
System.out.println(pemitted);
}
七.SpringBoot整合Shiro
yml:
spring:
datasource:
druid:
url: jdbc:mysql://127.0.0.1:3306/shiro
driver-class-name: com.mysql.cj.jdbc.Driver
#如果数据库是8.x com.mysql.cj.jdbc.Driver
username: root
password: root
initial-size: 1
min-idle: 1
max-active: 20
mybatis:
mapper-locations: classpath:mappers/*Mapper.xml
type-aliases-package: com.shiro.beans
pom:
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
shiro的config配置文件******核心
//数据库读取方式
@Bean
public JdbcRealm geJdbcRealm(DataSource dataSource){
JdbcRealm jdbcRealm = new JdbcRealm();
//jdbcrealm 会自己在数据库查数据,前提是数据表结构满足jdbcrelam规范
//DataSource 从哪来的 ,是我们配置好的duride数据源,他会自动装配到spring容器
jdbcRealm.setDataSource(dataSource);
//jdbcRealm默认开启认证,需要手动开启授权功能
jdbcRealm.setPermissionsLookupEnabled(true);//PermissionsLookupEnabled 权限开启已启用
return jdbcRealm;
}
//数据库读取方式
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(JdbcRealm jdbcRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//security 要完成校验就需要 realm
securityManager.setRealm(jdbcRealm);
return securityManager;
}
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
//过滤器就是shiro进行权限校验的核心,进行认证和权限是需要SecurityManager
filter.setSecurityManager(securityManager);
//过滤器设置拦截规则
//anon 匿名用户可访问(任何人都行)
//authc 认证用户可访问(登陆过的)
//user 使用RememberMe的用户可访问
//perms 对应权限可访问
//role 对应的角色可访问
Map<String,String> filterMap = new HashMap<String, String>();
filterMap.put("/","anon"); //根路径不拦截
filterMap.put("/login.html","anon");//登录界面不拦截
filterMap.put("/regist.html","anon");//注册界面不拦截
filterMap.put("/user/login","anon");//登录路由不拦截
filterMap.put("/user/regist","anon");//注册路由不拦截
filterMap.put("/static/**","anon");//静态文件不拦截
filterMap.put("/**","authc");// 除了以上的不拦截,其他的都有需要登陆后才能访问
filterMap.put("/exit","logout");// 退出(并且在页面配置a href =“exit”)
filter.setFilterChainDefinitionMap(filterMap);
//设置登陆页面
filter.setLoginUrl("/login.html");
//设置未授权访问页面
filter.setUnauthorizedUrl("/login.html");
return filter;
}
filterMap.put("/exit","logout");// 退出(并且在页面加 a href =“exit”)
不需要走 controller层
若要html中支持shiro需要导入这个依赖
<!-- thymeleaf -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
在html中引入thymeleaf 模板
<html xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
html中常用的shiro标签,这个就是调用subject是否登录
<shiro:guest>
欢迎游客,<a href="login.html">登录</a>
</shiro:guest>
<shiro:user> //用户登陆的信息
欢迎你,[<shiro:principal/>] //用户名
</shiro:user>
授权:
操作数据之前,进行权限检查,有两种做法,
1.用户登录后只显示他能看到的菜单,通过页面的标签判断
<shiro:hasPermission name=”sys:c:save”>
<a href=”#”>入库</a>
</shiro:hasPermission>
2.过滤器授权,显示所有菜单,看他有权限访问这个菜单吗(防止自己主动输入路径越权访问)
2.1配置类控制好
只要访问c_add页面,必须有sys:c:save权限
filterMap.put("/c_add.html","perms[sys:c:save]");
跳转未授权页面
filter.setUnauthorizedUrl("/lesspermission.html");
2.2配置spring对shiro注解控制权限的支持(访问路径的权限)
//让注解加载执行,就是让控制权限的注解加入到这个类中让他处理
@Bean
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
autoProxyCreator.setProxyTargetClass(true);
return autoProxyCreator;
}
//注解加载器,在注解上控制权限,需要在这里生效注解
@Bean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager){
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
//添加注解
//如果没有sys:k:find ,就不让访问这个路径
@RequiresPermissions("sys:k:find")
@RequestMapping("list")
public String list(){
System.out.println("--------------》查询客户信息");
return "customer_list";
}
权限不足抛异常,
spring配置全局异常错误
//全局异常处理类
@ControllerAdvice
public class GlobalExceptionHandler {
//抛出 AuthorizationException 这个异常走这个方法
@ExceptionHandler
public String doException(Exception e){
if(e instanceof AuthorizationException){
return "lesspermission";
}
return null;
}
}
2.3代码控制权限,从subject中取出权限进行控制
@RequestMapping("list")
public String list(){
Subject subject = SecurityUtils.getSubject();
if(subject.isPermitted("sys:k:find")){
System.out.println("--------------》查询客户信息");
return "customer_list";
}else{
return "lesspermission";
}
}
缓存:
跟权限有关的界面,每次点击都需要访问 realm 中的doGetAuthorticationInfo 进行查询跟权限相关的角色和权限信息
1.导入依赖
开启缓存的支持
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
将shiro的缓存读进来
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.6</version>
</dependency>
shiro的缓存,
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-cache</artifactId>
<version>1.4.1</version>
</dependency>
2.配置缓存策略
在resource 下创建一个 ehcache.xml的文件
<?xml version="1.0" encoding="utf-8" ?>
<encache updateCheck="false" dynamicConfig="false">
<diskStore path="D:\cache" />
<cache name="users" timeToLiveSeconds="300" maxEntriesLocalHeap="1000"/>
<defaultCache name="defauleCache"
maxElementsInMemory="10000"
eternam="false"
timeToIdleSeconds="120"
timeLiveSeconds="120"
overflowToDisk="100000"
diskPersistent="false"
diskExpiryTheadIntervalSecond="120"
memoryStoreEvictionPolicy="LRU"/>
<!-- 缓存淘汰策略 算法
LRU 最近最少使用
FIFO 先进先出
LFU 最少使用
-->
</encache>
3 shiro.config配置文件
@Bean
public EhCacheManager getEhCacheManager(){
EhCacheManager ehCacheManager = new EhCacheManager();
ehCacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
return ehCacheManager;
}
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//security 要完成校验就需要 realm
securityManager.setRealm(myRealm);
//设置缓存
securityManager.setCacheManager(getEhCacheManager());
return securityManager;
}
session 管理器:
shiro 默认管理了session 可以自定义设置超时时间:
1.设置session过期时间:
@Bean
public DefaultSessionManager getDefaultSessionManager(){
DefaultSessionManager sessionManage = new DefaultSessionManager();
System.out.println("---------------"+sessionManage.getGlobalSessionTimeout());
sessionManage.setGlobalSessionTimeout(15*1000);//15秒
return sessionManage;
}
2.加入到SecurityManager:
//设置session过期时间
securityManager.setSessionManager(getDefaultSessionManager());