Shiro认证框架

目录

概述

认证授权及鉴权

Shiro框架的核心组件

基本流程

spring boot+shiro+mybatisPlus+...实现用户登录

step1:准备工作

(1)坐标

(2)连接数据库

(3)JavaBean

(4)dao数据访问层

 (5)密码工具类 DigestsUtil

 (6)配置类

step2:认证功能

step3:授权鉴权


概述

shiro是apache下一个开源框架,它将软件系统的安全认证功能抽离出来,组成一个通用的安全认证框架,其功能主要有身份认证,授权鉴权,会话管理等功能。

认证授权及鉴权

对于认证授权及鉴权,可以通过这样一个例子来理解,比如说我买了一张去国外的机票,现在要登机,那我在取机票的时候,出示的身份证就是认证的过程,工作人员在核实你确实是本人之后,会把机票给你,这个就是授权,当你拿着张机票去登记的时候,工作人员还要查你的机票,看你是不是我这个航班的机票,这个就是鉴权。理解之后,再看下面的概念就很具体了。

身份认证是指判断一个用户是否为合法用户的过程,最常用的身份认证方式是系统通过判断用户输入的用户名密码和数据库中存储的用户名密码是否一致。由此确认该用户是否为合法用户。

授权也叫访问控制,它是指控制谁能够访问哪些资源。用户认证成功后,系统会为其分配对应的权限,访问资源时,会校验其是否有权限访问这个校验的过程就是鉴权

Shiro框架的核心组件

  • Subject(主体)

即外部应用与subject进行交互,subject将用户作为当前操作的主体,这个主体:可以是一 个通过浏览器请求的用户,也可能是一个运行的程序 。比如说我今天要做一个登录功能的认证,那我的Subject就是当前登录的用户。

  • SecurityManager(权限管理器)

权限管理器是Shiro的核心,负责管理所有Subject并通过Authenticator完成认证,以及Authorizer完成授权。

  • Authenticator(认证器)

登录时进行身份认证

  • Authorizer(授权器)

当用户通过认证,访问资源时,对用户们进行授权操作

  • Realm(数据源)

Realm用于完成数据库的读取,并在其中完成授权校验相关操作

基本流程

1、首先调用Subject.isPermitted/hasRole接口,其会委托给SecurityManager。

2、SecurityManager接着会委托给内部组件Authorizer;

3、Authorizer再将其请求委托给我们的Realm去做;Realm才是真正干活的;

4、Realm将用户请求的参数封装成权限对象。再从我们重写的doGetAuthorizationInfo方法中获取从 数据库中查询到的权限集合。

5、Realm将用户传入的权限对象,与从数据库中查出来的权限对象,进行一一对比。如果用户传入的 权限对象在从数据库中查出来的权限对象中,则返回true,否则返回false。 进行授权操作的前提:用户必须通过认证。

OK,理论结束,实践开始。。。。

spring boot+shiro+mybatisPlus+...实现用户登录

step1:准备工作

在这一部分需要先搭建一个项目的基本框架,与数据库的交互以及数据库表。在数据库方面一共需要五张表,表的结构在级联查询中已经提到,这里不再赘述,链接附在这里CSDN

 需要特别关注一点的是,对于表中密码这部分的数据,我使用sha-1算法进行了加密,一部分原因是为了安全系数更高些,另一部分原因是shiro框架支持多种算法,例如sha系列算法,以及md5Hash,md2Hash,在这里刚好也使用一下。

(1)坐标

首先需要搭建一个springBoot 项目,然后添加需要的坐标,比如数据持久层的mybatisPlus,管理javaBean的lombok,以及shiro框架相关坐标

 <properties><java.version>1.8</java.version><shiro.version>1.3.2</shiro.version></properties><dependencies><!--mybatis--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-web</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-ehcache</artifactId><version>${shiro.version}</version></dependency></dependencies>
(2)连接数据库

在resource资源文件下的application.properties文件中配置4想数据库连接的基本信息

(3)JavaBean

作用:ORM架构中的O,与数据库表中的字段进行一一对应。

在数据库中我们设计了5张表,但在实体类这里,不涉及关系表,关系表只在查数据的时候使用,比如我在判断该用户有没有某种权限的时候,根据登录用户输入的用户名查询用户的基本信息,拿着基本信息中的id查询用户权限,这个时候就需要使用到关系表,

 

(4)dao数据访问层

数据的交互基于两个查询操作,一个是查询基本信息也就是user表总的信息,另一个是查询详细信息,包括角色信息和权限信息

 

 (5)密码工具类 DigestsUtil

作用:获取明文密码的密文和盐值,这是由于数据库中没有数据,需要先造几条数据供使用

