大家好,我是 V 哥。Apache Shiro 是一个强大且灵活的 Java 安全框架,专注于提供认证、授权、会话管理和加密功能。它常用于保护 Java 应用的访问控制,特别是在 Web 应用中。相比于 Spring Security,Shiro 的设计更简洁,适合轻量级应用,并且在许多方面具有更好的易用性和扩展性,今天 V 哥就来聊聊 Shiro 安全框架。

Shiro 的核心概念

按照惯例,和 V 哥一起来了解一下 Shiro 的核心概念:

  1. Subject

    Subject 是 Shiro 框架中一个核心的接口,表示应用中的“用户”或“实体”,用于交互和存储认证状态。通常通过 SecurityUtils.getSubject() 获取当前的 Subject。它代表了用户的身份信息和权限数据。

  2. SecurityManager

    SecurityManager 是 Shiro 的核心控制器,负责管理所有的安全操作和认证。通过配置 SecurityManager,可以控制用户的认证、授权、会话等管理。

  3. Realm

    Realm 是 Shiro 从数据源获取用户、角色和权限信息的途径。通过实现自定义的 Realm,可以将 Shiro 与数据库、LDAP、文件等数据源整合。Shiro 会把用户的认证和授权数据从 Realm 中获取。

  4. Session

    Shiro 自带会话管理,不依赖于 Servlet 容器提供的会话。即使在非 Web 环境下,也可以使用 Shiro 的会话管理。Shiro 的会话管理提供了更细致的控制,比如会话超时、存储和共享等功能。

  5. Authentication(认证)

    认证是指验证用户身份的过程。Shiro 提供了简单的 API 来实现认证过程,比如 subject.login(token)。在实际应用中,通常通过用户名和密码的组合进行认证,但 Shiro 也支持其他方式(如 OAuth2、JWT 等)。

  6. Authorization(授权)

    授权是指验证用户是否具备某些权限或角色的过程。Shiro 支持基于角色和基于权限的授权,允许更精细的权限控制。通过 subject.hasRolesubject.isPermitted 方法,开发者可以检查用户的角色和权限。

  7. Cryptography(加密)

    Shiro 内置了加密功能,提供对密码和敏感信息的加密和解密支持。它支持多种加密算法,并且在密码存储时支持散列和盐值。

Shiro 的主要功能和优势

V 哥总结几点Shiro 的主要功能和优势,这个在面试时吹牛逼用得到。

  1. 易于集成

    Shiro 的 API 设计简单,易于集成到各种 Java 应用中。开发者可以基于 Shiro 提供的默认实现快速搭建一个基本的安全架构,也可以根据需要自定义各种功能。

  2. 独立的会话管理

    与基于 Web 容器的会话管理不同,Shiro 提供了跨环境的会话管理,可以应用于 Web 和非 Web 的环境,增加了应用的灵活性。

  3. 权限控制简单而灵活

    Shiro 的权限管理可以通过配置文件、注解或代码实现,提供了细粒度的访问控制。通过权限和角色的组合,开发者可以非常灵活地控制访问权限。

  4. 支持多种数据源

    Shiro 可以从多种数据源(如数据库、LDAP、文件等)获取用户和权限信息,方便与各种现有系统整合。

  5. 支持 Web 和非 Web 环境

    Shiro 不仅可以在 Web 应用中使用,也支持在桌面应用或微服务等环境中使用。

Shiro 的基本使用示例

光讲概念不是 V 哥风格,接下来,通过一个典型的 Shiro 应用来了解一下如何使用,包含配置 SecurityManager、配置 Realm、进行认证和授权等步骤。

  1. 配置 Shiro 环境

    可以通过 shiro.ini 文件配置 Shiro,也可以通过代码进行配置。
   [main]
