当前位置: 首页 > news >正文

Shiro认证(Authentication)

Shiro简介:特性和架构

Apache Shiro是一个功能强大且易于使用的Java安全(权限)框架,提供了认证、授权、会话管理、加密、与Web集成、缓存等功能。Shiro不仅可以在JavaSE环境中使用,也可以在JavaEE环境中使用。

特性

  1. Authentication(认证):身份认证/登录,验证用户是否拥有相应的身份。
  2. Authorization(授权):权限验证,验证某个已认证的用户是否拥有某个权限。
  3. Session Management(会话管理):管理用户登录后的会话信息。
  4. Cryptography(加密):保护数据的安全性,如密码加密存储到数据库。
  5. Web Support:非常容易集成到Web环境。
  6. Caching:缓存用户信息、角色和权限,提高效率。
  7. Concurrency:支持多线程应用的并发验证。
  8. Remember Me:记住我功能,一次登录后下次无需再次登录。

架构

Shiro的架构从外部和内部来看可以分为两个部分:

  1. 外部架构

    • Subject:代表当前“用户”,与应用交互的任何东西都可以是Subject,如网络爬虫、机器人等。所有Subject都绑定到SecurityManager。
    • SecurityManager:安全管理器,所有与安全有关的操作都会与SecurityManager交互,且它管理着所有Subject。它是Shiro的核心,负责与Shiro的其他组件进行交互。
    • Realm:域,Shiro从Realm获取安全数据(如用户、角色、权限)。SecurityManager要验证用户身份,需要从Realm获取相应的用户进行比较以确定用户身份是否合法。
  2. 内部架构

    • 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());  }  
}


认证流程

  1. 调用Subject.login(Token)进行登录,其会自动委托给SecurityManager
  2. SecurityManager负责真正的身份验证逻辑,它会委托给Authenticator进行身份验证。
  3. Authenticator可能会委托给相应的AuthenticationStrategy进行多Realm身份验证。
  4. 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的相关对象,如SecurityManagerShiroFilterFactoryBean

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简介&#xff1a;特性和架构 Apache Shiro是一个功能强大且易于使用的Java安全&#xff08;权限&#xff09;框架&#xff0c;提供了认证、授权、会话管理、加密、与Web集成、缓存等功能。Shiro不仅可以在JavaSE环境中使用&#xff0c;也可以在JavaEE环境中使用。 特性 …...

Qt和c++面试集合

目录 Qt面试 什么是信号&#xff08;Signal&#xff09;和槽&#xff08;Slot&#xff09;&#xff1f; 什么是Meta-Object系统&#xff1f; 什么是Qt的MVC模式&#xff1f; 1. QT中connect函数的第五个参数是什么&#xff1f;有什么作用&#xff1f; 3. 在QT中&#xff…...

Spark 3.3.x版本中的动态分区裁剪(DPP,Dynamic Partition Pruning)的实现及应用剖析

文章目录 Dynamic Partition Pruning&#xff08;DPP&#xff09;的作用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策略的高级应用具体实现结论 在构建分布式系统时&#xff0c;确保数据的一致性和操作的原子性是至关重要的。Redis锁作为一种高效且广泛使用的分布式锁机制&#xff0c;能够帮助我们在多进程或分…...

uniapp-小程序开发0-1笔记大全

uniapp官网&#xff1a; https://uniapp.dcloud.net.cn/tutorial/syntax-js.html uniapp插件市场&#xff1a; https://ext.dcloud.net.cn/ uviewui类库&#xff1a; https://www.uviewui.com/ 柱状、扇形、仪表盘库&#xff1a; https://www.ucharts.cn/v2/#/ CSS样式&…...

Go语言数据库操作深入讲解

go操作MySQL 使用第三方开源的mysql库: github.com/go-sql-driver/mysql (mysql驱动)github.com/jmoiron/sqlx (基于mysql驱动的封装) 命令行输入 &#xff1a; go get github.com/go-sql-driver/mysqlgo get github.com/jmoiron/sqlx Insert操作 登录后复制 // 连接Mysql data…...

搜维尔科技:SenseGlove Nova 2触觉反馈手套开箱测评

SenseGlove Nova 2触觉反馈手套开箱测评 搜维尔科技&#xff1a;SenseGlove Nova 2触觉反馈手套开箱测评...