对于输入的明文,在获取密文密码前需要先获取盐值,所以调用generateSalt方法生成随机的盐值密文。其次调用show方法进行加密。然后存到map集合中进行返回,到这里我们需要做的就是把数据存到数据库中。

public class DigestsUtil {
//确定要使用的加密算法public static final String SHA1 = "SHA-1";
//加密次数public static final Integer COUNTS =369;/*** @Description sha1方法,根据明文和盐值进行加密* @param input 需要散列字符串* @param salt 盐字符串* @return*/public static String show(String input, String salt) {return new SimpleHash(SHA1, input, salt,COUNTS).toString();}/*** @Description 随机获得salt字符串* @return*/public static String generateSalt(){SecureRandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();return randomNumberGenerator.nextBytes().toHex();}/*** @Description 生成密码字符密文和salt密文* @param* @return*/public static Map<String,String> entryptPassword(String passwordPlain) {Map<String,String> map = new HashMap<>();String salt = generateSalt();String password =show(passwordPlain,salt);map.put("salt", salt);map.put("password", password);return map;}public static void main(String[] args) {
//用户测试数据String name = "xixi";String pwd = "12345";Map map = entryptPassword(pwd);System.out.println(map.toString());}
}
 (6)配置类

作用:定义shiro框架的基本配置,包括拦截规则,登录页面等等,具体功能在方法上有备注

@Configuration
public class ShiroConfiguration {/*** 1.创建shiro自带cookie对象*/@Beanpublic SimpleCookie sessionIdCookie(){SimpleCookie simpleCookie = new SimpleCookie();simpleCookie.setName("ShiroSession");return simpleCookie;}//2.创建自定义的realm,用于登录认证和授权@Beanpublic MyRealm getRealm() {return new MyRealm();}/*** 3.创建会话管理器*/@Beanpublic DefaultWebSessionManager sessionManager(){DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();sessionManager.setSessionValidationSchedulerEnabled(false);sessionManager.setSessionIdCookieEnabled(true);sessionManager.setSessionIdCookie(sessionIdCookie());sessionManager.setGlobalSessionTimeout(3600000);return sessionManager;}//4.创建安全管理器@Beanpublic SecurityManager defaultWebSecurityManager() {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();securityManager.setRealm(getRealm());securityManager.setSessionManager(sessionManager());return securityManager;}/*** 5.保证实现了Shiro内部lifecycle函数的bean执行*/@Bean(name = "lifecycleBeanPostProcessor")public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();}/*** 6.开启对shiro注解的支持*   AOP式方法级权限检查*/@Bean@DependsOn("lifecycleBeanPostProcessor")public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);return defaultAdvisorAutoProxyCreator;}/*** 7.配合DefaultAdvisorAutoProxyCreator实现使用注解进行权限校验,例如:@RequireRoles、@RequirePermissions等*/@Beanpublic AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager());return authorizationAttributeSourceAdvisor;}//8.配置shiro的过滤器工厂再web程序中,shiro进行权限控制全部是通过一组过滤器集合进行控制@Beanpublic ShiroFilterFactoryBean shiroFilter() {//1.创建过滤器工厂ShiroFilterFactoryBean filterFactory = new ShiroFilterFactoryBean();//2.设置安全管理器filterFactory.setSecurityManager(defaultWebSecurityManager());//3.通用配置(跳转登录页面,为授权跳转的页面)filterFactory.setLoginUrl("/autherror");//跳转url地址//4.设置过滤器集合//key = 拦截的url地址//value = 过滤器类型Map<String,String> filterMap = new LinkedHashMap<>();//key:请求规则   value:过滤器名称filterMap.put("/login","anon");//当前请求地址可以匿名访问filterMap.put("/user/**","authc");//当前请求地址必须认证之后可以访问//在过滤器工程内设置系统过滤器filterFactory.setFilterChainDefinitionMap(filterMap);return filterFactory;}}

至此,准备阶段就结束了,可以进行shiro框架功能的测试。

step2:认证功能

认证流程在前文已经叙述过,这里不再赘述,下文主要描述怎么利用shiro实现认证。首先用户在登录界面输入用户名和密码,因为我们在数据库里存的是密文,所以需要先判断该用户名和密码,这个时候,根据我们在配置类中自定义的Realm类中的doGetAuthenticationInfo方法进行认证

 @Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//将参数AuthenticationToken 转换为用户名密码令牌UsernamePasswordToken token=(UsernamePasswordToken)authenticationToken;
//获取令牌中的用户名String username = token.getUsername();
//按照该用户名查询数据库,若数据库中没有数据,说明该用户不存在,返回null,若存在,进行验证User user = userService.findUserByName(username);if(user!=null){
//SimpleAuthenticationInfo:该类是shiro提供的对象,可以根据传入的参数进行解密操作
/**参数含义
*参数1:安全对象,后续用于鉴权
*参数2:从数据库中查到的密文密码
*参数3:从数据库中查到的盐值的字节数组
*参数4:realm类名
*/SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), ByteSource.Util.bytes(user.getSalt()), "myRealm");return info;}return null;}

