【Shiro】Springboot集成Shiro(四)

简介: 【Shiro】Springboot集成Shiro(四)

【2】过滤器链

定义:authentication.properties

#静态资源不过滤

/static/**=anon

#登录链接不过滤

/login/**=anon

#其他链接是需要登录的

/**=authc

注意:这里定义的过滤器是有执行顺序的,从上向下执行

【3】加载原理分析

定义:PropertiesUtil,从classpath中加载authentication.properties

1. package com.itheima.shiro.properties;
2. 
3. import com.itheima.shiro.utils.EmptyUtil;
4. import lombok.extern.log4j.Log4j2;
5. 
6. /**
7.  * @Description 读取Properties的工具类
8.  */
9. @Log4j2
10. public class PropertiesUtil {
11. 
12. public static LinkProperties propertiesShiro = new LinkProperties();
13. 
14. /**
15.      * 读取properties配置文件信息
16.      */
17. static {
18. String sysName = System.getProperty("sys.name");
19. if (EmptyUtil.isNullOrEmpty(sysName)) {
20.             sysName = "application.properties";
21.         } else {
22.             sysName += ".properties";
23.         }
24. try {
25.             propertiesShiro.load(PropertiesUtil.class.getClassLoader()
26.                     .getResourceAsStream("authentication.properties"));
27.         } catch (Exception e) {
28.             log.warn("资源路径中不存在authentication.properties权限文件,忽略读取!");
29.         }
30.     }
31. 
32. /**
33.      * 根据key得到value的值
34.      */
35. public static String getShiroValue(String key) {
36. return propertiesShiro.getProperty(key);
37.     }
38. 
39. }

定义LinkProperties,这个类保证了Properties类的有序

1. package com.itheima.shiro.properties;
2. 
3. import java.io.*;
4. import java.util.ArrayList;
5. import java.util.Enumeration;
6. import java.util.List;
7. import java.util.Properties;
8. 
9. 
10. /**
11.  * @Description 有序Properties类
12.  */
13. 
14. public class LinkProperties extends Properties{
15. 
16.   /** serialVersionUID */
17.   private static final long serialVersionUID = 7573016303908223266L;
18. 
19.   private List<Object> keyList = new ArrayList<Object>();  
20. 
21. /** 
22.      * 默认构造方法 
23.      */
24. public LinkProperties() {  
25. 
26.     }  
27. 
28. /** 
29.      * 从指定路径加载信息到Properties 
30.      * @param path 
31.      */
32. public LinkProperties(String path) {  
33. try {  
34. InputStream is = new FileInputStream(path);  
35. this.load(is);  
36.         } catch (FileNotFoundException e) {  
37.             e.printStackTrace();  
38. throw new RuntimeException("指定文件不存在!");  
39.         } catch (IOException e) {  
40.             e.printStackTrace();  
41.         }  
42.     }  
43. 
44. /** 
45.      * 重写put方法,按照property的存入顺序保存key到keyList,遇到重复的后者将覆盖前者。 
46.      */
47. @Override
48. public synchronized Object put(Object key, Object value) {  
49. this.removeKeyIfExists(key);  
50.         keyList.add(key);  
51. return super.put(key, value);  
52.     }  
53. 
54. 
55. /** 
56.      * 重写remove方法,删除属性时清除keyList中对应的key。 
57.      */
58. @Override
59. public synchronized Object remove(Object key) {  
60. this.removeKeyIfExists(key);  
61. return super.remove(key);  
62.     }  
63. 
64. /** 
65.      * keyList中存在指定的key时则将其删除 
66.      */
67. private void removeKeyIfExists(Object key) {  
68.         keyList.remove(key);  
69.     }  
70. 
71. /** 
72.      * 获取Properties中key的有序集合 
73.      * @return 
74.      */
75. public List<Object> getKeyList() {  
76. return keyList;  
77.     }  
78. 
79. /** 
80.      * 保存Properties到指定文件,默认使用UTF-8编码 
81.      * @param path 指定文件路径 
82.      */
83. public void store(String path) {  
84. this.store(path, "UTF-8");  
85.     }  
86. 
87. /** 
88.      * 保存Properties到指定文件,并指定对应存放编码 
89.      * @param path 指定路径 
90.      * @param charset 文件编码 
91.      */
92. public void store(String path, String charset) {  
93. if (path != null && !"".equals(path)) {  
94. try {  
95. OutputStream os = new FileOutputStream(path);  
96. BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os, charset));  
97. this.store(bw, null);  
98.                 bw.close();  
99.             } catch (FileNotFoundException e) {  
100.                 e.printStackTrace();  
101.             } catch (IOException e) {  
102.                 e.printStackTrace();  
103.             }  
104.         } else {  
105. throw new RuntimeException("存储路径不能为空!");  
106.         }  
107.     }  
108. 
109. /** 
110.      * 重写keys方法,返回根据keyList适配的Enumeration,且保持HashTable keys()方法的原有语义, 
111.      * 每次都调用返回一个新的Enumeration对象,且和之前的不产生冲突 
112.      */
113. @Override
114. public synchronized Enumeration<Object> keys() {  
115. return new EnumerationAdapter<Object>(keyList);  
116.     }  
117. 
118. /** 
119.      * List到Enumeration的适配器 
120.      */
121. private class EnumerationAdapter<T> implements Enumeration<T> {  
122. private int index = 0;  
123. private final List<T> list;  
124. private final boolean isEmpty;  
125. 
126. public EnumerationAdapter(List<T> list) {  
127. this.list = list;  
128. this.isEmpty = list.isEmpty();  
129.         }  
130. 
131. public boolean hasMoreElements() {  
132. //isEmpty的引入是为了更贴近HashTable原有的语义,在HashTable中添加元素前调用其keys()方法获得一个Enumeration的引用,  
133. //之后往HashTable中添加数据后,调用之前获取到的Enumeration的hasMoreElements()将返回false,但如果此时重新获取一个  
134. //Enumeration的引用,则新Enumeration的hasMoreElements()将返回true,而且之后对HashTable数据的增、删、改都是可以在  
135. //nextElement中获取到的。  
136. return !isEmpty && index < list.size();  
137.         }  
138. 
139. public T nextElement() {  
140. if (this.hasMoreElements()) {  
141. return list.get(index++);  
142.             }  
143. return null;  
144.         }  
145. 
146.     }  
147. }