# 配置 SecurityManager
securityManager = org.apache.shiro.mgt.DefaultSecurityManager # 配置 Realm
myRealm = com.wg.MyCustomRealm
securityManager.realms = $myRealm
  1. 创建自定义 Realm

    自定义 Realm 通过继承 AuthorizingRealm 并实现 doGetAuthenticationInfodoGetAuthorizationInfo 方法来提供用户和权限数据。

   public class MyCustomRealm extends AuthorizingRealm {
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 获取用户名和密码等信息,查询数据库进行认证
return new SimpleAuthenticationInfo(username, password, getName());
} @Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 获取用户角色和权限信息
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRole("admin");
info.addStringPermission("user:read");
return info;
}
}
  1. 使用 Shiro 进行认证和授权
   Subject currentUser = SecurityUtils.getSubject();
if (!currentUser.isAuthenticated()) {
UsernamePasswordToken token = new UsernamePasswordToken("username", "password");
try {
currentUser.login(token);
System.out.println("认证成功");
} catch (AuthenticationException ae) {
System.out.println("认证失败");
}
} // 检查权限
if (currentUser.hasRole("admin")) {
//用输出模拟一下哈
System.out.println("用户拥有 admin 角色");
}
if (currentUser.isPermitted("user:read")) {
//用输出模拟一下哈
System.out.println("用户具有 user:read 权限");
}

通过这个简单的案例学习,咱们可以了解 Shiro 的基本使用,但这不是全部,听V哥继续慢慢道来。

场景案例

这点很重要,强调一下哈,Shiro 适合需要简洁易用、安全控制要求灵活的 Java 应用,如中小型 Web 应用、桌面应用、分布式微服务等。对于大型企业应用或需要集成多种认证方式(如 OAuth2、JWT 等)的项目,Spring Security 可能会更合适。

要在微服务架构中实现基于 Apache Shiro 的安全认证和授权,比如一个订单管理系统为例。这个系统包含两个主要服务:

  1. 用户服务:负责用户的注册、登录、认证等操作。
  2. 订单服务:允许用户创建、查看、删除订单,并限制访问权限。

咱们来看一下,这个应该怎么设计呢?

微服务案例设计

在这个场景中,我们需要以下几项核心功能:

  1. 用户认证:用户通过用户名和密码登录。
  2. 权限控制:仅管理员能删除订单,普通用户只能查看和创建订单。
  3. Token机制:使用 JWT Token(JSON Web Token)来管理用户的登录状态,实现无状态认证,使得在分布式环境下不依赖于单一会话。
  4. 跨服务认证:订单服务在接收到请求时,检查并验证用户的身份和权限。

架构和技术选型

  • Spring Boot:用于快速搭建微服务。
  • Shiro:实现认证、授权。
  • JWT:生成和验证 Token,保持无状态认证。
  • Spring Data JPA:访问数据库存储用户和订单数据。

系统结构

+------------------+      +---------------------+
| 用户服务 | | 订单服务 |
| | | |
| 用户注册、登录 | | 查看、创建、删除订单|
+------------------+ +---------------------+
| |
|----用户 Token ------|

步骤:实现微服务中的认证和授权

1. 引入必要的依赖

pom.xml 文件中,添加 Shiro、JWT 和 Spring Data JPA 等依赖:

<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.8.0</version>
</dependency> <dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>

2. 配置 Shiro 与 JWT 过滤器

使用 Shiro 的自定义 JWT 过滤器实现无状态认证,通过 Token 验证用户。

public class JwtFilter extends BasicHttpAuthenticationFilter {

    @Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String token = httpServletRequest.getHeader("Authorization"); if (StringUtils.isBlank(token)) {
return false;
} try {
// 解析 JWT token
JwtToken jwtToken = new JwtToken(token);
getSubject(request, response).login(jwtToken);
return true;
} catch (Exception e) {
return false;
}
}
}

3. 实现自定义 Realm

自定义 Realm,从数据库获取用户和角色信息,并使用 JWT Token 进行无状态认证。

public class JwtRealm extends AuthorizingRealm {

    @Override
public boolean supports(AuthenticationToken token) {
return token instanceof JwtToken;
} @Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String jwtToken = (String) token.getPrincipal(); // 验证 Token
String username = JwtUtil.getUsernameFromToken(jwtToken);
if (username == null) {
throw new AuthenticationException("Token 无效");
} // 查询用户
User user = userService.findByUsername(username);
if (user == null) {
throw new AuthenticationException("用户不存在");
} return new SimpleAuthenticationInfo(jwtToken, jwtToken, getName());
} @Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = JwtUtil.getUsernameFromToken(principals.toString()); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
User user = userService.findByUsername(username); // 添加角色和权限
authorizationInfo.addRole(user.getRole());
authorizationInfo.addStringPermission(user.getPermission()); return authorizationInfo;
}
}