这个时候就有人有问题了,这个参数authenticationToken里面的数据是怎么来传过来的?🆗,解释一下,在我们访问登录页面输入数据时,在控制层中,会先进行判断,若不为空,将数据封装成UsernamePasswordToken对象,再获取Subject对象,调用login方法进行登录验证,否则处理空异常。

 这个时候,又有人会有问题了,之前设置了加密算法和加密次数,那shiro框架在解密的时候怎么知道你用的是哪个加密算法,加密了多少次啊?🆗再解释一下,在Realm类中其实还有一个方法initCredentialsMatcher(),它是用来指导密码的加密算法和迭代次数的,写完后告诉shiro你的这个实现类是谁,shiro就知道该去回调哪个方法了。

step3:授权鉴权

这个功能主要是用户在访问某个功能鉴权的的时候使用,也就说,每当我访问一个新的功能进行鉴权的时候,都需要重新执行授权方法,该方法同样定义在Realm类中

    @Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取认证通过的用户对象User user =  (User) principalCollection.getPrimaryPrincipal();
//根据用户id查询该用户的详细信息User userDetail = userService.findUserDetailById(user.getId());
//定义存储角色的集合HashSet<String> roles = new HashSet<>();
//定义存储权限的集合HashSet<String> perms = new HashSet<>();
//对角色集合进行遍历,将每一个角色对应的的权限存入权限集合for (Role role : userDetail.getRoles()) {for (Permission perm : role.getPermissions()) {perms.add(perm.getCode());}}
//封装角色权限对象返回SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();info.setStringPermissions(perms);info.setRoles(roles);return info;}

 对于后续的鉴权,我使用注解解决

        在资源上使用@RequiresPermissions注解,那么当用户访问该资源时判断用户有没有相应的权限 ,若有,可以访问资源,若无,抛出异常。对于异常情况的处理,使用全局异常处理器@ControllerAdvice进行捕获

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/55782.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一文1500字从0到1搭建 Jenkins 自动化测试平台

Jenkins 自动化测试平台的作用 自动化构建平台的执行流程&#xff08;目标&#xff09;是&#xff1a; 我们将代码提交到代码托管工具上&#xff0c;如github、gitlab、gitee等。 1、Jenkins要能够检测到我们的提交。 2、Jenkins检测到提交后&#xff0c;要自动拉取代码&#x…

Uniapp笔记(七)uniapp打包

一、项目打包 1、h5打包 登录dcloud账户&#xff0c;在manifest.json的基础配置选项中&#xff0c;点击重新获取uniapp应用标识APPID 在manifest.json的Web配置选项的运行的基础路径中输入./ 在菜单栏的发行栏目&#xff0c;点击网站-PC或手机H5 输入网站标题和网站域名&am…

leetcode.105 从前序和中序遍历序列构造二叉树

题目描述&#xff1a; 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一 棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 题目要求&#xff1a; 1 < preorder.length < 3000inorder.length…

软件工程(十四) 设计模式之结构型模式(二)

1、组合模式 简要说明 将对象组合成树形结构以表示“整体-部分”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。 速记关键字 树形目录结构 类图如下 由类图其实可以看出,组合模式就是将具有父子关系的结构,组装形成一棵树,并且根据规范,树干节点和叶子节…

javaee spring依赖注入之spel方式

spring依赖注入之spel方式 <dependency><groupId>org.springframework</groupId><artifactId>spring-expression</artifactId><version>4.3.18.RELEASE</version></dependency>package com.test.pojo;import java.util.List; …

【算法专题突破】双指针 - 快乐数(3)

目录 1. 题目解析 2. 算法原理 3. 代码编写 写在最后&#xff1a; 1. 题目解析 题目链接&#xff1a;202. 快乐数 - 力扣&#xff08;Leetcode&#xff09; 这道题的题目也很容易理解&#xff0c; 看一下题目给的示例就能很容易明白&#xff0c; 但是要注意一个点&#…

MyBatis之动态sql

目录 一、MyBatis动态sql 1.1 是什么 1.2 作用 1.3 优点 1.4 特殊标签 1.5 代码演示 二、#和$的区别 2.1 #使用 2.2 $使用 2.3 综合 2.4 代码演示 三、resultType与resultMap的区别 3.1 关于resultType 3.2 关于resultMap 3.3 两者区别 3.4 代码演示 一、MyBati…

退出屏保前玩一把游戏吧!webBrowser中网页如何调用.NET方法

