Java阶段四Day08

Java阶段四Day08

文章目录

  • Java阶段四Day08
    • 关于pom.xml中的版本
    • 关于Session
    • 关于Token
    • 关于JWT
    • 在项目中使用JWT
      • CustomUserDetails
      • UserDetailServiceImpl
      • UserServiceImpl

关于pom.xml中的版本

  • 查看<groupId> 是同一家的只需配一个版本号<version>
  • <artifactId>spring-boot-starter开头的可不写版本号<version>
  • springBoot保证了添加的依赖“开箱即用”即 约定大于配置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j6TePRMv-1687687094756)(../../../AppData/Roaming/Typora/typora-user-images/image-20230625110039742.png)]

关于Session

  • 服务器端的应用程序通常是基于HTTP协议的,HTTP协议本身是一种“无状态"协议,所以,它并不能保存客户端的状态,例如,无法识别客户端的身份,所以,即使同一个客户端多次访问同一个服务器,服务器并不能识别出它就是此前来访的客户端

  • 在开发实践中,大多是需要能够识别客户端身份的,通常可以使用Session机制来解决

  • 当某个客户端首次访问某个服务器端时,将直接发起请求,当服务器端收到此请求时,会在响应时返回一个Session lD值(本质上是一个UUID值),当客户端收到Session lD后,后续的访问都会自动携带此Session ID到服务器端,则服务器端可以根据这个Session ID值来识别客户端的身份。

  • 在服务器端,使用K-V结构的数据表示Session,客户端携带的Session ID就是K-V结构中的Key,所以,每个客户端都可以访问到不同的value,即每个客户端对应的Session数据。

  • Session是存储在服务器端的内存中的数据,而内存资源是相对有限的资源,存储空间相对较小,所以,必然存在清除Session的机制,默认的清除机制是"超时自动清除",即某个客户端最后一次提交请求之后,在多长时间之内没有再次提交请求,服务器端就会清除此客户端对应的Session数据,至于过多久清除Session,没有明确的要求,大多软件的默认时间是15~30分钟,但是,也可以设置为更短或更长的时间。

  • 基于Session的特征,必有一些不足:

    • 不适合存储较大的数据,可以通过规范的开发来避免此问题
    • 不易于应用到集群或分布式系统中,可以通过共享Session来解决此问题
    • 不可以长时间存储数据,无解

关于Token

Token:票据、令牌

当某个客户端向服务器端发起登录的请求时, 将直接发起请求,当服务器端收到此请求时,如果判断登录成功,会在响应时返回一个Token值,当客户端收到Token后,后续的访问都会自动携带此Token到服务器端,则服务器端可以根据这个Token值来识别客户端的身份。

与Session不同,Token是由服务器端的程序(开发者自行编写)生成的一段有意义的数据。例如可以将用户的ID、用户名都存放到Token中,则在后续访问中,客户端携带了Token后,服务器端可以直接从Token中找到相关信息,如用户ID、用户名,从而服务器端的内存中,并不需要持续保存相关信息,所以,Token可以被设置一段非常长的有效期,且不用担心持续性的消耗服务器端内存的问题。

基于Token的特征,可以解决Session能解决的问题,且天生适用于集群或分布式系统,只要集群或分布式系统中的各个服务器具有相同的检查Token和解析Token的程序即可。

关于JWT

JWT:(JSON Web Token) 官网;

每个JWT数据都是由3大部分组成的:

  • Header:声明算法与Token类型
  • Payload:数据
  • Verify Signature:验证签名

在尝试生成和解析JWT之前,需要添加依赖项:

<!--    JJWT (Java JWT)-->
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>

测试

public class JWTTest {String secretKey = "ladnamdsm2ne12[d;mas;camd;a,d[]12ke[12ke";@Testvoid generateToken() {Date date = new Date(System.currentTimeMillis() + 24L * 60 * 60 * 1000 *30);//注 超出Integer上限 加入LMap<String, Object> claims = new HashMap<>();claims.put("id", 81290);claims.put("username", "BoB Doe");String jwt = Jwts.builder()//Header.setHeaderParam("alg", "HS256").setHeaderParam("typ", "JWT")//Payload.setClaims(claims).setExpiration(date)//Verify Signature.signWith(SignatureAlgorithm.HS256, secretKey).compact();System.out.println("jwt = " + jwt);}//eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6OTk3LCJleHAiOjE2ODc3NjMyMDUsInVzZXJuYW1lIjoiSm9obiBEb2UifQ.neXB-DvVoV7YU_etCvgFqCodSk25mv8hAiq2KYyTpV0@Testvoid parseToken() {//String jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6OTk3LCJleHAiOjE2ODc3NjMyMDUsInVzZXJuYW1lIjoiSm9obiBEb2UifQ.neXB-DvVoV7YU_etCvgFqCodSk25mv8hAiq2KYyTpV0";String jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ODEyOTAsImV4cCI6MTY4Nzc2MzgxMCwidXNlcm5hbWUiOiJCb0IgRG9lIn0.rtO2Ifae7B-NtAvZS9Rkm8omzuOaTt-giApzV8giMcQ";//可见请求头不变//JWT 并不是一种可以保护隐私的数据,即使不知道SecretKey JWT数据也会被解析 所以不要存放敏感信息//io.jsonwebtoken.ExpiredJwtException 过期异常//io.jsonwebtoken.SignatureException 签名错误异常//io.jsonwebtoken.MalformedJwtException  格式错误异常Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();System.out.println("claims = " + claims);System.out.println("username = " +claims.get("username",String.class));System.out.println("id = " + claims.get("id"));}
}

在项目中使用JWT

大致分为两个步骤:

