Shiro【散列算法、Shiro会话、退出登录 、权限表设计、注解配置鉴权 】(五)-全面详解(学习总结---从入门到深化)(下)

简介: Shiro【散列算法、Shiro会话、退出登录 、权限表设计、注解配置鉴权 】(五)-全面详解(学习总结---从入门到深化)

Shiro【散列算法、Shiro会话、退出登录 、权限表设计、注解配置鉴权 】(五)-全面详解(学习总结---从入门到深化)(上):https://developer.aliyun.com/article/1419956


Shiro授权_数据库查询权限


在认证后进行授权需要根据用户id查询到用户的权限,写法如下:


1、编写用户、角色、权限实体类

@Data
public class Users implements Serializable
{
    private Integer uid;
    private String username;
    private String password;
    private String salt;
}
// 角色
@Data
public class Role implements Serializable{
    private Integer rid;
    private String roleName;
    private String roleDesc;
}
// 权限
@Data
public class Permission implements Serializable{
    private Integer pid;
    private String permissionName;
    private String url;
}


2、修改UsersMapper接口

// 根据用户id查询权限
List<Permission> findPermissionById(Integer id);


3、在resources目录中编写UsersMapper的映射文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tong.myshiro1.mapper.UsersMapper">
    <select id="findPermissionById" resultType="com.tong.myshiro1.domain.Permission">
       SELECT DISTINCT permission.pid,permission.permissionName,permission.url FROM
           users
               LEFT JOIN users_role on users.uid = users_role.uid
               LEFT JOIN role on users_role.rid = role.rid
               LEFT JOIN role_permission on role.rid = role_permission.rid
               LEFT JOIN permission on role_permission.pid = permission.pid
       where users.uid = #{uid}
    </select>
</mapper>


4、测试方法

@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UsersMapper usersMapper;
    @Test
    public void testFindPermissionById(){
        List<Permission> permissions = usersMapper.findPermissionById(1);
        permissions.forEach(System.out::println);
   }
}


Shiro授权_在Realm进行授权



在自定义Realm中可以自定义授权方法:

// 自定义授权方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    //1.拿到用户认证信息
    Users users = (Users) principalCollection.getPrimaryPrincipal();
    //2.从数据库中查询权限
    List<Permission> permissions = usersMapper.findPermissionById(users.getUid());
    //3.遍历权限对象,将所有权限名交给Shiro管理
    SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
    for (Permission permission : permissions) {
         authorizationInfo.addStringPermission(permission.getUrl());
   }
    return authorizationInfo;
}


Shiro授权_过滤器配置鉴权



Shiro可以根据用户拥有的权限,控制具体资源的访问,这一过程称 为鉴权。在Shiro中,可以通过过滤器进行鉴权配置:

// 配置过滤器
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
    // 1.创建过滤器工厂
    ShiroFilterFactoryBean filterFactory=new ShiroFilterFactoryBean();
    // 2.过滤器工厂设置SecurityManager
   filterFactory.setSecurityManager(securityManager);
    // 3.设置shiro的拦截规则
    Map<String,String> filterMap=new HashMap<>();
    // 不拦截的资源
    filterMap.put("/login.html","anon");
    filterMap.put("/fail.html","anon");
    filterMap.put("/user/login","anon");
    filterMap.put("/css/**","anon");
    // 鉴权过滤器,要写在/**之前,否则认证都无法通过
    filterMap.put("/reportform/find","perms[/reportform/find]");
    filterMap.put("/salary/find","perms[/salary/find]");
    filterMap.put("/staff/find","perms[/staff/find]");
    // 其余资源都需要认证,authc过滤器表示需要认证才能进行访问; 
    //user过滤器表示配置记住我或认证都可以访问
    //filterMap.put("/**","authc");
    filterMap.put("/user/pay","authc");
    filterMap.put("/**", "user");
    // 4.将拦截规则设置给过滤器工厂
    filterFactory.setFilterChainDefinitionMap(filterMap);
    // 5.登录页面
    filterFactory.setLoginUrl("/login.html");
    return filterFactory;
}
// 编写测试控制器
@RestController
public class MyController {
    @GetMapping("/reportform/find")
    public String findReportform(){
        return "查询报表";
   }
    @GetMapping("/salary/find")
    public String findSalary(){
        return "查询工资";
   }
    @GetMapping("/staff/find")
    public String findStaff(){
        return "查询员工";
   }
}