本文主要以 HackerScreenSaver 新功能的开发经历介绍 webBrowser中网页如何调用.NET方法的过程。 1. 背景 之前开源了一款名为 HackerScreenSaver 的 Windows 屏保程序。该程序具有模拟黑客炫酷界面的特点&#xff0c;用户可以将自定义的网页作为锁屏界面。不久前&#xff0c;…

【C++笔记】C++之类与对象(下)

【C笔记】C之类与对象(下&#xff09; 1、再看构造函数1.1、构造函数的初始化列表1.2、C支持单参数的构造函数的隐式类型转换1.3、匿名对象 2、Static成员2.1、为什么要有静态成员变量&#xff1f;2.2、一个类的静态成员变量属于这个类的所有对象2.3、静态成员函数 3、友元3.1、…

基于体素形态学测量分析(VBM)的工具包比较及其在年龄预测中的应用

摘要 基于体素的形态学测量分析(VBM)通常用于灰质体积(GMV)的局部量化。目前存在多种实现VBM的方法。然而&#xff0c;如何比较这些方法及其在应用中的效用(例如对年龄效应的估计)仍不清楚。这会使研究人员疑惑他们应该在其项目中使用哪种VBM工具包。本研究以用户为中心&#…

基于单片机的智能数字电子秤proteus仿真设计

一、系统方案 1、当电子称开机时&#xff0c;单片机会进入一系列初始化&#xff0c;进入1602显示模式设定&#xff0c;如开关显示、光标有无设置、光标闪烁设置&#xff0c;定时器初始化&#xff0c;进入定时器模式&#xff0c;如初始值赋值。之后液晶会显示Welcome To Use Ele…

摆动序列【贪心算法】

摆动序列 如果连续数字之间的差严格地在正数和负数之间交替&#xff0c;则数字序列称为 摆动序列 。第一个差&#xff08;如果存在的话&#xff09;可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。 class Solution {public int wiggleMaxLength(int…

老胡的周刊(第105期)

老胡的信息周刊[1]&#xff0c;记录这周我看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。 &#x1f3af; 项目 Piwigo[2] Piwigo 是一个开源的网络照片库软…

BM80 买卖股票的最好时机(一)

目录 1.题目描述 2.题目分析 3.编写代码 4.总结 这是牛客网上的一道题目 1.题目描述 题目链接&#xff1a;买卖股票的最好时机(一)_牛客题霸_牛客网 (nowcoder.com) 2.题目分析 我们看到这个题目中一个数组表示每一天的股价&#xff0c;那么最大利润怎么算呢&#xff0c…

selenium实现输入数字字母验证码

思路 1. 登录url 2. 获取验证码坐标 3. 根据桌标截图验证码 4. 对验证码进行识别 5. 自动输入验证码 测试代码 import os import time from io import BytesIO from PIL import Image from selenium import webdriver from selenium.webdriver.common.by import By impo…

WebGL矩阵变换

目录 变换矩阵&#xff1a;旋转 变换矩阵&#xff1a;平移 44的旋转矩阵 示例代码&#xff1a; gl.uniformMatrix4fv&#xff08;&#xff09;规范 平移&#xff1a;相同的策略 变换矩阵&#xff1a;缩放 变换矩阵&#xff1a;旋转 对于简单的变换&#xff0c;你可以使用…

Elasticsearch实现增删改查

调用elasticsearch通常使用restful风格请求&#xff0c;这里记录一些常用的Java API和Postman Url Java API调用Es 1. 查询总文档数 Testvoid getAllCount() { // RestHighLevelClient clientnew RestHighLevelClient(RestClient.builder(new HttpHost("192.168…

【微服务】02-集成事件与MediatR

文章目录 1.集成事件1.1 定义1.2 集成事件工作原理1.3 总结 2.使用RabbitMQ来实现EventBus2.1 RabbitMQ安装2.2 CAP框架实现RabbitMQ2.2.1 CAP框架实现架构2.2.2 CAP框架实现原理 3.MediatR3.1 使用Mediator实现命令查询职责分离模式(CQRS)3.1.1 核心对象 3.2 处理领域事件3.2.…

安装部署JavaFX和IDEA添加JavaFX的详细步骤

安装部署JavaFX和IDEA添加JavaFX的详细步骤 一、认识JavaFX二、下载JavaFX三、解压到目录下四、IDEA导入JavaFX五、添加JavaFX的VM选项六、运行命令七、总结一、认识JavaFX JavaFX是Java平台的一个图形用户界面(GUI)工具包,用于创建丰富、交互式和可视化的应用程序。JavaFX提…

Java线程 - 详解(1)

一&#xff0c;创建线程 方法一&#xff1a;继承Thread类 class MyThread extends Thread{Overridepublic void run() {System.out.println("线程1");} }public class Test {public static void main(String[] args) {MyThread myThread new MyThread();myThread.…