springSecurity(二):实现登入获取token与解析token

登入生成token

主要思想

  1. springSecurity使用UsernamePasswordAuthenticationToken类来封装用户名和密码的认证信息

代码实现

发起登入请求后,进入到login()方法

  /*** 在接口中我们通过AuthenticationManager的authenticate方法来进行用户认证,* 所以需要在SecurityConfig中配置把AuthenticationManager注入容器。* @param user* @return*/@Overridepublic ResponseResult login(User user) {//通过AuthenticationManager的authenticate方法来进行用户认证UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword());Authentication authenticate = authenticationManager.authenticate(token);//如果没通过,给出对应的提示if(Objects.isNull(authenticate)){throw new RuntimeException("用户名或密码错误");}//如果通过了,使用userId生成一个jwt,存入ResponseResult返回LoginUser loginUser = (LoginUser)authenticate.getPrincipal();String id = loginUser.getUser().getId().toString();//根据用户id生成tokenString jwt = JwtUtil.createJWT(id);//把完整的用户信息存入redis,使用userId作为keyredisCache.setCacheObject("login:"+id,loginUser);ResponseResult responseResult = new ResponseResult();responseResult.setCode(200);responseResult.setMsg("登入成功");Map<String,String> map = new HashMap<>();map.put("token",jwt);responseResult.setData(map);return responseResult;}


在执行 Authentication authenticate = authenticationManager.authenticate(token);时,会调用security框架的loadUserByUsername方法查询用户信息,这里我们重写loadUserByUsername方法

@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserMapper userMapper;@Autowiredprivate MenuMapper menuMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//查询用户信息LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(User::getUserName,username);User user = userMapper.selectOne(lambdaQueryWrapper);//如果没有查询到用户就抛出异常if (Objects.isNull(user)){throw new RuntimeException("用户名或密码错误");}//查询对应的权限信息List<String> list = menuMapper.selectPermsByUserId(user.getId());//把数据封装成UserDetails返回return new LoginUser(user,list);}
}

这样执行完loadUserByUsername方法之后,就把权限信息封装到LoginUser中

效果展示

调用接口之后返回一个token信息

{"code": 200,"msg": "登入成功","data": {"token": "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJiODhkZmIxZjExMDg0NmZhOTJlN2I5OTM4M2Q3ZTQ5NyIsInN1YiI6IjQiLCJpc3MiOiJ3aHMiLCJpYXQiOjE3MTg2MjQyMTAsImV4cCI6MTcxODYyNzgxMH0.Z-qa-1rD6dIOxKSaeZ_wjHFKs_TY31hFgZnl2Yld4M4"}
}

题外话

看以下UsernamePasswordAuthenticationToken源码的实现思想

public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {}public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer {}

这段代码同时可以参考ArrayList的实现思想

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{ 
}public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
}

思想理论基础

  • 抽象类是一种特殊的类,它的方法体包含抽象方法和非抽象方法
    • 抽象方法是一种没有具体实现的方法,必须在子类被重写实现
    • 非抽象方法是有具体实现的方法,可以在子类中被继承使用
    • 抽象类的主要目的是为了被继承和重写,而不是被实例化
  • 当一个类继承了一个抽象类和实现了一个接口之后,如果抽象类和接口都有方法A(),这个类是否需要实现方法A()呢?
    • 答案是不需要。因为当抽象类和接口中含有相同的方法名、参数列表和返回类型时候,这个类并不需要强制重写这个方法。
    • 接口默认方法和抽象类中的抽象方法是不同的概念,它们可以共存而不会产生冲突

优点

  1. extends抽象类提供了基础实现
    抽象类可以包含部分已实现的方法和成员变量,使子类能够继承这些实现,减少重复代码。例如:
abstract class Animal {String name;void sleep() {System.out.println(name + " is sleeping.");}abstract void makeSound();
}
  1. implements接口提供了灵活性
    接口定义了一组方法,子类必须实现这些方法。这强制子类提供具体实现,同时接口可以用于实现多重继承,因为一个类可以实现多个接口。例如:
interface Pet {void play();
}
  1. 组合使用的话:
    抽象类提供基础功能,接口提供额外功能
public class Dog extends Animal implements Pet {public Dog(String name) {this.name = name;}@Overridevoid makeSound() {System.out.println(name + " says: Woof!");}@Overridepublic void play() {System.out.println(name + " is playing.");}
}
  1. 灵活的接口实现
    通过实现接口,一个类可以被视为实现该接口的对象类型,这使得代码更加灵活和松耦合
public class Main {public static void main(String[] args) {Dog dog = new Dog("Buddy");dog.sleep(); // Animal类的方法dog.makeSound(); // Dog类实现的抽象方法dog.play(); // Pet接口的方法Pet pet = dog; // 可以用接口类型引用对象pet.play(); // 接口的方法}
}
  1. 设计模式的支持
    这种组合模式在策略模式和模板方法模式得到了广泛应用。抽象类可以提供通用的算法结构,接口可以定义可替换的行为。

总结