4. 创建 JWT 工具类

编写一个工具类,用于生成和解析 JWT Token。

public class JwtUtil {

    //这里替换一下你自己的secret_key
private static final String SECRET_KEY = "这里打码了"; public static String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1 hour
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
} public static String getUsernameFromToken(String token) {
Claims claims = Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
return claims.getSubject();
} public static boolean isTokenExpired(String token) {
Claims claims = Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
return claims.getExpiration().before(new Date());
}
}

5. 编写用户服务和订单服务接口

用户服务接口

用户服务提供注册和登录 API。

@RestController
@RequestMapping("/user")
public class UserController { @PostMapping("/register")
public ResponseEntity<?> register(@RequestBody User user) {
userService.save(user);
return ResponseEntity.ok("用户注册成功");
} @PostMapping("/login")
public ResponseEntity<?> login(@RequestBody User user) {
User dbUser = userService.findByUsername(user.getUsername());
if (dbUser != null && dbUser.getPassword().equals(user.getPassword())) {
String token = JwtUtil.generateToken(user.getUsername());
return ResponseEntity.ok(token);
}
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("登录失败");
}
}
订单服务接口

订单服务在操作订单时会验证用户的角色和权限。

@RestController
@RequestMapping("/order")
public class OrderController { @GetMapping("/{orderId}")
public ResponseEntity<?> getOrder(@PathVariable Long orderId) {
Subject currentUser = SecurityUtils.getSubject();
if (currentUser.isPermitted("order:read")) {
// 查询订单
return ResponseEntity.ok("订单详情");
}
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("无权限查看订单");
} @DeleteMapping("/{orderId}")
public ResponseEntity<?> deleteOrder(@PathVariable Long orderId) {
Subject currentUser = SecurityUtils.getSubject();
if (currentUser.hasRole("admin")) {
// 删除订单
return ResponseEntity.ok("订单已删除");
}
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("无权限删除订单");
}
}

最后

这个案例中咱们通过如何使用 Shiro、JWT 和 Spring Boot 来构建一个无状态的微服务认证授权机制。通过 Shiro 实现用户认证和权限控制,使用 JWT 实现无状态 Token 验证。在轻量级的分布式微服务应用中,是不是使用 Shiro 感觉更加清爽呢,欢迎评论区一起讨论,关注威哥爱编程,爱上Java,一辈子。

适合才最美:Shiro安全框架使用心得的更多相关文章

  1. shiro安全框架

    原文:http://blog.csdn.net/boonya/article/details/8233303 可能大家早先会见过 J-security,这个是 Shiro 的前身.在 2009 年 3 ...

  2. Shiro安全框架【快速入门】就这一篇!

    Shiro 简介 照例又去官网扒了扒介绍: Apache Shiro™ is a powerful and easy-to-use Java security framework that perfo ...

  3. SpringBoot集成Shiro安全框架

    跟着我的步骤:先运行起来再说 Spring集成Shiro的GitHub:https://github.com/yueshutong/shiro-imooc 一:导包 <!-- Shiro安全框架 ...

  4. Springboot整合Shiro安全框架

    最近在学习Springboot,在这个过程中遇到了很多之前都没有技术知识,学习了一阵子,稍微总结一些. ---- Shiro框架 shiro框架,是一个相对比较简便的安全框架,它可以干净利落地处理身份 ...

  5. (转) shiro权限框架详解06-shiro与web项目整合(上)

    http://blog.csdn.net/facekbook/article/details/54947730 shiro和web项目整合,实现类似真实项目的应用 本文中使用的项目架构是springM ...

  6. SpringBoot学习笔记(五):SpringBoot集成lombok工具、SpringBoot集成Shiro安全框架

    SpringBoot集成lombok工具 什么是lombok? 自动生成setget方法,构造函数,打印日志 官网:http://projectlombok.org/features/index. 平 ...

  7. Shiro 安全框架详解二(概念+权限案例实现)

    Shiro 安全框架详解二 总结内容 一.登录认证 二.Shiro 授权 1. 概念 2. 授权流程图 三.基于 ini 的授权认证案例实现 1. 实现原理图 2. 实现代码 2.1 添加 maven ...

  8. thymeleaf模板引擎shiro集成框架

    shiro权限框架.前端验证jsp设计.间tag它只能用于jsp系列模板引擎. 使用最近项目thymeleaf作为前端模板引擎,采用HTML档,未出台shiro的tag lib,假设你想利用这段时间s ...

  9. shiro权限框架(一)

    不知不觉接触shiro安全框架都快三个月了,这中间配合项目开发踩过无数的坑.现在回想总结下,也算是一种积累,一种分享.中间有不够完美的地方或者不好的地方,希望大家指出来能一起交流.在这里谢谢开涛老师的 ...

  10. Shiro权限框架简介

    http://blog.csdn.net/xiaoxian8023/article/details/17892041   Shiro权限框架简介 2014-01-05 23:51 3111人阅读 评论 ...

