Shiro + JWT 进行登录验证

Shiro是一个关于java的安全框架,可以实现用户的认证和授权,简单易用。

首先导入依赖

        <dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.4.1</version></dependency><!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt --><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency><!-- https://mvnrepository.com/artifact/com.auth0/java-jwt --><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>4.4.0</version></dependency>

JwtRealm 验证配置

@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {String jwt = (String) token.getPrincipal();if (jwt == null) {throw new NullPointerException("jwtToken 不允许为空");}// 判断if (!jwtUtil.isVerify(jwt)) {throw new UnknownAccountException();}// 可以获取username信息,并做一些处理String username = (String) jwtUtil.decode(jwt).get("username");logger.info("鉴权用户 username:{}", username);return new SimpleAuthenticationInfo(jwt, jwt, "JwtRealm");
}

在 doGetAuthenticationInfo 方法中,使用 jwtUtil.isVerify(jwt) 方法做验证处理。

JwtFilter 过滤器

public class JwtFilter extends AccessControlFilter {private Logger logger = LoggerFactory.getLogger(JwtFilter.class);/*** isAccessAllowed 判断是否携带有效的 JwtToken* 所以这里直接返回一个 false,让它走 onAccessDenied 方法流程*/@Overrideprotected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {return false;}/*** 返回结果为true表明登录通过*/@Overrideprotected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {HttpServletRequest request = (HttpServletRequest) servletRequest;// 如果你设定的 token 放到 header 中,则可以这样获取;request.getHeader("Authorization");JwtToken jwtToken = new JwtToken(request.getParameter("token"));try {// 鉴权认证getSubject(servletRequest, servletResponse).login(jwtToken);return true;} catch (Exception e) {logger.error("鉴权认证失败", e);onLoginFail(servletResponse);return false;}}/*** 鉴权认证失败时默认返回 401 状态码*/private void onLoginFail(ServletResponse response) throws IOException {HttpServletResponse httpResponse = (HttpServletResponse) response;httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);httpResponse.getWriter().write("Auth Err!");}}

这是一个自定义的 Filter 在 onAccessDenied 获取 request 请求的 token 入参信息,之后调用 getSubject 进行验证处理。

ShiroConfig 启动配置

@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean() {ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();shiroFilter.setSecurityManager(securityManager());shiroFilter.setLoginUrl("/unauthenticated");shiroFilter.setUnauthorizedUrl("/unauthorized");// 添加jwt过滤器Map<String, Filter> filterMap = new HashMap<>();// 设置过滤器【anon\logout可以不设置】filterMap.put("anon", new AnonymousFilter());filterMap.put("jwt", new JwtFilter());filterMap.put("logout", new LogoutFilter());shiroFilter.setFilters(filterMap);// 拦截器,指定方法走哪个拦截器 【login->anon】【logout->logout】【verify->jwt】Map<String, String> filterRuleMap = new LinkedHashMap<>();filterRuleMap.put("/login", "anon");filterRuleMap.put("/logout", "logout");filterRuleMap.put("/verify", "jwt");shiroFilter.setFilterChainDefinitionMap(filterRuleMap);return shiroFilter;
}

这部分是一个设置过滤器和拦截处理,把 jwt 的过滤器设置上,之后拦截指定的 /verify 方法。如果是 /** 就是拦截所有除了 login、logout 配置的其他方法了。通常也是 Web 请求的一些配置操作。

ApiAccessController

@RestController
public class ApiAccessController {private Logger logger = LoggerFactory.getLogger(ApiAccessController.class);@RequestMapping("/authorize")public ResponseEntity<Map<String, String>> authorize(String username, String password) {Map<String, String> map = new HashMap<>();// 模拟账号和密码校验if (!"xyb".equals(username) || !"123".equals(password)) {map.put("msg", "用户名密码错误");return ResponseEntity.ok(map);}// 校验通过生成tokenJwtUtil jwtUtil = new JwtUtil();Map<String, Object> chaim = new HashMap<>();chaim.put("username", username);String jwtToken = jwtUtil.encode(username, 24*60 * 60 * 1000, chaim);map.put("msg", "授权成功");map.put("token", jwtToken);// 返回token码return ResponseEntity.ok(map);}/*** http://localhost:8080/verify?token=*/@RequestMapping("/verify")public ResponseEntity<String> verify(String token) {logger.info("验证 token:{}", token);return ResponseEntity.status(HttpStatus.OK).body("verify success!");}@RequestMapping("/success")public String success(){return "test success by xfg";}
}