  • 代码复用:继承抽象类可以重用父类的代码。
  • 灵活性:实现接口可以实现多重继承,提供额外功能。
  • 松耦合:接口使得代码更加灵活和易于扩展。
  • 支持设计模式:这种组合在很多设计模式中被广泛应用,提高代码的可维护性和可扩展性。

请求解析token

前端登入获取token之后,之后其他请求在访问接口时候都需要带上token

主要思想

  • 在SpringSecurity中,会使用默认的FilterSecurityInterceptor来进行权限校验。在FilterSecurityInterceptor中会从SecurityContextHolder获取其中的Authentication,然后获取其中的权限信息。当前用户是否拥有访问当前资源所需的权限。
  • 所以我们在项目中只需要把当前登录用户的权限信息也存入Authentication。然后设置我们的资源所需要的权限即可。

代码实现

开启配置

在SecurityConfig类上加上如下注解

@EnableGlobalMethodSecurity(prePostEnabled = true)

在接口上加@PreAuthorize注解

  /*** 测试* @return*/@RequestMapping("/hello")@PreAuthorize("ex.hasAuthority('sysytem:dept:list')")public String hello(){return "hello";}

重写认证过滤器,解析token

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {@Autowiredprivate RedisCache redisCache;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {//获取tokenString token = request.getHeader("token");if(!StringUtils.hasText(token)){//放行filterChain.doFilter(request,response);return;}//解析tokenString userId;try {Claims claims = JwtUtil.parseJWT(token);userId= claims.getSubject();} catch (Exception e) {throw new RuntimeException("token非法");}//从redis中获取用户信息String redisKey = "login:"+userId;LoginUser loginUser = redisCache.getCacheObject(redisKey);if(Objects.isNull(loginUser)){throw new RuntimeException("用户未登入");}//存入SecurityContextHolder//获取权限信息,封装到Authentication中UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser,null,loginUser.getAuthorities());SecurityContextHolder.getContext().setAuthentication(authenticationToken);//放行filterChain.doFilter(request,response);}
}

效果展示

在header加上token之后可以请求到正确结果
image.png
如果不加token,则会报错401
image.png

后台回复springSecurity获取项目完整代码

搜索框传播样式-白色版

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

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

相关文章

淘宝镜像地址失效

1. 使用nvm安装node时候报错 报错内容 Get "https://npm.taobao.org/mirrors/node/latest/SHASUMS256.txt": tls: failed to verify certificate: x509: certificate has expired or is not yet valid:报错原因 淘宝镜像地址的证书过期了 解决 找到nvm安装的根目…

echarts legend 背景色渐变

问题与本文无关&#xff1a;如果检测软件显示loadsh.js 的版本是4.17.10 装element-ui 2.15.8版本以下&#xff0c;2.15.6经过测试可以 代码&#xff1a; <template><div class"levelMain"><div class"survey-head"><div class"…

vue记录:nextTick

nextTick 是 Vue.js 中的一个核心功能&#xff0c;用于在 DOM 更新完成后执行延迟回调。这在 Vue 的响应式系统中非常有用&#xff0c;因为当数据变化时&#xff0c;Vue 并不立即更新 DOM&#xff0c;而是等待一个“tick”&#xff08;或者叫“微任务”&#xff09;来批量更新。…

RK3568平台(音频篇)声音的数字化和数字音频接口

一.声音信号的数字化 我们应该都知道&#xff0c;声音是一种模拟信号&#xff0c;如果想用于计算机&#xff0c;就必须要将模拟信号转换为数字信号&#xff0c;这样&#xff0c;我们就能在计算机上存储声音了&#xff0c;等待用户想播放的时候&#xff0c;再将数字信号转换为模…

【Java】已解决java.lang.CloneNotSupportedException异常

文章目录 问题背景可能出错的原因错误代码示例正确代码示例注意事项 已解决java.lang.CloneNotSupportedException异常 在Java编程中&#xff0c;java.lang.CloneNotSupportedException是一个常见的运行时异常&#xff0c;它发生在尝试调用对象的clone()方法时&#xff0c;但该…

vlan、vxlan、vpc学习

文章目录 前言VLAN (Virtual Local Area Network)定义工作原理优点应用场景限制 VXLAN (Virtual eXtensible Local Area Network)工作原理优点应用场景与VLAN的区别 VPC (Virtual Private Cloud)定义特点优势应用场景与VLAN/VXLAN的关联 总结 前言 VLAN&#xff08;Virtual Lo…

Linux | grep命令和 find命令有什么区别

如是我闻&#xff1a; 他们俩都是linux系统中具有查找功能的命令&#xff0c;但是grep 和 find 用于不同的目的。grep 用于在文件中查找文本模式&#xff0c;而 find 用于在文件系统中查找文件和目录。下面是它们的主要区别&#xff1a; grep 用途&#xff1a; grep 是用于在…

使用 Vue.js 实现一个电子签名系统

使用 Vue.js 实现一个电子签名系统 电子签名系统在现代应用中越来越普遍&#xff0c;尤其是在文档管理、合同签署等场景中。本文将介绍如何使用 Vue.js 实现一个简单的电子签名系统。 项目初始化 首先&#xff0c;我们需要创建一个新的 Vue.js 项目。如果你还没有安装 Vue C…

有哪些零售O2O应用模式?如何构建O2O闭环生态系统?

在零售业的演变历程中&#xff0c;O2O模式的兴起标志着一个新时代的开始。这种模式以其创新性&#xff0c;将线上的便捷与线下的实体体验完美融合&#xff0c;为消费者带来了前所未有的购物便利和体验丰富性。随着技术的不断进步和消费者需求的日益多样化&#xff0c;O2O模式已…

Go基础编程 - 08 - 结构体

结构体 1. 自定义类型、类型别名1.1. 自定义类型1.2. 类型别名1.3. 类型定义和类型别名的区别 2. 结构体定义3. 结构体初始化4. 指针类型结构体5. 构造函数6. 方法和接收者6.1. 方法定义6.2. 方法调用6.3. 值方法和指针方法6.4. 指针方法使用场景6.5. 任意类型添加方法 7. 结构…

在windows 台式机电脑部署GLM4大模型

参考这篇文章在windows笔记本电脑部署GLM4大模型_16g显卡本地部署glm4-CSDN博客 我的环境&#xff08;PC台式机电脑&#xff1a; 处理器 Intel(R) Core(TM) i9-14900K 3.20 GHz 机带 RAM 32.0 GB (31.8 GB 可用)、32G内存、NVIDIA RTX4080&#xff08;16G&#xff09;…

Ubuntu20.04中复现FoundationPose

Ubuntu20.04中复现FoundationPose 文章目录 Ubuntu20.04中复现FoundationPose1.安装cuda和cudnn2.下载相关资源3.环境配置4.运行model-based demo5.运行ycbv demoReference &#x1f680; 非常重要的环境配置 &#x1f680; ubuntu 20.04cuda 11.8.0cudnn v8.9.7python 3.9.19…

如何理解电流镜负载的差分对的增益

我们知道最普通的电阻负载的差分对的差分增益是-gmRD&#xff0c;如果我们不希望输出是双端的&#xff0c;而是希望单端输出&#xff0c;那么使用电阻负载的差分对会导致增益变为原先的一半&#xff0c;因此引入了电流镜负载的差分对&#xff0c;它可以在保证增益与原先相同的情…

Nuxt快速学习开发 - Nuxt3静态资源Assets

Nuxt 使用两个目录来处理样式表、字体或图像等资产。 public/目录内容按原样在服务器根目录中提供。 assets/目录包含您希望构建工具&#xff08;Vite 或 webpack&#xff09;处理的所有资产。 public/目录 public目录用作静态资产的公共服务器&#xff0c;可在您的应用程序定…

【LeetCode 128】 最长连续子序列

判断前一位数在不在字典中是这道题的关键之处&#xff0c;这样就可以避免重复查找&#xff0c;从而达到O(n) 的时间复杂度。如果没有这个判断&#xff0c;那么时间复杂度最坏也得是O(N^2)级别的。 1. 题目 2. 分析 合理利用数据结构。本题中使用了set来保存数组的元素&#x…

氮化铝上的厚膜高功率片式电阻器

EAK厚膜高功率片式电阻器和氮化铝片式端接非常适合大多数需要在小尺寸封装中实现高导热性的应用。AlN 是 BeO 的理想替代品&#xff0c;具有高功耗且对环境或健康无危害。厚膜技术以非常实惠的价格提供稳定的电阻元件。 高稳定性厚膜电阻元件 AlN衬底材料 标准电阻范围为 10Ω…

5216万!国内自动化巨头,拟剥离旗下子业务

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》 近日&#xff0c;中控技术发布公告称&#xff0c;为进一步优化资产结构和产业布局&#xff0c;提升公司核心竞争力&#xff0c;公司拟将其全资子…

多模态LLM 跨越语言与视觉的边界

一、引言 在数字时代的浪潮中&#xff0c;我们被由语言和视觉等多种模态构成的信息海洋所包围。人类大脑以其卓越的多模态上下文理解能力&#xff0c;在日常任务中游刃有余。然而&#xff0c;在人工智能领域&#xff0c;如何将这种能力赋予机器&#xff0c;尤其是如何在语言模…

计算子网掩码

例题 如果子网掩码是255.255.192.0&#xff0c; 那么下面主机&#xff08;&#xff09;必须通过路由器才能与主机129.23.144.16通信&#xff08; 1分 &#xff09;A.129.23.148.127B. 129.23.191.21C. 129.23.127.222D. 129.23.130.33计算 要确定哪些主机必须通过路由器才能与…

MybatisPlus:高效便捷的Java持久层框架

一、MybatisPlus简介 MybatisPlus&#xff08;简称MP&#xff09;是一个流行的Java持久层框架&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生&#xff0c;旨在简化数据库操作和提高开发效率。MybatisPlus为开发者提供了一套方便的API和…