【Shiro】Shiro 的学习教程(五)之 SpringBoot 集成 Shiro + JWT

与 Spring 集成:与 Spring 集成
与 SpringBoot 集成:与 SpringBoot 集成

1、SpringBoot + Shiro + Jwt

①:引入 pom.xml

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional>
</dependency>
<!-- shiro -->
<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-starter</artifactId><version>1.5.3</version>
</dependency>
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.4.0</version>
</dependency>
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.75</version>
</dependency>

②:配置信息 yml:

spring:redis:host: localhostport: 6379password:timeout: 2000slettuce:pool:max-active: 8  max-wait: -1ms max-idle: 8    min-idle: 0 

③:JWT 工具类 JwtUtil

@Slf4j
public class JwtUtil {private static final long EXPIRE_TIME = 30 * 60 * 1000;public static String sign(String username, String secret) {Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);Algorithm algorithm = Algorithm.HMAC256(secret);// 附带username信息return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);}public static String getUsername(String token) {try {DecodedJWT jwt = JWT.decode(token);return jwt.getClaim("username").asString();} catch (JWTDecodeException e) {return null;}}public static boolean verify(String token, String username, String secret) {try {//根据密码生成JWT效验器Algorithm algorithm = Algorithm.HMAC256(secret);JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build();//效验TOKENDecodedJWT jwt = verifier.verify(token);log.info("登录验证成功!");return true;} catch (Exception exception) {log.error("JwtUtil登录验证失败!");return false;}}}

④:重写 token

public class JwtToken implements AuthenticationToken {private String token;public JwtToken(String token) {this.token = token;}@Overridepublic Object getPrincipal() {return token;}@Overridepublic Object getCredentials() {return token;}}

⑤:重写 filter

@Slf4j
public class JwtFilter extends BasicHttpAuthenticationFilter implements Filter {// 对跨域提供支持@Overrideprotected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {HttpServletRequest httpServletRequest = (HttpServletRequest) request;HttpServletResponse httpServletResponse = (HttpServletResponse) response;httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));// 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {httpServletResponse.setStatus(HttpStatus.OK.value());return false;}return super.preHandle(request, response);}// 执行登录认证@Overrideprotected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {try {return executeLogin(request, response);} catch (Exception e) {log.error("JwtFilter过滤验证失败!");return false;}}// 执行登录@Overrideprotected boolean executeLogin(ServletRequest request, ServletResponse response) throws IOException {HttpServletRequest httpServletRequest = (HttpServletRequest) request;String token = httpServletRequest.getHeader("SevenHee-Token");JwtToken jwtToken = new JwtToken(token);// 提交给realm进行登入,如果错误他会抛出异常并被捕获try {getSubject(request, response).login(jwtToken);// 如果没有抛出异常则代表登入成功,返回truereturn true;} catch (AuthenticationException e) {return false;}}// 认证失败时,自定义返回json数据@Overrideprotected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {JSONObject jsonObject = new JSONObject();jsonObject.put("msg", "认证失败");Object parse = JSONObject.toJSON(jsonObject);response.setCharacterEncoding("utf-8");response.getWriter().print(parse);return super.onAccessDenied(request, response);}}

⑥:shiro 配置类

@Configuration
public class ShiroConfig {@Bean(name = "shiroFilter")public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {//创建拦截链实例ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();//设置安全管理器shiroFilterFactoryBean.setSecurityManager(securityManager);//设置拦截器链////设置拦截链mapLinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();//放行请求filterChainDefinitionMap.put("/shiro/getToken", "anon");//自定义过滤器//// 添加自己的自定义拦截器并且取名为jwtMap<String, Filter> filterMap = new HashMap<>(1);filterMap.put("jwt", new JwtFilter());shiroFilterFactoryBean.setFilters(filterMap);//拦截链配置,从上向下顺序执行,一般将jwt过滤器放在最为下边filterChainDefinitionMap.put("/**", "jwt");//配置拦截链到过滤器工厂shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);//登录url、未授权url////设置组登录请求,其他路径一律自动跳转到这里shiroFilterFactoryBean.setLoginUrl("/login");//未授权跳转路径shiroFilterFactoryBean.setUnauthorizedUrl("/notRole");//返回实例return shiroFilterFactoryBean;}// 安全管理器@Beanpublic DefaultWebSecurityManager securityManager(Realm shiroRealm) {//创建默认的web安全管理器DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();//配置shiro的自定义认证逻辑defaultSecurityManager.setRealm(shiroRealm);/** 关闭shiro自带的session,详情见文档* http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29*/DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();defaultSessionStorageEvaluator.setSessionStorageEnabled(false);subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);defaultSecurityManager.setSubjectDAO(subjectDAO);//返回安全管理器实例return defaultSecurityManager;}@Beanpublic Realm shiroRealm(){return new ShiroRealm();}// 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions)@Beanpublic DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();advisorAutoProxyCreator.setProxyTargetClass(true);return advisorAutoProxyCreator;}// 开启aop注解支持@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);return authorizationAttributeSourceAdvisor;}}

⑦:shiro 认证、授权类

@Slf4j
public class ShiroRealm extends AuthorizingRealm {@Autowiredprivate RedisTemplate redisTemplate;// 设置对应的token类型@Overridepublic boolean supports(AuthenticationToken token) {return token instanceof JwtToken;}@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {//权限认证log.info("开始进行权限认证.............");//获取用户名String token = (String) SecurityUtils.getSubject().getPrincipal();String username = JwtUtil.getUsername(token);//模拟数据库校验,写死用户名 test,其他用户无法登陆成功if (!GlobalConstant.USER_NAME.equals(username)) {return null;}//创建授权信息SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();//创建set集合,存储权限HashSet<String> rootSet = new HashSet<>();//添加权限rootSet.add("user:show");rootSet.add("user:admin");//设置权限info.setStringPermissions(rootSet);//返回权限实例return info;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {log.info("开始身份认证.....................");//获取tokenString token = (String) authenticationToken.getCredentials();//创建字符串,存储用户信息String username = null;try {//获取用户名username = JwtUtil.getUsername(token);} catch (AuthenticationException e) {throw new AuthenticationException("heard的token拼写错误或者值为空");}if (username == null) {throw new AuthenticationException("token无效");}// 校验token是否超时失效 & 或者账号密码是否错误if (!jwtTokenRefresh(token, username, GlobalConstant.PASSWORD)) {throw new AuthenticationException("Token失效,请重新登录!");}//返回身份认证信息return new SimpleAuthenticationInfo(token, token, this.getName());}// 刷新tokenpublic boolean jwtTokenRefresh(String token, String userName, String passWord) {String redisToken = (String) redisTemplate.opsForValue().get(token);if (redisToken != null) {if (!JwtUtil.verify(redisToken, userName, passWord)) {String newToken = JwtUtil.sign(userName, passWord);//设置redis缓存redisTemplate.opsForValue().set(token, newToken, GlobalConstant.REDIS_EXPIRE_TIME * 2 / 1000, TimeUnit.SECONDS);}return true;}return false;}}

⑧:常量类

public interface GlobalConstant {// redis 过期时间Integer REDIS_EXPIRE_TIME = 1800000;// 测试用户String USER_NAME = "test";// 测试密码String PASSWORD = "123456";}

⑨:测试接口

@RestController
@RequestMapping("/shiro")
public class ShiroController {@Autowiredprivate RedisTemplate redisTemplate;@RequestMapping("/getToken")public String getToken() {String token = JwtUtil.sign(GlobalConstant.USER_NAME, GlobalConstant.PASSWORD);redisTemplate.opsForValue().set(token, token, GlobalConstant.REDIS_EXPIRE_TIME * 2 / 1000, TimeUnit.SECONDS);return token;}@RequiresPermissions("user:admin")@RequestMapping("/test")public String test() {System.out.println("进入测试,只有带有令牌才可以进入该方法");return "访问接口成功";}}

⑩:postman 测试

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

【网络安全】服务基础第二阶段——第三节:Linux系统管理基础----Linux用户与组管理

目录 一、用户与组管理命令 1.1 用户分类与UID范围 1.2 用户管理命令 1.2.1 useradd 1.2.2 groupadd 1.2.3 usermod 1.2.4 userdel 1.3 组管理命令 1.3.1 groupdel 1.3.2 查看密码文件 /etc/shadow 1.3.4 passwd 1.4 Linux密码暴力破解 二、权限管理 2.1 文件与目…

sping boot 基于 RESTful 风格,模拟增删改查操作

RESTful -> 增&#xff1a;post 删&#xff1a;delete 改: put 查: get RESTful 资源路径&#xff0c;一般以 s 复数结尾 以下是代码示例&#xff1a; package com.example.springboot.controller;import org.springframework.web.bind.annotation.*;RestControll…

Mac+Pycharm配置PyQt6教程

安装包 pip install PyQt6 PyQt6-tools #查看Qt版本 pip show PyQt6 pip show pyqt6-tools 配置扩展工具 QTD(界面设计) Program&#xff1a;/Users/wan/PycharmProjects/NewDemo/venv/lib/python3.11/site-packages/qt6_applications/Qt/bin/Designer.app Working directo…

虚拟机ubuntu配置opencv和opencv_contrib

前期准备 1.下载opencv和opencv_contrib源码 opencv-4.6.0&#xff1a;https://opencv.org/releases/ opencv_contrib-4.6.0&#xff1a;https://github.com/opencv/opencv_contrib 在ubuntu直接下载或者在window上下好传到虚拟机里都可以 自己找个地方把他们解压&#xf…

基于springboot+vue+uniapp的“共享书角”图书借还管理系统小程序

开发语言&#xff1a;Java框架&#xff1a;springbootuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#…

Leetcode69.x的平方根

题目 代码&#xff08;首刷看解析 2024年9月8日&#xff09; 注意相乘越界问题 class Solution { public:int mySqrt(int x) {if (x 0) return 0;if (x 1) return 1;int left 1;int right x / 2;while (left < right) {int mid left (right - left) / 2;if (mid <…

【第0007页 · 数组】数组中重复的数据(如何实现数组的原地修改)

【前言】本文以及之后的一些题解都会陆续整理到目录中&#xff0c;若想了解全部题解整理&#xff0c;请看这里&#xff1a; 第0007页 数组中重复的数据 今天&#xff0c;我们来看一个在实际工作中运用不多&#xff0c;但是对于一些算法题还是有必要的奇技淫巧——数组的原地修…

探索非局部均值滤波在椒盐噪声去除中的应用

在图像处理领域&#xff0c;椒盐噪声是一种常见的干扰&#xff0c;它会导致图像出现随机的黑白像素点&#xff0c;严重影响图像质量。为了解决这一问题&#xff0c;本文将介绍一种有效的去噪技术——非局部均值滤波&#xff08;NLM&#xff09;的改进版本&#xff0c;即NAMF&am…

springboot数据库连接由localhost改成IP以后访问报错500(2024/9/7

步骤很详细&#xff0c;直接上教程 情景复现 一.没改为IP之前正常 二.改完之后报错 问题分析 SQL没开启远程连接权限 解决方法 命令行登入数据库 mysql -u root -p切换到对应数据库 use mysql;设置root用户的连接权限允许其他IP连接数据库 update user set host % whe…

keepalived和lvs高可用集群

keepavlied和lvs高可用集群搭建 主备模式&#xff1a; 关闭防火墙和selinux systemctl stop firewalld setenforce 0部署master负载调度服务器 zyj86 安装ipvsadm keepalived yum install -y keepalived ipvsadm修改主节点配置 vim /etc/keepalived/keepalived.conf! Conf…

240908-Linux设置软连接关联大模型文件

在Linux中&#xff0c;您可以使用ln命令来创建软链接&#xff08;符号链接&#xff09;。软链接是一种特殊类型的文件&#xff0c;它指向另一个文件或目录。以下是如何设置软链接的步骤&#xff1a; 创建软链接 基本语法&#xff1a; ln -s [目标文件或目录] [软链接的名称]示…

驾驭不断发展的人工智能世界

从很多方面来看&#xff0c;历史似乎正在重演。许多企业正争相采用生成式人工智能 (Gen AI)&#xff0c;就像它们争相采用云计算一样&#xff0c;原因也是一样的&#xff1a;效率、成本节约和竞争优势。 然而&#xff0c;与云一样&#xff0c;GenAI 仍是一项发展中的技术&…

Django+Vue3前后端分离学习(一)(项目开始时settings.py里的设置)

一、创建django项目 二、修改settings.py里的配置&#xff1a; 1、修改语言和时区&#xff1a; # 语言编码 LANGUAGE_CODE zh-hansTIME_ZONE UTCUSE_I18N True# 不用时区 USE_TZ False 2、配置数据库&#xff1a; DATABASES {default: {ENGINE: django.db.backends.m…

[数据集][目标检测]街头摊贩识别检测数据集VOC+YOLO格式758张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;758 标注数量(xml文件个数)&#xff1a;758 标注数量(txt文件个数)&#xff1a;758 标注类别…

前端几种常见框架【第一节】

​ 大家好&#xff0c;我是程序员小羊&#xff01; 前言&#xff1a; 最近比较忙&#xff0c;本人在复习软考中级设计考试&#xff0c;所以本系列文从零基础开始复习软考到结束软考&#xff08;计算机技术与软件专业技术资格考试&#xff09;作为国家级职业资格认证考试&#x…

【路径规划】 使用计算机视觉和机器人操纵器绘制肖像

摘要 本项目展示了使用计算机视觉和机械臂绘制肖像的完整流程。系统利用网络摄像头获取肖像图像&#xff0c;经过图像处理后生成路径&#xff0c;然后利用逆向运动学将路径转化为机械臂的运动轨迹&#xff0c;最终在硬件机器人上执行绘制。实验结果表明&#xff0c;该系统能够…

Android Launcher3

一、定义与功能 Android Launcher是Android操作系统中的一个重要组件&#xff0c;它负责管理和呈现用户界面&#xff0c;包括桌面、应用程序抽屉和部件。Launcher不仅为用户提供了一个启动应用程序的入口&#xff0c;还允许用户自定义手机的主屏幕、图标、小部件布局以及一些基…

2023年AI芯片峰会

概述 开幕式 再谈人工智能芯片——魏少军 可重构计算技术的软件定义芯片 生成式AI与大语言模型时代的NVIDIA GPU生态——NVIDIA NN的发展脉络 1989年&#xff0c;证明神经网络可以表示概率的近似&#xff0c;使得其具有强大的数据拟合能力。 模型的各项能力在2020年基本超…

u盘显示需要格式化才能用预警下的数据拯救恢复指南

U盘困境&#xff1a;需要格式化的紧急应对 在数字信息爆炸的时代&#xff0c;U盘作为便携的数据存储介质&#xff0c;承载着我们工作、学习乃至生活中的大量重要资料。然而&#xff0c;当U盘突然弹出“需要格式化才能用”的提示时&#xff0c;这份便捷瞬间转化为焦虑与不安。这…

Java架构师未来篇大模型

目录 1. 大模型的定义2 大模型相关概念区分3 大模型的发展历程4. 大模型的特点5 大模型的分类6 大模型的泛化与微调7 大模型岗位需求8 理解大模型8.1 生活中的比喻8.2 大模型的定义9 大模型工作9.1 数据的积累9.2 模型的训练9.3 预测和应用10 大模型的实际应用10.1 语言处理10.…