Shiro认证(Authentication)
Shiro简介:特性和架构
Apache Shiro是一个功能强大且易于使用的Java安全(权限)框架,提供了认证、授权、会话管理、加密、与Web集成、缓存等功能。Shiro不仅可以在JavaSE环境中使用,也可以在JavaEE环境中使用。
特性
- Authentication(认证):身份认证/登录,验证用户是否拥有相应的身份。
- Authorization(授权):权限验证,验证某个已认证的用户是否拥有某个权限。
- Session Management(会话管理):管理用户登录后的会话信息。
- Cryptography(加密):保护数据的安全性,如密码加密存储到数据库。
- Web Support:非常容易集成到Web环境。
- Caching:缓存用户信息、角色和权限,提高效率。
- Concurrency:支持多线程应用的并发验证。
- Remember Me:记住我功能,一次登录后下次无需再次登录。
架构
Shiro的架构从外部和内部来看可以分为两个部分:
-
外部架构:
- Subject:代表当前“用户”,与应用交互的任何东西都可以是Subject,如网络爬虫、机器人等。所有Subject都绑定到SecurityManager。
- SecurityManager:安全管理器,所有与安全有关的操作都会与SecurityManager交互,且它管理着所有Subject。它是Shiro的核心,负责与Shiro的其他组件进行交互。
- Realm:域,Shiro从Realm获取安全数据(如用户、角色、权限)。SecurityManager要验证用户身份,需要从Realm获取相应的用户进行比较以确定用户身份是否合法。
-
内部架构:
- Authenticator:认证器,负责主体认证。
- Authorizer:授权器,决定主体是否有权限进行相应的操作。
- SessionManager:管理会话的生存周期。
- SessionDAO:数据访问对象,用于会话的CRUD操作。
- CacheManager:缓存控制器,管理用户、角色、权限等的缓存。
- Cryptography:密码模块,提供常见的加密组件用于加密/解密操作。
认证
Token
在Shiro中,认证指的是识别和证明操作者是一个合法用户。用户如果想要通过认证,需要提供Principal(身份)和Credentials(凭证),从而应用能验证用户身份。这些身份和凭证信息在Shiro框架中以Token(令牌)的概念进行封装。
快速上手
添加依赖:
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>2.0.1</version>
</dependency>
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope>
</dependency>
配置shiro.ini:在resource目录下创建shiro.ini文件配置用户认证数据。
# 对用户信息进行匹配
[users]
# 用户账号和密码
admin=123456
czkt=111111
认证测试:
public class ShiroTester { @Test public void testShiro() { IniRealm realm = new IniRealm("classpath:shiro.ini"); DefaultSecurityManager securityManager = new DefaultSecurityManager(); securityManager.setRealm(realm); SecurityUtils.setSecurityManager(securityManager); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456"); try { subject.login(token); } catch (Exception e) { System.out.println("认证异常:"); e.printStackTrace(); } System.out.println("是否认证成功:" + subject.isAuthenticated()); System.out.println("身份信息:" + subject.getPrincipal()); }
}
认证流程
- 调用
Subject.login(Token)进行登录,其会自动委托给SecurityManager。 SecurityManager负责真正的身份验证逻辑,它会委托给Authenticator进行身份验证。Authenticator可能会委托给相应的AuthenticationStrategy进行多Realm身份验证。Authenticator会把相应的Token传入Realm,从Realm获取身份信息,如果没有返回或抛出异常表示身份验证失败。
记住我 vs 认证
“记住我”功能允许用户在一次登录后,下次访问时无需再次登录。这与普通的认证流程有所不同,因为“记住我”功能通常会在用户的浏览器中存储一个持久化的Cookie,用于在用户下次访问时自动进行身份验证。
注销Logout
用户可以通过调用Subject.logout()方法进行注销操作。这会委托给SecurityManager进行实际的注销逻辑处理。
SpringBoot + Shiro 认证
1. 基础代码调整
首先,你需要在Spring Boot项目中添加Shiro的依赖。这可以通过在pom.xml文件中添加以下依赖来完成:
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.7.1</version> <!-- 请根据需要选择最新版本 -->
</dependency>
2. 自定义Realm
Realm是Shiro与数据源之间的桥梁,用于获取安全数据(如用户、角色和权限)。你需要创建一个自定义的Realm类,并实现AuthorizingRealm接口。
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired; // 假设你有一个UserService用于处理用户相关的业务逻辑
@Component
public class CustomRealm extends AuthorizingRealm { @Autowired private UserService userService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { String username = (String) principals.getPrimaryPrincipal(); // 从数据库中获取用户的角色和权限信息 Set<String> roles = userService.getRolesByUsername(username); Set<String> permissions = userService.getPermissionsByUsername(username); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); authorizationInfo.setRoles(roles); authorizationInfo.setStringPermissions(permissions); return authorizationInfo; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken upToken = (UsernamePasswordToken) token; String username = upToken.getUsername(); // 从数据库中获取用户信息 User user = userService.findByUsername(username); if (user == null) { throw new UnknownAccountException("用户不存在"); } // 将用户信息封装到SimpleAuthenticationInfo中,并返回 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo( username, user.getPassword(), // 假设密码已经加密存储 ByteSource.Util.bytes(user.getSalt()), // 假设使用了盐值加密 getName() ); return authenticationInfo; }
}
3. 配置Shiro相关对象
你需要在Spring Boot的配置类中配置Shiro的相关对象,如SecurityManager和ShiroFilterFactoryBean。
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.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map; @Configuration
public class ShiroConfig { @Bean public SecurityManager securityManager(CustomRealm customRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(customRealm); return securityManager; } @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/login"); // 登录页面URL shiroFilterFactoryBean.setSuccessUrl("/index"); // 登录成功后的跳转页面 shiroFilterFactoryBean.setUnauthorizedUrl("/403"); // 未授权页面URL // 定义过滤器链 Map<String, String> filterChainDefinitionMap = new HashMap<>(); filterChainDefinitionMap.put("/static/**", "anon"); // 静态资源无需认证 filterChainDefinitionMap.put("/login", "anon"); // 登录页面无需认证 filterChainDefinitionMap.put("/**", "authc"); // 其他URL都需要认证 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public FilterRegistrationBean<DelegatingFilterProxy> delegatingFilterProxy() { FilterRegistrationBean<DelegatingFilterProxy> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new DelegatingFilterProxy("shiroFilter")); registrationBean.addUrlPatterns("/*"); return registrationBean; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; }
}
4. IndexController重写登录方法
你需要创建一个控制器来处理登录请求。
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam; @Controller
public class IndexController { @GetMapping("/login") public String login() { return "login"; // 返回登录页面 } @PostMapping("/login") public String login(@RequestParam("username") String username, @RequestParam("password") String password, Model model) { Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, password); try { subject.login(token); return "redirect:/index"; // 登录成功后重定向到首页 } catch (Exception e) { model.addAttribute("error", "用户名或密码错误"); return "login"; // 登录失败返回登录页面 } } @GetMapping("/index") public String index() { return "index"; // 返回首页 } @GetMapping("/403") public String accessDenied() { return "403"; // 返回未授权页面 }
}
5. 测试认证登录
现在,你可以启动Spring Boot应用程序,并访问/login页面来测试登录功能。输入正确的用户名和密码后,你应该会被重定向到/index页面。如果输入错误的用户名或密码,你应该会看到登录页面上的错误信息。
确保你的UserService和数据库配置正确,以便能够正确地获取和验证用户信息。此外,你还需要配置一个视图解析器(如Thymeleaf或JSP)来渲染登录页面、首页和未授权页面。
相关文章:
Shiro认证(Authentication)
Shiro简介:特性和架构 Apache Shiro是一个功能强大且易于使用的Java安全(权限)框架,提供了认证、授权、会话管理、加密、与Web集成、缓存等功能。Shiro不仅可以在JavaSE环境中使用,也可以在JavaEE环境中使用。 特性 …...
Qt和c++面试集合
目录 Qt面试 什么是信号(Signal)和槽(Slot)? 什么是Meta-Object系统? 什么是Qt的MVC模式? 1. QT中connect函数的第五个参数是什么?有什么作用? 3. 在QT中ÿ…...
Spark 3.3.x版本中的动态分区裁剪(DPP,Dynamic Partition Pruning)的实现及应用剖析
文章目录 Dynamic Partition Pruning(DPP)的作用DPP生效的一些要点DPP生效的简单SQL示例DPP生效SQL的解析示例Deduplicate Correlated SubqueryRewrite Predicates as JoinRewrite Join With Dynamic SubqueryRewrite Dynamic Subquery as Dynamic Expre…...
Android 各国语言value文件夹命名规则
中文 values-zh英语values-en 阿拉伯语 values-ar 保加利亚语 values-bg加泰罗尼亚语values-ca 捷克语 values-cs 丹麦语 values-da 德语 values-de 希腊语 values-el 西班牙语 values-es 芬兰语 values-fi 法语 values-fr 希伯来语 values-iw 印地语 values-hi 克罗里亚语 …...
深入理解Redis锁与Backoff重试机制在Go中的实现
文章目录 流程图Redis锁的深入实现Backoff重试策略的深入探讨结合Redis锁与Backoff策略的高级应用具体实现结论 在构建分布式系统时,确保数据的一致性和操作的原子性是至关重要的。Redis锁作为一种高效且广泛使用的分布式锁机制,能够帮助我们在多进程或分…...
uniapp-小程序开发0-1笔记大全
uniapp官网: https://uniapp.dcloud.net.cn/tutorial/syntax-js.html uniapp插件市场: https://ext.dcloud.net.cn/ uviewui类库: https://www.uviewui.com/ 柱状、扇形、仪表盘库: https://www.ucharts.cn/v2/#/ CSS样式&…...
Go语言数据库操作深入讲解
go操作MySQL 使用第三方开源的mysql库: github.com/go-sql-driver/mysql (mysql驱动)github.com/jmoiron/sqlx (基于mysql驱动的封装) 命令行输入 : go get github.com/go-sql-driver/mysqlgo get github.com/jmoiron/sqlx Insert操作 登录后复制 // 连接Mysql data…...
搜维尔科技:SenseGlove Nova 2触觉反馈手套开箱测评
SenseGlove Nova 2触觉反馈手套开箱测评 搜维尔科技:SenseGlove Nova 2触觉反馈手套开箱测评...
步步精科技诚邀您参加2024慕尼黑华南电子展
尊敬的客户: 我们诚挚地邀请您参加即将于2024年10月14日至10月16日在深圳国际会展中心 (宝安新馆)举办的慕尼黑华南电子展(electronica South China)。本届将聚焦人工智能、数据中心、新型储能、无线通信、硬件安全、新能源汽车、第三代半导…...
OPC UA与PostgreSQL如何实现无缝连接?
随着工业4.0的推进,数据交换和集成在智能制造中扮演着越来越重要的角色。OPC UA能够实现设备与设备、设备与系统之间的高效数据交换。而PostgreSQL则是一种强大的开源关系型数据库管理系统,广泛应用于数据存储和管理。如何将OPC UA与PostgreSQL结合起来&…...
C语言[斐波那契数列2]
本篇文章讲述前一篇文章的细节,方便大家进行代码的运算。 本次代码题为: 输出斐波那契数列的前20位数,每行4位数。 详细解释: 在 main 函数中,首先定义了循环变量 i 和用于存储斐波那契数列项的三个长整型变量 f1 、 f2 和 temp 。其…...
八、Linux之实用指令
1、指定运行级别 1.1 基本介绍 运行级别说明 0 :关机 1 :单用户【找回丢失密码】 2:多用户状态没有网络服务(用的非常少) 3:多用户状态有网络服务(用的最多) 4:系统未使…...
2024_E_100_连续字母长度
连续字母长度 题目描述 给定一个字符串,只包含大写字母,求在包含同一字母的子串中,长度第 k 长的子串的长度,相同字母只取最长的那个子串。 输入描述 第一行有一个子串(1<长度<100),只包含大写字母。 第二行为…...
清空redo导致oracle故障恢复---惜分飞
客户由于空间不足,使用> redo命令清空了oracle的redo文件 数据库挂掉之后,启动报错 Fri Oct 04 10:32:57 2024 alter database open Beginning crash recovery of 1 threads parallel recovery started with 31 processes Started redo scan Errors in file /home/oracle…...
VAE(与GAN)
VAE 1. VAE 模型概述 变分自编码器(Variational Autoencoder, VAE)是一种生成模型,主要用于学习数据的潜在表示并生成新样本。它由两个主要部分组成:编码器和解码器。 编码器:将输入数据映射到潜在空间,…...
【高等数学】多元微分学(二)
隐函数的偏导数 二元方程的隐函数 F ( x , y ) 0 F(x,y)0 F(x,y)0 推出隐函数形式 y y ( x ) yy(x) yy(x). 欲求 d y d x \frac{d y}{d x} dxdy 需要对 F 0 F0 F0 两边同时对 x x x 求全导 0 d d x F ( x , y ( x ) ) ∂ F ∂ x d x d x ∂ F ∂ y d y d x ∂ F…...
.NET 中的 Web服务(Web Services)和WCF(Windows Communication Foundation)
一、引言 在当今数字化时代,不同的软件系统和应用程序之间需要进行高效、可靠的通信与数据交换。.NET 框架中的 Web 服务和 WCF(Windows Communication Foundation)为此提供了强大的技术支持。它们在构建分布式应用程序、实现跨平台通信以及…...
Linux小知识2 系统的启动
我们在上文中介绍了文件系统,提到了Linux的文件系统存在一个块的概念,其中有一个特殊的块:引导块。这和我们这里要讲的系统启动有关。 BIOS 基本输入输出系统,基本上是一个操作系统最早实现也是最早运行的第一个程序。是一个比较…...
Oracle-19g数据库的安装
简介 Oracle是一家全球领先的数据库和云解决方案提供商。他们提供了一套完整的技术和产品,包括数据库管理系统、企业级应用程序、人工智能和机器学习工具等。Oracle的数据库管理系统是业界最受欢迎和广泛使用的数据库之一,它可以管理和存储大量结构化和…...
Dubbo快速入门(二):第一个Dubbo程序(附源码)
文章目录 一、生产者工程0.目录结构1.依赖2.配置文件3.启动类4.生产者服务 二、消费者工程0.目录结构1.依赖2.配置文件3.启动类4.服务接口5.controller接口 三、测试代码 本博客配套源码:gitlab仓库 首先,在服务器上部署zookeeper并运行,可以…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