此时如果权限不足会抛出401异常,我们可以自定义权限不足的跳转页面:


1、编写权限不足页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>权限不足</title>
</head>
<body>
    <h1>您的权限不足,请联系管理员!</h1>
</body>
</html>


2、配置权限不足的跳转页面

// 配置过滤器
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
    // 1.创建过滤器工厂
    ShiroFilterFactoryBean filterFactory=new ShiroFilterFactoryBean();
    // 2.过滤器工厂设置SecurityManager
    filterFactory.setSecurityManager(securityManager);
    // 3.设置shiro的拦截规则
    Map<String,String> filterMap=new HashMap<>();
    // 不拦截的资源
    filterMap.put("/login.html","anon");
    filterMap.put("/fail.html","anon");
    filterMap.put("/noPermission.html","anon");
    filterMap.put("/user/login","anon");
    filterMap.put("/css/**","anon");
    // 鉴权过滤器
    filterMap.put("/reportform/find","perms[/reportform/find]");
    filterMap.put("/salary/find","perms[/salary/find]");
    filterMap.put("/staff/find","perms[/staff/find]");
    // 其余资源都需要认证,authc过滤器表示需要认证才能进行访问; 
    //user过滤器表示配置记住我或认证都可以访问
    //filterMap.put("/**","authc");
    filterMap.put("/user/pay","authc");
    filterMap.put("/**", "user");
    //4.将拦截规则设置给过滤器工厂
    filterFactory.setFilterChainDefinitionMap(filterMap);
    // 5.登录页面
    filterFactory.setLoginUrl("/login.html");
    // 6.权限不足访问的页面
    filterFactory.setUnauthorizedUrl("/noPermission.html");
    return filterFactory;
}


Shiro授权_注解配置鉴权



除了过滤器,Shiro也提供了一些鉴权的注解。我们可以使用注解配置鉴权。


@RequiresGuest:不认证即可访问的资源。

@RequiresUser:通过登录方式或“记住我”方式认证后可以访问资源。 @RequiresAuthentication:通过登录方式认证后可以访问资 源。

@RequiresRoles:认证用户拥有特定角色才能访问的资源

@RequiresPermissions:认证用户拥有特定权限才能访问的资源


1、在配置类开启Shiro注解

// 开启shiro注解的支持
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
    AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
    advisor.setSecurityManager(securityManager);
    return advisor;
}
// 开启aop注解支持
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
    DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
    defaultAAP.setProxyTargetClass(true);
    return defaultAAP;
}


2、在控制器方法上添加鉴权注解

@GetMapping("/test/index")
@RequiresGuest
public String testIndex() {
    return "访问首页";
}
@GetMapping("/test/user")
@RequiresUser
public String testUser() {
    return "用户中心";
}
@GetMapping("/test/pay")
@RequiresAuthentication
public String testPay() {
    return "支付中心";
}
@GetMapping("/tax/find")
@RequiresPermissions("/tax/find")
public String taxFind() {
    return "查询税务";
}
@GetMapping("/address/find")
@RequiresPermissions("/address/find")
public String addressFind() {
    return "查询地址";
}



Shiro授权_Thymeleaf中进行鉴权



Shrio可以在一些视图技术中进行控制显示效果。例如Thymeleaf 中,只有认证用户拥有某些权限才会展示一些菜单。


1、在pom中引入Shiro和Thymeleaf的整合依赖

<dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extrasshiro</artifactId>
    <version>2.0.0</version>
</dependency>


2、在配置文件中注册ShiroDialect

@Bean
public ShiroDialect shiroDialect(){
    return new ShiroDialect();
}


3、在Thymeleaf中使用Shiro标签,控制前端的显示内容

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
    xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <meta charset="UTF-8">
    <title>主页面</title>
