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"…

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

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

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

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

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

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

在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;可在您的应用程序定…

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

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

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

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

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

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

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

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

About Apple Pay

本文翻译整理自&#xff1a;About Apple Pay &#xff08;更新时间&#xff1a;2017-03-16&#xff09; https://developer.apple.com/library/archive/ApplePay_Guide/index.html#//apple_ref/doc/uid/TP40014764 文章目录 一、关于 Apple Pay1、使用 Apple Pay2、测试 Apple …

SpringBoot3整合SpringDoc实现在线接口文档

写在前面 在现目前项目开发中&#xff0c;一般都是前后端分离项目。前端小姐姐负责开发前端&#xff0c;苦逼的我们负责后端开发 事实是一个人全干&#xff0c;在这过程中编写接口文档就显得尤为重要了。然而作为一个程序员&#xff0c;最怕的莫过于自己写文档和别人不写文档…

【数据结构(邓俊辉)学习笔记】二叉搜索树02——查找、插入和删除

文章目录 1.概述2. 查找2.1 查找&#xff1a;算法2.2 查找&#xff1a;理解2.3 查找&#xff1a;实现2.4 查找&#xff1a;语义 3. 插入3.1 插入&#xff1a;算法3.2 插入&#xff1a;实现 4. 删除4.1 删除&#xff1a;框架4.2 删除&#xff1a;单分支4.3 删除&#xff1a;双分…

Pyqt QCustomPlot 简介、安装与实用代码示例(一)

目录 简介安装实用代码示例带有填充的简单衰减正弦函数及其红色的指数包络线具有数据点的 sinc 函数、相应的误差条和 2--sigma 置信带几种散点样式的演示展示 QCustomPlot 在设计绘图方面的多功能性 结语 所有文章除特别声明外&#xff0c;均采用 CC BY-NC-SA 4.0 许可协议。转…

RERCS系统开发实战案例-Part05 FPM Application的Feeder Class搜索组件的实施

1、通过事务码 SE24对Feeder Class实施 1&#xff09;接口页签的简单说明&#xff1a; ① IF_FPM_GUIBB&#xff1a;通用UI构建块&#xff0c;整个UIBB模块的基础接口&#xff1b; ② IF_FPM_GUIBB_SEARCH&#xff1a;通用搜索UI构建块&#xff0c;搜索组件UIBB的基础接口&…

期末复习GGG-----查找子串

郭的 char *search( char *s, char *t ){int i0;while(s[i]){int j0;if(s[i]t[0]){while(s[ij]t[j]&&t[j]){j;}if(t[j]\0)return si;}i;}return NULL; } AI的 #include <stdio.h> #include <string.h> #define MAXS 30char *search(char *s, char *t);in…

ctfshow web七夕杯

web签到 执行命令没有回显&#xff0c;我们直接写文件就可以了 有字符长度限制 ls />a nl /*>a访问url/api/a下载文件 easy_calc <?phpif(check($code)){eval($result."$code".";");echo($result); }function check(&$code){$num1…