  1. 当验证客户端登录信息成功之后,生成JWT数据,并响应到客户端去 >> 相当于“买票”过程,
  2. 客户端自主携带JWT 向服务器端发请求,服务器端尝试接收并解析JWT >> 相当于“验票”过程
  3. 解析成功后得到JWT中的数据信息,将这些信息创建为Authentication对象并存入到SecurityContext中 >> 相当于“进站”过程,

CustomUserDetails

@Getter
@ToString(callSuper = true) //调用父类的toString
@EqualsAndHashCode(callSuper = true)
public class CustomUserDetails extends User {private Long id;private String avatar;public CustomUserDetails(Long id, String username, String password, String avatar,boolean enabled, Collection<? extends GrantedAuthority> authorities) {super(username, password, enabled, true, true, true, authorities);this.id = id;this.avatar = avatar;}
}

UserDetailServiceImpl

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {log.debug("Spring Security框架自动调用UserDetailsService对象,根据用户名获取用户详情");UserLoginInfoVO loginInfo = userRepository.getLoginInfoByUsername(username);log.debug("根据用户名【{}】从数据库中查询用户详情,查询结果:{}", username, loginInfo);if (loginInfo == null) {return null;}List<GrantedAuthority> authorities = new ArrayList<>();List<String> permissions = loginInfo.getPermissionValue();for (String permission : permissions) {SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permission);authorities.add(authority);}//自定义的UserDetailsCustomUserDetails userDetails = new CustomUserDetails(loginInfo.getId(),loginInfo.getUsername(),loginInfo.getPassword(),loginInfo.getAvatar(),loginInfo.getEnable() == 1,authorities);/*    UserDetails userDetails = User.builder().password(loginInfo.getPassword()).username(loginInfo.getUsername()).disabled(loginInfo.getEnable() == 0)     // 账号是否被禁用   优先判断状态,再校验密码.accountLocked(false)   // 账号是否被锁定 当前项目中无此概念,则所以账号都是false.accountExpired(false) //账号是否过期.credentialsExpired(false) //凭证是否过期.authorities(authorities) //后续添加.build();*/log.debug("即将向Spring Security框架返回UserDetails类型的结果:{}" ,userDetails);log.debug("接下来,将由Spring Security框架自动验证用户状态、密码等,以判断是否成功登录!");return userDetails;
}

UserServiceImpl

@Override
public String login(UserLoginInfoParam userLoginInfoParam) {log.debug("开始处理【用户登录】业务,参数:{}", userLoginInfoParam);Authentication authentication = new UsernamePasswordAuthenticationToken(userLoginInfoParam.getUsername(), userLoginInfoParam.getPassword());log.debug("准备调用 AuthenticationManager 的认证方法,判断用户名、密码 是否成功登录");Authentication authenticate = authenticationManager.authenticate(authentication);log.debug("验证用户登录成功,返回认证结果:{}", authenticate);Object principal = authenticate.getPrincipal(); //认证结果的当事人就是 userDetail的人log.debug("从认证结果中获取当事人:{}", principal);CustomUserDetails userDetails = (CustomUserDetails) principal;Long id = userDetails.getId();log.debug("从认证结果中的当事人中获取ID:{}", id);String username = userDetails.getUsername();log.debug("从认证结果中的当事人中获取用户名:{}", username);String avatar = userDetails.getAvatar();log.debug("从认证结果中的当事人中获取头像:{}", avatar);Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();log.debug("从认证结果中的当事人中获取权限列表:{}", authorities);String authoritiesJsonString = JSON.toJSONString(authorities);log.debug("将权限列表对象转换为JSON格式的字符串:{}", authoritiesJsonString);Date date = new Date(System.currentTimeMillis() + 30L * 24 * 60 * 60 * 1000);//                                                  ↑ 注意加L,避免int溢出为负数String secretKey = "fNesMDkqrJFdsfDSwAbFLJ8SnsHJ438AF72D73aKJSmfdsafdLKKAFKDSJ";Map<String, Object> claims = new HashMap<>();claims.put("id", id);claims.put("username", username);claims.put("avatar", avatar);//        claims.put("authorities", authorities);claims.put("authoritiesJsonString", authoritiesJsonString);return Jwts.builder().setHeaderParam("alg", "HS256").setHeaderParam("typ", "JWT").setClaims(claims).setExpiration(date).signWith(SignatureAlgorithm.HS256, secretKey).compact();//改为使用JWT后,不必在登录成功后就将认证信息存入 SecurityContext 中/*log.debug("准备将认证信息结果存入 SecurityContext 中...");SecurityContextHolder.getContext().setAuthentication(authenticate);log.debug("已经将认证信息存入到 SecurityContext 中 登录业务处理完成");*/
}

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

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