</head>
<body>
<h1>主页面</h1>
<ul>
    <li shiro:hasPermission="/reportform/find">
      <a href="/reportform/find">查询报表</a></li>
   <li shiro:hasPermission="/salary/find">
     <a href="/salary/find">查询工资</a></li>
   <li shiro:hasPermission="/staff/find">
     <a href="/staff/find">查询员工</a></li>
</ul>
    <h2><a href="/user/logout">退出登录</a></h2>
</body>
</html>


Shiro授权_缓存



在Shiro中,每次拦截请求进行鉴权,都会去数据库查询该用户的权 限信息。因为用户的权限信息在短时间内是不可变的,每次查询出 来的数据其实都是重复数据,此时就会非常浪费资源。所以一般我 们会将权限数据放在缓存中进行管理,这样我们就不用每次请求都 查询数据库,提升了系统性能。


缓存


缓存即存在于内存中的一块数据。数据库的数据是存储在硬盘上 的,而内存的读写效率要远远的高于数据库。但硬盘中保存的数据 是持久化数据,断电后依然存在;而内存中保存的是临时数据,随 时可能清空。所以我们为了提升系统性能,减少程序和数据库的交 互,会将经常查询但不常改变的,改变后对结果影响不大的数据放 入缓存中。


Shiro支持多种缓存产品,在课程中我们使用ehcache缓存用户的权限数据。


ehcache


ehcache是用来管理缓存的一个工具,其缓存的数据可以放在内存 中,也可以放在硬盘上。ehcache的核心是CacheManager,一切 的ehcache的应用都是从CacheManager开始的。


1、引入shiro和ehcache整合包

<!-- shiro和ehcache整合包 -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>1.9.0</version>
</dependency>


2、创建配置文件shiro-ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <diskStore path="java.io.tmpdir/Tmp_EhCache"/>
    <!--
        默认缓存设置
        maxElementsInMemory:缓存最大数目
        maxEntriesLocalHeap:指定允许在内存中存放元素的最大数量。
        timeToIdleSeconds:一个元素在不被请求的情况下允许在缓存中存活的最大时间。0表示永久有效。
        timeToLiveSeconds:无论一个元素闲置与否,其允许在Cache中存活的最大时间。0表示永久有效。
        diskExpiryThreadIntervalSeconds:检查元素是否过期的线程多久运行一次
      -->
    <defaultCache
            maxElementsInMemory="10000"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"/>
    <!-- 授权缓存设置 -->
    <cache name="authorizationCache"
           maxEntriesLocalHeap="2000"
           timeToIdleSeconds="0"
           timeToLiveSeconds="0">
    </cache>
</ehcache>


3、在配置文件创建CacheManager

// 创建CacheManager
@Bean
public EhCacheManager ehCacheManager() {
    EhCacheManager ehCacheManager = new EhCacheManager();
    ehCacheManager.setCacheManagerConfigFile( "classpath:shiro-ehcache.xml");
    return ehCacheManager;
}


4、在SecurityManager中配置CacheManager

@Bean
public DefaultWebSecurityManager securityManager(MyRealm myRealm,MyRealm2 myRealm2,
       SessionManager sessionManager, CookieRememberMeManager rememberMeManager,
       EhCacheManager ehCacheManager){
      DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    // 自定义Realm放入SecurityManager中
    // securityManager.setRealm(myRealm);
    // 设置Realm管理者(需要设置在Realm之前)
    securityManager.setAuthenticator(modularRealmAuthenticator());
    List<Realm> realms = new ArrayList();
    realms.add(myRealm);
    //realms.add(myRealm2);
    securityManager.setRealms(realms);
    securityManager.setSessionManager(sessionManager);
    securityManager.setRememberMeManager(rememberMeManager);
    securityManager.setCacheManager(ehCacheManager);
    return securityManager;
}


5、启动项目,测试权限缓存。