查看shirocConfig

 

加载完整之后交于ShiroFilterFactoryBean使用setFilterChainDefinitionMap使得过滤生效

【4】自定义过滤器

上面我们使用了shiro的默认过滤器,但是由于业务需求,咱们可能要定义自己的过滤器,那么咱们定义呢?

这里我们先查看RolesAuthorizationFilter

 

分析:改源码表示,例如:/admin/order= roles["admin, root"] ,只有当放问该接口同时具备admin和root两种角色时,才可以被访问。

【5】自定义过滤器使用

【5.1】需求

1、实现只要有其中一个角色,则可访问对应路径

【5.2】RolesOrAuthorizationFilter

新建filter层,新建类RolesOrAuthorizationFilter

1. package com.itheima.shiro.filter;
2. 
3. import org.apache.shiro.subject.Subject;
4. import org.apache.shiro.util.CollectionUtils;
5. import org.apache.shiro.web.filter.authz.AuthorizationFilter;
6. 
7. import javax.servlet.ServletRequest;
8. import javax.servlet.ServletResponse;
9. import java.io.IOException;
10. import java.util.Set;
11. 
12. /**
13.  * @Description:角色或关系
14.  */
15. public class RolesOrAuthorizationFilter extends AuthorizationFilter {
16. 
17. //TODO - complete JavaDoc
18. 
19. @SuppressWarnings({"unchecked"})
20. public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
21. 
22. Subject subject = getSubject(request, response);
23.         String[] rolesArray = (String[]) mappedValue;
24. 
25. if (rolesArray == null || rolesArray.length == 0) {
26. //no roles specified, so nothing to check - allow access.
27. return true;
28.         }
29. 
30.         Set<String> roles = CollectionUtils.asSet(rolesArray);
31. //循环roles判断只要有角色则返回true
32. for (String role : roles) {
33. if(subject.hasRole(role)){
34. return true;
35.             }
36.         }
37. return false;
38.     }
39. 
40. }
【5.3】编辑ShiroConfig

在ShiroConfig类中添加如下内容

1. /**
2.      * @Description 自定义过滤器定义
3.      */
4. private Map<String, Filter> filters() {
5.         Map<String, Filter> map = new HashMap<String, Filter>();
6.         map.put("role-or", new RolesOrAuthorizationFilter());
7. return map;
8.     }
9. 
10. /**
11.      * @Description Shiro过滤器
12.      */
13. @Bean("shiroFilter")
14. public ShiroFilterFactoryBean shiroFilterFactoryBean(){
15. ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
16.         shiroFilter.setSecurityManager(defaultWebSecurityManager());
17. //使自定义过滤器生效
18.         shiroFilter.setFilters(filters());
19.         shiroFilter.setFilterChainDefinitionMap(filterChainDefinition());
20.         shiroFilter.setLoginUrl("/login");
21.         shiroFilter.setUnauthorizedUrl("/login");
22. return shiroFilter;
23.     }

【2.2.3】编辑authentication.properties

#静态资源不过滤