相关文章

Spring Boot中的Profile:原理、用法与示例

Spring Boot中的Profile&#xff1a;原理、用法与示例 前言 Spring Boot 是一个快速开发 Spring 应用程序的框架&#xff0c;它提供了很多有用的功能和特性。其中&#xff0c;Profile 是一个常用的功能&#xff0c;它可以根据不同的环境配置来加载不同的配置文件&#xff0c;…

双路高速 DA 实验

目录 双路高速 DA 实验 1、简介 2、实验任务 3、程序设计 3.1、hs_dual_da顶层模块代码 3.2、ROM 波形存储模块&#xff08;rom_1024x10b&#xff09; 创建单端口 ROM IP核 3.2、DA 数据发送模块&#xff08;da_wave_send&#xff09;代码 4、硬件设计 4.1、添加.xdc…

Nginx网站服务

目录 Nginx简介 简述Nginx和Apache的差异 3 Nginx 相对于 Apache 的优点 阻塞与非阻塞 同步与异步 ginx 应用场景 nginx编译安装 Nginx安装和升级 1.关闭防火墙&#xff0c;将安装nginx所需软件包传到/opt目录下 2.拖入软件包 3.安装依赖包 3.创建运行用户与组 5.编译安…

【黑马头条-Java微服务项目】

黑马头条-Java微服务项目 (一)、项目介绍1.项目背景介绍(1).基本介绍(2).业务说明(3).项目术语介绍 2.技术栈说明(1).技术栈-基础六层技术(2).技术栈-服务四层技术(3).技术栈-分布 (二)、nacos环境搭建 (一)、项目介绍 1.项目背景介绍 (1).基本介绍 随着智能手机的普及&…

调用百度文心AI作画API实现中文-图像跨模态生成

作者介绍 乔冠华&#xff0c;女&#xff0c;西安工程大学电子信息学院&#xff0c;2020级硕士研究生&#xff0c;张宏伟人工智能课题组。 研究方向&#xff1a;机器视觉与人工智能。 电子邮件&#xff1a;1078914066qq.com 一&#xff0e;文心AI作画API介绍 1. 文心AI作画 文…

Seata 四种模式对比总结

一、前言 通过以下系列章节&#xff1a; docker-compose 实现Seata Server高可用部署 | Spring Cloud 51 Seata AT 模式理论学习、事务隔离及部分源码解析 | Spring Cloud 52 Spring Boot集成Seata利用AT模式分布式事务示例 | Spring Cloud 53 Seata XA 模式理论学习、使用…

Day_56-57kMeans 聚类

目录 Day_56-57 k-Means 聚类 一. 基本概念介绍 二. 具体过程 三. 代码实现与解释 1. 导入数据与数据初始化 2. 核心代码 3. 后续信息的补充 4. 距离计算和随机排列 四. 后续的数据分析 五. 运行结果 Day_56-57 k-Means 聚类 一. 基本概念介绍 同我上一篇博客的介绍&…

【Linux】打开Linux大门,踏入Linux世界(环境搭建再加一群Linux基本指令就OK啦~)

&#x1f9d1;‍&#x1f393;个人主页&#xff1a;简 料 &#x1f3c6;所属专栏&#xff1a;Linux系统编程与网络编程 &#x1f3c6;个人社区&#xff1a;越努力越幸运社区 &#x1f3c6;简 介&#xff1a;简料简料&#xff0c;简单有料~在校大学生一枚&#x…

MySQL表的约束

目录 前言 1.什么是约束 2.空属性 3.默认值 4.列描述 5.zerofill 6.主键 7.自增长 8.唯一键 9.外键 总结 前言 hello&#xff0c;各位小伙伴大家好&#xff0c;本章内容为大家介绍关于MySQL约束的相关内容&#xff0c;关于约束这个概念&#xff0c;如果是第一次接触可…

redis---基础(部署及常用命令)

目录 前言一、关系型数据库与非关系型数据库1. 关系型数据库2. 非关系型数据库3. 关系型数据库和非关系型数据库区别4. 非关系型数据库产生背景小结&#xff1a; 二、Redis简介1. 单进程快速的原因&#xff1a;2.epoll 机制优势&#xff1a; 三、Redis 具有以下几个优点四、red…

机器学习之LDA算法

目录 LDA算法 LDA目标 LDA原理推导 LDA除法模型 LDA减法模型 LDA除法正则模型 LDA减法正则模型 证明&#xff1a;StSwSb LDA算法流程 LDA优点 LDA缺点 基于LDA的人脸识别 LDA算法 线性判别分析&#xff08;linear discriminant analysis&#xff0c;LDA&#xff0…

计算机网络——物理层

物理层 物理层是计算机网络体系结构中的底层层级&#xff0c;负责处理计算机与物理传输媒介之间的接口和通信细节。它主要关注如何在物理媒介上传输原始比特流&#xff0c;并确保数据能够可靠地从发送方传输到接收方。 物理层的主要任务包括&#xff1a; 传输介质&#xff1a…