随机推荐

  1. 原生js操作dom的总结

    一.学习DOM之前需要知道的 1.什么是window? window:是一个全局对象, 代表浏览器中一个打开的窗口, 每个窗口都是一个window对象 2.什么是document?         d ...

  2. 2023上海理工大学校内选拔赛A-D题

    前言 不要在意标题,既然是随记,就随性点() 今天参加了2023年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(同步赛)_ACM/NOI/CSP/CCPC/ICPC算法编程 ...

  3. kubernetes中集成istio出现拉取配置中心数据失败导致服务启动失败 荐

    由于在k8s使用了grpc,所以这里我们集成istio来实现http2的自动发现以及负载均衡,但是随着节点增加,istio之前同步配置时间边长导致第一次启动时,服务启动拉取配置时istio却还没初始化 ...

  4. 我是如何使用 vue2+element-ui 处理负责表单,避免单文件过大的问题

    引言 在工作中我经常需要处理一些复杂.动态表单,但是随着需求不断迭代,我们也许会发现曾经两三百行的.vue文件现在不知不觉到了两千行,三千行,甚至更多... 这对于一个需要长期维护的项目,无疑是增加了 ...

  5. SSM_Spring+SpringMVC+MyBatis学习

    没听过的重点部分 springSecurity 4.0开始默认打开_csrf防护,但是会导致403 forbidden问题,所以可以关闭,但是关了就没有csrf防护了 其中还有传递的token和加密的 ...

  6. pyinstall通过配置.spec文件引用资源文件

    pyinstall通过配置.spec文件引用资源文件 pyinstall可以自动将所有依赖的.py文件连接起来编译成一个可执行exe文件,但是如果在程序中 使用了外部资源,如图片,或者是其它的配置文件 ...

  7. 怎么在Windows操作系统部署阿里开源版通义千问(Qwen2)

    怎么在Windows操作系统部署阿里开源版通义千问(Qwen2) |  原创作者/编辑:凯哥Java                            |  分类:人工智能学习系列教程 GitHu ...

  8. 测距技术 超声波、毫米波、激光雷达LIDAR

    超声波 技术成熟,成本之选 声波传输慢,高速时误差大 超声波雷达有40kHz.48kHz和58kHz三种,频率越高,灵敏度越高,探测角度越小.在工作状态,通过收发超声波,超声波雷达能以1-3cm精度测 ...

  9. spark 解析 kafka message

    备用 https://databricks.com/blog/2018/11/30/apache-avro-as-a-built-in-data-source-in-apache-spark-2-4. ...

  10. 暑假集训SCP提高模拟10

    我(看着百度百科):我已经知道这场谁组的题了 CTH: 谁 我:你想想,能在模拟赛里塞四道数学题还玩邦的,还能有谁 CTH: 我不知道 我:我不知道 CTH: 我知道了 我:我知道了 我:我是 Bob ...