/static/**=anon

#登录链接不过滤

/login/**=anon

#访问/resource/**需要有admin的角色

/resource/**=role-or[admin]

#其他链接是需要登录的

/**=authc

7、注解方式鉴权

【1】注解介绍

以下为常用注解

注解 说明
@RequiresAuthentication 表明当前用户需是经过认证的用户
@ RequiresGuest 表明该用户需为”guest”用户
@RequiresPermissions 当前用户需拥有指定权限
@RequiresRoles 当前用户需拥有指定角色
@ RequiresUser 当前用户需为已认证用户或已记住用户

例如RoleAction类中我们添加

1. /**
2.   *@Description: 跳转到角色的初始化页面
3.   */
4.  @RequiresRoles(value ={"SuperAdmin","dev"},logical = Logical.OR)
5.  @RequestMapping(value = "listInitialize")
6.  public ModelAndView listInitialize(){
7.    return  new ModelAndView("/role/role-listInitialize");
8.  }

【2】注解原理分析

【2.1】装载过程

【2.2】调用过程

相关文章
|
11天前
|
安全 Java Apache
SpringBoot+Shiro(一)
SpringBoot+Shiro(一)
|
5天前
|
存储 前端开发 Java
Spring Boot 集成 MinIO 与 KKFile 实现文件预览功能
本文详细介绍如何在Spring Boot项目中集成MinIO对象存储系统与KKFileView文件预览工具,实现文件上传及在线预览功能。首先搭建MinIO服务器,并在Spring Boot中配置MinIO SDK进行文件管理;接着通过KKFileView提供文件预览服务,最终实现文档管理系统的高效文件处理能力。
|
9天前
|
XML Java 关系型数据库
springboot 集成 mybatis-plus 代码生成器
本文介绍了如何在Spring Boot项目中集成MyBatis-Plus代码生成器,包括导入相关依赖坐标、配置快速代码生成器以及自定义代码生成器模板的步骤和代码示例,旨在提高开发效率,快速生成Entity、Mapper、Mapper XML、Service、Controller等代码。
springboot 集成 mybatis-plus 代码生成器
|
9天前
|
Java Spring
springboot 集成 swagger 2.x 和 3.0 以及 Failed to start bean ‘documentationPluginsBootstrapper‘问题的解决
本文介绍了如何在Spring Boot项目中集成Swagger 2.x和3.0版本,并提供了解决Swagger在Spring Boot中启动失败问题“Failed to start bean ‘documentationPluginsBootstrapper’; nested exception is java.lang.NullPointerEx”的方法,包括配置yml文件和Spring Boot版本的降级。
springboot 集成 swagger 2.x 和 3.0 以及 Failed to start bean ‘documentationPluginsBootstrapper‘问题的解决
|
2月前
|
NoSQL 关系型数据库 MySQL
SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘
SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘
93 2
|
2月前
|
SQL Java 数据库连接
springboot+mybatis+shiro项目中使用shiro实现登录用户的权限验证。权限表、角色表、用户表。从不同的表中收集用户的权限、
这篇文章介绍了在Spring Boot + MyBatis + Shiro项目中,如何使用Shiro框架实现登录用户的权限验证,包括用户、角色和权限表的设计,以及通过多个表查询来收集和验证用户权限的方法和代码实现。
springboot+mybatis+shiro项目中使用shiro实现登录用户的权限验证。权限表、角色表、用户表。从不同的表中收集用户的权限、
|
2月前
|
SQL 前端开发 Java
springboot项目中使用shiro实现用户登录以及权限的验证
这篇文章详细介绍了如何在Spring Boot项目中集成Apache Shiro框架来实现用户登录和权限验证,包括项目依赖配置、数据库连接、实体类定义、控制器、服务层、Mapper层以及前端页面的实现,并展示了实际效果和过滤器代码。
springboot项目中使用shiro实现用户登录以及权限的验证
|
2月前
|
NoSQL Java Redis
Spring Boot集成Redis全攻略:高效数据存取,打造性能飞跃的Java微服务应用!
【8月更文挑战第3天】Spring Boot是备受欢迎的微服务框架,以其快速开发与轻量特性著称。结合高性能键值数据库Redis,可显著增强应用性能。集成步骤包括:添加`spring-boot-starter-data-redis`依赖,配置Redis服务器参数,注入`RedisTemplate`或`StringRedisTemplate`进行数据操作。这种集成方案适用于缓存、高并发等场景,有效提升数据处理效率。
334 2
|
2月前
|
Java Spring
【Azure Developer】Springboot 集成 中国区的Key Vault 报错 AADSTS90002: Tenant 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' not found
【Azure Developer】Springboot 集成 中国区的Key Vault 报错 AADSTS90002: Tenant 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' not found
|
2月前
|
Java Spring
【Azure 事件中心】Spring Boot 集成 Event Hub(azure-spring-cloud-stream-binder-eventhubs)指定Partition Key有异常消息
【Azure 事件中心】Spring Boot 集成 Event Hub(azure-spring-cloud-stream-binder-eventhubs)指定Partition Key有异常消息
下一篇
无影云桌面