目录
相关文章
|
21天前
|
算法
基于GA遗传优化的混合发电系统优化配置算法matlab仿真
**摘要:** 该研究利用遗传算法(GA)对混合发电系统进行优化配置,旨在最小化风能、太阳能及电池储能的成本并提升系统性能。MATLAB 2022a用于实现这一算法。仿真结果展示了一系列图表,包括总成本随代数变化、最佳适应度随代数变化,以及不同数据的分布情况,如负荷、风速、太阳辐射、弃电、缺电和电池状态等。此外,代码示例展示了如何运用GA求解,并绘制了发电单元的功率输出和年变化。该系统原理基于GA的自然选择和遗传原理,通过染色体编码、初始种群生成、适应度函数、选择、交叉和变异操作来寻找最优容量配置,以平衡成本、效率和可靠性。
|
10天前
|
算法 安全 数据安全/隐私保护
支付系统---微信支付09------数字签名,现在Bob想要给Pink写一封信,信件的内容不需要加密,怎样能够保证信息的完整性,使用信息完整性的主要手段是摘要算法,散列函数,哈希函数,H称为数据指纹
支付系统---微信支付09------数字签名,现在Bob想要给Pink写一封信,信件的内容不需要加密,怎样能够保证信息的完整性,使用信息完整性的主要手段是摘要算法,散列函数,哈希函数,H称为数据指纹
|
1月前
|
存储 算法 NoSQL
数据结构和算法——哈希查找冲突处理方法(开放地址法-线性探测、平方探测、双散列探测、再散列,分离链接法)
数据结构和算法——哈希查找冲突处理方法(开放地址法-线性探测、平方探测、双散列探测、再散列,分离链接法)
41 1
|
1月前
|
存储 算法
数据结构和算法——了解哈希表(哈希查找、散列的基本思想)
数据结构和算法——了解哈希表(哈希查找、散列的基本思想)
22 0
|
1月前
|
算法 搜索推荐
数据结构和算法——表排序(算法概述、物理排序、复杂度分析,包含详细清晰图示过程)
数据结构和算法——表排序(算法概述、物理排序、复杂度分析,包含详细清晰图示过程)
15 0
|
2月前
|
存储 缓存 算法
【数据结构查找算法篇】----散列查找【实战项目】
【数据结构查找算法篇】----散列查找【实战项目】
56 10
|
2月前
|
缓存 算法 Java
Shiro【散列算法、Shiro会话、退出登录 、权限表设计、注解配置鉴权 】(五)-全面详解(学习总结---从入门到深化)
Shiro【散列算法、Shiro会话、退出登录 、权限表设计、注解配置鉴权 】(五)-全面详解(学习总结---从入门到深化)
90 0
Shiro【散列算法、Shiro会话、退出登录 、权限表设计、注解配置鉴权 】(五)-全面详解(学习总结---从入门到深化)
|
1天前
|
算法 数据安全/隐私保护
基于GA遗传优化算法的Okumura-Hata信道参数估计算法matlab仿真
在MATLAB 2022a中应用遗传算法进行无线通信优化,无水印仿真展示了算法性能。遗传算法源于Holland的理论,用于全局优化,常见于参数估计,如Okumura-Hata模型的传播损耗参数。该模型适用于150 MHz至1500 MHz的频段。算法流程包括选择、交叉、变异等步骤。MATLAB代码执行迭代,计算目标值,更新种群,并计算均方根误差(RMSE)以评估拟合质量。最终结果比较了优化前后的RMSE并显示了SNR估计值。
15 7
|
3天前
|
算法 数据挖掘
MATLAB数据分析、从算法到实现
MATLAB数据分析、从算法到实现
|
10天前
|
机器学习/深度学习 算法 调度
Matlab|基于改进鲸鱼优化算法的微网系统能量优化管理matlab-源码
基于改进鲸鱼优化算法的微网系统能量管理源码实现,结合LSTM预测可再生能源和负荷,优化微网运行成本与固定成本。方法应用于冷热电联供微网,结果显示经济成本平均降低4.03%,提高经济效益。代码包括数据分段、LSTM网络定义及训练,最终展示了一系列运行结果图表。