步步精科技诚邀您参加2024慕尼黑华南电子展

尊敬的客户&#xff1a; 我们诚挚地邀请您参加即将于2024年10月14日至10月16日在深圳国际会展中心 &#xff08;宝安新馆&#xff09;举办的慕尼黑华南电子展(electronica South China)。本届将聚焦人工智能、数据中心、新型储能、无线通信、硬件安全、新能源汽车、第三代半导…...

OPC UA与PostgreSQL如何实现无缝连接?

随着工业4.0的推进&#xff0c;数据交换和集成在智能制造中扮演着越来越重要的角色。OPC UA能够实现设备与设备、设备与系统之间的高效数据交换。而PostgreSQL则是一种强大的开源关系型数据库管理系统&#xff0c;广泛应用于数据存储和管理。如何将OPC UA与PostgreSQL结合起来&…...

C语言[斐波那契数列2]

本篇文章讲述前一篇文章的细节&#xff0c;方便大家进行代码的运算。 本次代码题为: 输出斐波那契数列的前20位数&#xff0c;每行4位数。 详细解释: 在 main 函数中&#xff0c;首先定义了循环变量 i 和用于存储斐波那契数列项的三个长整型变量 f1 、 f2 和 temp 。其…...

八、Linux之实用指令

1、指定运行级别 1.1 基本介绍 运行级别说明 0 &#xff1a;关机 1 &#xff1a;单用户【找回丢失密码】 2&#xff1a;多用户状态没有网络服务&#xff08;用的非常少&#xff09; 3&#xff1a;多用户状态有网络服务&#xff08;用的最多&#xff09; 4&#xff1a;系统未使…...

2024_E_100_连续字母长度

连续字母长度 题目描述 给定一个字符串&#xff0c;只包含大写字母&#xff0c;求在包含同一字母的子串中&#xff0c;长度第 k 长的子串的长度&#xff0c;相同字母只取最长的那个子串。 输入描述 第一行有一个子串(1<长度<100)&#xff0c;只包含大写字母。 第二行为…...

清空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 模型概述 变分自编码器&#xff08;Variational Autoencoder, VAE&#xff09;是一种生成模型&#xff0c;主要用于学习数据的潜在表示并生成新样本。它由两个主要部分组成&#xff1a;编码器和解码器。 编码器&#xff1a;将输入数据映射到潜在空间&#xff0c;…...

【高等数学】多元微分学(二)

隐函数的偏导数 二元方程的隐函数 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)

一、引言 在当今数字化时代&#xff0c;不同的软件系统和应用程序之间需要进行高效、可靠的通信与数据交换。.NET 框架中的 Web 服务和 WCF&#xff08;Windows Communication Foundation&#xff09;为此提供了强大的技术支持。它们在构建分布式应用程序、实现跨平台通信以及…...

Linux小知识2 系统的启动

我们在上文中介绍了文件系统&#xff0c;提到了Linux的文件系统存在一个块的概念&#xff0c;其中有一个特殊的块&#xff1a;引导块。这和我们这里要讲的系统启动有关。 BIOS 基本输入输出系统&#xff0c;基本上是一个操作系统最早实现也是最早运行的第一个程序。是一个比较…...

Oracle-19g数据库的安装

简介 Oracle是一家全球领先的数据库和云解决方案提供商。他们提供了一套完整的技术和产品&#xff0c;包括数据库管理系统、企业级应用程序、人工智能和机器学习工具等。Oracle的数据库管理系统是业界最受欢迎和广泛使用的数据库之一&#xff0c;它可以管理和存储大量结构化和…...

Dubbo快速入门(二):第一个Dubbo程序(附源码)

文章目录 一、生产者工程0.目录结构1.依赖2.配置文件3.启动类4.生产者服务 二、消费者工程0.目录结构1.依赖2.配置文件3.启动类4.服务接口5.controller接口 三、测试代码 本博客配套源码&#xff1a;gitlab仓库 首先&#xff0c;在服务器上部署zookeeper并运行&#xff0c;可以…...

OpenClaw技能扩展:基于nanobot开发自定义自动化模块

OpenClaw技能扩展&#xff1a;基于nanobot开发自定义自动化模块 1. 为什么选择nanobot作为技能开发基础 当我第一次尝试为OpenClaw开发自定义技能时&#xff0c;面对庞大的框架和复杂的依赖关系感到无从下手。直到发现nanobot这个轻量级解决方案&#xff0c;才真正找到了适合…...