 专门用于授权分配Token和验证处理的操作。不过这里的登录目前还没有走数据库,只是简单的验证处理。

测试:http://localhost:8080/authorize?username=xyb&password=123 - 你会获得一个 Token 信息。用于访问 http://localhost/api?token=【添加到这里】 - 这个地址是 Nginx 提供的 

Nginx配置如下:

location /api/ {auth_request /auth;# 鉴权通过后的处理方式proxy_pass http://localhost:8080/success;
}
location = /auth {# 发送子请求到HTTP服务,验证客户端的凭据,返回响应码internal;# 设置参数set $query '';if ($request_uri ~* "[^\?]+\?(.*)$") {set $query $1;}# 验证成功,返回200 OKproxy_pass http://localhost:8080/verify?$query;# 发送原始请求proxy_pass_request_body off;# 清空 Content-Typeproxy_set_header Content-Type "";}

相关类的解释说明;

  1. JwtToken:Token 的对象信息,你可以设置用户ID、用户密码
  2. JwtRealm:一个自定义的验证服务,需要继承 AuthorizingRealm 类。
  3. JwtFilter:自定义的 Filter 过滤器。
  4. JwtUtil:token的创建、解析、验证工具类。
  5. ShiroConfig:Shiro 的一个配置启动类。
  6. ApiAccessController:新增加的API访问准入管理;当访问 OpenAI 接口时,需要进行准入验证。

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

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

相关文章

HarmonyOS开发案例:【电子相册】

介绍 如何实现一个简单的电子相册应用的开发&#xff0c;主要功能包括&#xff1a; 实现首页顶部的轮播效果。 实现页面跳转时共享元素的转场动画效果。 实现通过手势控制图片的放大、缩小、左右滑动查看细节等效果。 相关概念 [Swiper]&#xff1a;滑块视图容器&#x…

W801学习笔记二十二:英语背单词学习应用——下

续上篇&#xff1a; W801学习笔记二十一&#xff1a;英语背单词学习应用——上 五、处理用户交互 由于英语也是采用了和唐诗一样的《三分钟限时挑战》《五十题竞速挑战》《零错误闯关挑战》&#xff0c;所以用户交互的逻辑和唐诗是一样的。所以&#xff0c;我们抽一个基类&a…

Leetcode—138. 随机链表的复制【中等】

2024每日刷题&#xff08;129&#xff09; Leetcode—138. 随机链表的复制 实现代码 /* // Definition for a Node. class Node { public:int val;Node* next;Node* random;Node(int _val) {val _val;next NULL;random NULL;} }; */class Solution { public:Node* copyRan…

海洋行业工业气体检测传感器的重要性

海洋行业是一个广阔而复杂的领域&#xff0c;涉及多个分支和应用&#xff0c;包括浮式生产、储存和卸载&#xff08;FPSO&#xff09;装置、渡轮和潜艇等。这些船舶和设施在执行任务时&#xff0c;都可能遇到各种潜在的气体危害。因此&#xff0c;对于海洋行业来说&#xff0c;…

C++语法|可调用对象与function类型

文章目录 引入function的使用function类型的典型应用 引入 还记得C语言中的函数指针数组吗&#xff1f; 我们通过函数指针数组实现一个&#xff0c;图书管理系统的界面&#xff1a; #include <stdio.h> void doShowAllBooks() {printf("查看所有书籍信息\n")…

STM32接入CH340芯片的初始化进入升级模式(死机)问题处理

目录 1. 问题描述2. 问题分析2.1 CH340G/K 的初始化波形2.2 第1种USB升级电路2.3 第2种USB升级电路2.4 第3种USB升级电路2.5 第4种USB升级电路 3. 总结 1. 问题描述 我所用的CH340G&#xff08;CH340K也用过&#xff09;接在MCU的电路中&#xff0c;在插入CH340G/K 的接插件&a…

Unity EventSystem入门

概述 相信在学习Unity中&#xff0c;一定有被UI事件困扰的时候把&#xff0c;当添加UICanvas的时候&#xff0c;Unity会为我们自动添加EventSystem&#xff0c;这个是为什么呢&#xff0c;Unity的UI事件是如何处理的呢&#xff0c;在使用各个UI组件的时候&#xff0c;一定有不…

Java面试题:如何使用原子类(如AtomicInteger)来实现线程安全的计数

在 Java 中&#xff0c;java.util.concurrent.atomic 包提供了一组原子类&#xff0c;它们用于在多线程环境中执行原子操作。AtomicInteger 是这个包中最基本的原子类之一&#xff0c;它提供了一种线程安全的方式来进行整数的原子操作。以下是如何使用 AtomicInteger 来实现线程…

2269. 找到一个数字的 K 美丽值C++

一个整数 num 的 k 美丽值定义为 num 中符合以下条件的 子字符串 数目&#xff1a; 子字符串长度为 k 。子字符串能整除 num 。 给你整数 num 和 k &#xff0c;请你返回 num 的 k 美丽值。 注意&#xff1a; 允许有 前缀 0 。0 不能整除任何值。 一个 子字符串 是一个字符…

Redis(Redis配置和订阅发布)

文章目录 1.Redis配置1.网络配置1.配置文件位置 /etc/redis.conf2.bind&#xff08;注销支持远程访问&#xff09;1.默认情况bind 127.0.0.1 只能接受本机的访问2.首先编辑配置文件3.进入命令模式输入/bind定位&#xff0c;输入n查找下一个&#xff0c;shift n查找上一个&…

嵌入式实时操作系统在工业领域的应用

嵌入式实时操作系统是面向嵌入式系统的、保证在一定时间限制内完成各种程序的执行并提供资源分配、调度、输入输出控制以及数据管理等服务的软件。嵌入式实时操作系统一般包含核心功能和扩展功能&#xff0c;核心功能主要包含任务管理、任务同步与通信、时钟/定时器管理和中断异…

OpenHarmony 实战开发—— refreshlayout 组件开发学习指南~

1. RefreshLayout_harmonyos 功能介绍 1.1. 组件介绍&#xff1a; RefreshLayout_harmonyos 是一款下拉刷新组件 1.2. 手机模拟器上运行效果&#xff1a; 2. RefreshLayout_harmonyos 使用方法 2.1 在目录 build.gradle 下 implementation project(":refreshlayout_ha…

新能源汽车动力电池热管理-液冷方案应用原理与应用前景简介

前言 动力电池是新能源汽车的核心部件之一&#xff0c;其性能和寿命直接影响着车辆的续航里程和使用成本。液冷方案作为一种常见的动力电池温控解决方案&#xff0c;被广泛应用于新能源汽车领域。本文将详细介绍液冷方案的原理、发展方向以及市场前景。 一、液冷方案的原理 …

Jmeter 中 CSV 如何参数化测试数据并实现自动断言

当我们使用Jmeter工具进行接口测试&#xff0c;可利用CSV Data Set Config配置元件&#xff0c;对测试数据进行参数化&#xff0c;循环读取csv文档中每一行测试用例数据&#xff0c;来实现接口自动化。此种情况下&#xff0c;很多测试工程师只会人工地查看响应结果来判断用例是…

CentOS7编译安装freeswitch1.10.11

由于 FreeSWITCH 更新非常快&#xff0c;请自己查找最新的版本&#xff0c;如&#xff0c;截止 2022年6月4日&#xff0c;最稳定的发行版是&#xff1a;1.10.11 下载源代码&#xff1a; wget https://files.freeswitch.org/freeswitch-releases/freeswitch-1.10.11.-release.…

Liunx打包压缩

注&#xff1a;只用记忆tar和gzip&#xff0c;zip/unzip三种命令与常用参数使用方式&#xff0c;其他做为了解 目录 压缩与打包的概念 常用的压缩与打包工具 tar gzip bzip2 xz 速记总结 1.使用 tar 进行打包 2.使用 tar 结合压缩工具 3.解压缩与解打包 其他压缩工…

Springboot+Vue项目-基于Java+MySQL的影院订票系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

生成gitee公钥

1、打开设置 2、设置SSH公钥 3、生成公钥 4、复制终端输出的公钥&#xff0c;放到这里&#xff0c;标题随便取。 5、测试 ssh -T gitgitee.com 最后用这个测试

帆软报表实现填报报表

我们拿emp表举例 登记信息表 设计一个报表实现对emp表员工的登记 &#xff08;emp表为ORACLE自带用户scott下的一个表&#xff09; 首先&#xff0c;我们设计好填报界面&#xff0c;新建一个普通报表&#xff0c;将emp表中需要的输入一一回应填写进表中。 如下图所示&#xf…

var、let、const的区别

在JavaScript中&#xff0c;var、let、const都是用来声明变量的关键字&#xff0c;但它们之间存在一些关键的区别&#xff0c;这些差异主要体现在作用域、变量提升、重复声明和值的可变性等方面&#xff1a; var 作用域: var声明的变量具有函数作用域或全局作用域。在函数内部…