RViz实战:如何用C++在ROS中动态切换不同形状的物体(含避坑指南)

RViz实战&#xff1a;如何用C在ROS中动态切换不同形状的物体&#xff08;含避坑指南&#xff09; 在机器人开发过程中&#xff0c;RViz作为ROS生态中的三维可视化利器&#xff0c;其核心价值在于让抽象的数据变得直观可见。而Marker消息系统则是实现这种可视化的关键桥梁——它…...

DAMO-YOLO实战:用AI视觉系统做内容安全审核与统计

DAMO-YOLO实战&#xff1a;用AI视觉系统做内容安全审核与统计 1. 引言&#xff1a;当AI视觉遇见内容安全 在数字内容爆炸式增长的今天&#xff0c;如何高效地进行内容审核成为许多平台面临的挑战。传统人工审核不仅效率低下&#xff0c;而且容易因疲劳导致误判。本文将介绍如…...

终极指南:如何让Nautilus、Dolphin等Linux文件管理器拥有macOS Finder般流畅的快捷键体验

终极指南&#xff1a;如何让Nautilus、Dolphin等Linux文件管理器拥有macOS Finder般流畅的快捷键体验 【免费下载链接】kinto Mac-style shortcut keys for Linux & Windows. 项目地址: https://gitcode.com/gh_mirrors/kin/kinto 你是否厌倦了在Linux文件管理器中不…...

遥感智能解译新纪元:GeoSeg破解地物识别效率瓶颈的技术革新

遥感智能解译新纪元&#xff1a;GeoSeg破解地物识别效率瓶颈的技术革新 【免费下载链接】GeoSeg UNetFormer: A UNet-like transformer for efficient semantic segmentation of remote sensing urban scene imagery, ISPRS. Also, including other vision transformers and CN…...

Xilinx Video IP实战:如何将HDMI输入转换为AXI4-Stream(附仿真+上板测试)

Xilinx Video IP实战&#xff1a;HDMI转AXI4-Stream全流程开发指南 在FPGA视频处理系统中&#xff0c;将HDMI等视频输入接口转换为标准化的AXI4-Stream协议是构建复杂视频处理流水线的关键第一步。不同于简单的接口转换&#xff0c;这一过程涉及视频时序解析、数据位宽适配、时…...

ESP32轻量级18650电池电量估算库设计与实现

1. 项目概述Battery_18650_Stats是一款专为 ESP32 平台设计的轻量级嵌入式电池状态计算库&#xff0c;核心目标是在 Arduino IDE 环境下&#xff0c;以最小资源开销、最高工程鲁棒性&#xff0c;实现对单节 18650 锂离子电池&#xff08;Li-ion&#xff09;荷电状态&#xff08…...

[具身智能-125]:RQT(Robot Qt),一个可以全方位监控ROS2系统内部节点工作状态的可视化超级终端!!!

如果说 RViz2 是机器人的“眼睛”&#xff08;看 3D 世界&#xff09;&#xff0c;那么 RQT 就是机器人的“听诊器”和“控制台”。它基于 Qt 框架开发&#xff0c;采用插件化架构&#xff0c;让你能在一个窗口里完成对 ROS2 系统内部状态的全方位监控与调试。为了让你更好地利…...

YOLOv8自定义检测头踩坑记:手把手教你修复‘NotImplementedError: new_detect task‘错误

YOLOv8自定义检测头实战&#xff1a;从报错到修复的深度解析 当你在YOLOv8框架中尝试添加一个名为new_detect的自定义检测头时&#xff0c;突然遇到NotImplementedError: new_detect task错误&#xff0c;这可能会让你感到困惑。本文将带你深入理解YOLOv8的任务调度机制&#x…...

网易云音乐评论数据分析:用Python爬取+可视化热门歌曲情感倾向

网易云音乐评论数据挖掘&#xff1a;从爬取到情感分析的完整实战指南 音乐平台的用户评论蕴含着丰富的情感价值和商业洞察。作为国内领先的音乐社区&#xff0c;网易云音乐的海量评论数据对产品经理优化功能、市场人员分析用户偏好具有重要价值。本文将系统性地介绍如何通过Pyt…...