SSM - Springboot - MyBatis-Plus 全栈体系(三十四)

第八章 项目实战

四、后台功能开发

1. 用户模块开发

1.1 jwt 和 token 介绍
1.1.1 token 介绍
  • 令牌(Token):在计算机领域,令牌是一种代表某种访问权限或身份认证信息的令牌。它可以是一串随机生成的字符或数字,用于验证用户的身份或授权用户对特定资源的访问。普通的令牌可能以各种形式出现,如访问令牌、身份令牌、刷新令牌等。

在这里插入图片描述

  • 简单理解 : 每个用户生成的唯一字符串标识,可以进行用户识别和校验
  • 类似技术: 天王盖地虎 , 小鸡炖蘑菇
  • 优势: token 验证标识无法直接识别用户的信息,盗取 token 后也无法登录程序! 相对安全!
1.1.2 jwt 介绍
  • Token 是一项规范和标准(接口)
  • JWT(JSON Web Token)是具体可以生成,校验,解析等动作 Token 的技术(实现类)

在这里插入图片描述

1.1.3. jwt 工作流程
  • 用户提供其凭据(通常是用户名和密码)进行身份验证。
  • 服务器对这些凭据进行验证,并在验证成功后创建一个 JWT。
  • 服务器将 JWT 发送给客户端,并客户端在后续的请求中将 JWT 附加在请求头或参数中。
  • 服务器接收到请求后,验证 JWT 的签名和有效性,并根据 JWT 中的声明进行身份验证和授权操作
1.1.4 jwt 数据组成和包含信息
  • JWT 由三部分组成: header(头部).payload(载荷).signature(签名)

在这里插入图片描述

  • 我们需要理解的是, jwt 可以携带很多信息! 一般情况,需要加入:有效时间,签名秘钥,其他用户标识信息!
  • 有效时间为了保证 token 的时效性,过期可以重新登录获取!
  • 签名秘钥为了防止其他人随意解析和校验 token 数据!
  • 用户信息为了我们自己解析的时候,知道 Token 对应的具体用户!
1.1.5 jwt 使用和测试
1.1.5.1 导入依赖
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency><dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.3.0</version>
</dependency>
1.1.5.2 编写配置
  • application.yaml
#jwt配置
jwt:token:tokenExpiration: 120 #有效时间,单位分钟tokenSignKey: headline123456  #当前程序签名秘钥 自定义
1.1.5.3 导入工具类
  • 封装 jwt 技术工具类
package com.alex.utils;import com.alibaba.druid.util.StringUtils;
import io.jsonwebtoken.*;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;import java.util.Date;@Data
@Component
@ConfigurationProperties(prefix = "jwt.token")
public class JwtHelper {private  long tokenExpiration; //有效时间,单位毫秒 1000毫秒 == 1秒private  String tokenSignKey;  //当前程序签名秘钥//生成token字符串public  String createToken(Long userId) {System.out.println("tokenExpiration = " + tokenExpiration);System.out.println("tokenSignKey = " + tokenSignKey);String token = Jwts.builder().setSubject("YYGH-USER").setExpiration(new Date(System.currentTimeMillis() + tokenExpiration*1000*60)) //单位分钟.claim("userId", userId).signWith(SignatureAlgorithm.HS512, tokenSignKey).compressWith(CompressionCodecs.GZIP).compact();return token;}//从token字符串获取useridpublic  Long getUserId(String token) {if(StringUtils.isEmpty(token)) return null;Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);Claims claims = claimsJws.getBody();Integer userId = (Integer)claims.get("userId");return userId.longValue();}//判断token是否有效public  boolean isExpiration(String token){try {boolean isExpire = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody().getExpiration().before(new Date());//没有过期,有效,返回falsereturn isExpire;}catch(Exception e) {//过期出现异常,返回truereturn true;}}
}
1.1.5.4 使用和测试
@org.springframework.boot.test.context.SpringBootTest
public class SpringBootTest {@Autowiredprivate JwtHelper jwtHelper;@Testpublic void test(){//生成 传入用户标识String token = jwtHelper.createToken(1L);System.out.println("token = " + token);//解析用户标识int userId = jwtHelper.getUserId(token).intValue();System.out.println("userId = " + userId);//校验是否到期! false 未到期 true到期boolean expiration = jwtHelper.isExpiration(token);System.out.println("expiration = " + expiration);}}
1.2. 登录功能实现
1.2.1 需求描述

在这里插入图片描述

  • 用户在客户端输入用户名密码并向后端提交,后端根据用户名和密码判断登录是否成功,用户有误或者密码有误响应不同的提示信息!
1.2.2 接口描述
  • url 地址: user/login

  • 请求方式:POST

  • 请求参数:

{"username":"zhangsan", //用户名"userPwd":"123456"     //明文密码
}
  • 响应数据:

    • 成功
    {"code":"200",         // 成功状态码"message":"success"   // 成功状态描述"data":{"token":"... ..." // 用户id的token}
    }
    
    • 失败
    {"code":"501","message":"用户名有误""data":{}
    }
    
    {"code":"503","message":"密码有误""data":{}
    }
    
1.2.3 实现代码
1.2.3.1 controller
@RestController
@RequestMapping("user")
@CrossOrigin
public class UserController {@Autowiredprivate UserService userService;/*** 登录需求* 地址: /user/login* 方式: post* 参数:*    {*     "username":"zhangsan", //用户名*     "userPwd":"123456"     //明文密码*    }* 返回:*   {*    "code":"200",         // 成功状态码*    "message":"success"   // 成功状态描述*    "data":{*         "token":"... ..." // 用户id的token*     }*  }** 大概流程:*    1. 账号进行数据库查询 返回用户对象*    2. 对比用户密码(md5加密)*    3. 成功,根据userId生成token -> map key=token value=token值 - result封装*    4. 失败,判断账号还是密码错误,封装对应的枚举错误即可*/@PostMapping("login")public Result login(@RequestBody User user){Result result = userService.login(user);System.out.println("result = " + result);return result;}}
1.2.3.2 service
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>implements UserService{@Autowiredprivate JwtHelper jwtHelper;@Autowiredprivate UserMapper userMapper;/*** 登录业务实现* @param user* @return result封装*/@Overridepublic Result login(User user) {//根据账号查询LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(User::getUsername,user.getUsername());User loginUser = userMapper.selectOne(queryWrapper);//账号判断if (loginUser == null) {//账号错误return Result.build(null, ResultCodeEnum.USERNAME_ERROR);}//判断密码if (!StringUtils.isEmpty(user.getUserPwd())&& loginUser.getUserPwd().equals(MD5Util.encrypt(user.getUserPwd()))){//账号密码正确//根据用户唯一标识生成tokenString token = jwtHelper.createToken(Long.valueOf(loginUser.getUid()));Map data = new HashMap();data.put("token",token);return Result.ok(data);}//密码错误return Result.build(null,ResultCodeEnum.PASSWORD_ERROR);}
}
1.3 根据 token 获取用户数据
1.3.1 需求描述
  • 客户端发送请求,提交 token 请求头,后端根据 token 请求头获取登录用户的详细信息并响应给客户端进行存储
1.3.2 接口描述
  • url 地址:user/getUserInfo

  • 请求方式:GET

  • 请求头:

    token: token内容
    
  • 响应数据:

    • 成功
    {"code": 200,"message": "success","data": {"loginUser": {"uid": 1,"username": "zhangsan","userPwd": "","nickName": "张三"}}
    }
    
    • 失败
    {"code": 504,"message": "notLogin","data": null
    }
    
1.3.3 代码实现
1.3.3.1 controller
/*** 地址: user/getUserInfo* 方式: get* 请求头: token = token内容* 返回:*    {*     "code": 200,*     "message": "success",*     "data": {*         "loginUser": {*             "uid": 1,*             "username": "zhangsan",*             "userPwd": "",*             "nickName": "张三"*         }*      }*   }** 大概流程:*    1.获取token,解析token对应的userId*    2.根据userId,查询用户数据*    3.将用户数据的密码置空,并且把用户数据封装到结果中key = loginUser*    4.失败返回504 (本次先写到当前业务,后期提取到拦截器和全局异常处理器)*/
@GetMapping("getUserInfo")
public Result userInfo(@RequestHeader String token){Result result = userService.getUserInfo(token);return result;
}
1.3.3.2 service
/*** 查询用户数据* @param token* @return result封装*/
@Override
public Result getUserInfo(String token) {//1.判定是否有效期if (jwtHelper.isExpiration(token)) {//true过期,直接返回未登录return Result.build(null,ResultCodeEnum.NOTLOGIN);}//2.获取token对应的用户int userId = jwtHelper.getUserId(token).intValue();//3.查询数据User user = userMapper.selectById(userId);if (user != null) {user.setUserPwd(null);Map data = new HashMap();data.put("loginUser",user);return Result.ok(data);}return Result.build(null,ResultCodeEnum.NOTLOGIN);
}
1.4 注册用户名检查
1.4.1 需求描述

在这里插入图片描述

  • 用户在注册时输入用户名时,立刻将用户名发送给后端,后端根据用户名查询用户名是否可用并做出响应
1.4.2 接口描述
  • url 地址:user/checkUserName
  • 请求方式:POST
  • 请求参数:param 形式
username=zhangsan
  • 响应数据:

    • 成功
    {"code":"200","message":"success""data":{}
    }
    
    • 失败
    {"code":"505","message":"用户名占用""data":{}
    }
    
1.4.3 代码实现
1.4.3.1 controller
/*** url地址:user/checkUserName* 请求方式:POST* 请求参数:param形式* username=zhangsan* 响应数据:* {*    "code":"200",*    "message":"success"*    "data":{}* }** 实现步骤:*   1. 获取账号数据*   2. 根据账号进行数据库查询*   3. 结果封装*/
@PostMapping("checkUserName")
public Result checkUserName(String username){Result result = userService.checkUserName(username);return result;
}
1.4.3.2 service
/*** 检查账号是否可以注册** @param username 账号信息* @return*/
@Override
public Result checkUserName(String username) {LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(User::getUsername,username);User user = userMapper.selectOne(queryWrapper);if (user != null){return Result.build(null,ResultCodeEnum.USERNAME_USED);}return Result.ok(null);
}
1.5 用户注册功能
1.5.1 需求描述

在这里插入图片描述

  • 客户端将新用户信息发送给服务端,服务端将新用户存入数据库,存入之前做用户名是否被占用校验,校验通过响应成功提示,否则响应失败提示
1.5.2 接口描述
  • url 地址:user/regist

  • 请求方式:POST

  • 请求参数:

{"username":"zhangsan","userPwd":"123456","nickName":"张三"
}
  • 响应数据:

    • 成功
    {"code":"200","message":"success""data":{}
    }
    
    • 失败
    {"code":"505","message":"用户名占用""data":{}
    }
    
1.5.3 代码实现
1.5.3.1 controller
/**
* url地址:user/regist
* 请求方式:POST
* 请求参数:
* {
*     "username":"zhangsan",
*     "userPwd":"123456",
*     "nickName":"张三"
* }
* 响应数据:
* {
*    "code":"200",
*    "message":"success"
*    "data":{}
* }
*
* 实现步骤:
*   1. 将密码加密
*   2. 将数据插入
*   3. 判断结果,成 返回200 失败 505
*/@PostMapping("regist")
public Result regist(@RequestBody User user){Result result = userService.regist(user);return result;
}
1.5.3.2 service
@Override
public Result regist(User user) {LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(User::getUsername,user.getUsername());Long count = userMapper.selectCount(queryWrapper);if (count > 0){return Result.build(null,ResultCodeEnum.USERNAME_USED);}user.setUserPwd(MD5Util.encrypt(user.getUserPwd()));int rows = userMapper.insert(user);System.out.println("rows = " + rows);return Result.ok(null);
}

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

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

相关文章

搭建一个windows的DevOps环境记录

边搭建边记录&#xff0c;整个DevOps环境的搭建可能会很久。。。 一、安装Jenkins&#xff1a; 参考&#xff1a;Jenkins基础篇--windows安装Jenkins-CSDN博客 注意上面选择JDK的路径&#xff0c;选择到安装目录&#xff0c;该目录并不一定要在path中配置了&#xff08;就是…

Springboot 常用注解

自动装配 ComponentScan 用于配置Spring需要扫描的被组件注解注释的类所在的包。 Component 用于标注一个普通的组件类&#xff0c;它没有明确的业务范围&#xff0c;只是通知Spring被此注解的类需要被纳入到Spring Bean容器中并进行管理。 Autowired Autowired用于自动装配…

Linux--进程终止

1.进程退出场景 进程退出场景只有三种&#xff1a; 代码运行完毕&#xff0c;结果正确代码运行完毕&#xff0c;结果错误代码在运行期间异常中断&#xff0c;退出进程 比如&#xff1a;对于错误的进程&#xff0c;可以通过不同的返回值来确定&#xff0c;什么是错误码呢&#x…

微信小程序前后端交互与WXS的应用

目录 前言 一、后台数据交互 1.数据表 2.后端代码的实现 3.前后端交互 3.1.后端接口URL管理 3.2.发送后端请求 3.3.请求方式的封装 4.前端代码的编写 二、WXS的使用 1、.wxs 文件 2.综合运用 前言 当今社交媒体的普及使得微信小程序成为了一种流行的应用开发形式。…

BUUCTF 大白 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; 看不到图&#xff1f; 是不是屏幕太小了 。 密文&#xff1a; 下载附件后解压&#xff0c;发现一张名为dabai.png的图片。 &#xff08;似乎因为文件被修改过&#xff0c;原图片无法放在这里&#xff0c;这张图片是…

【JavaScript】深入浅出理解事件循环

1. 浏览器的进程模型 1.1 进程 程序运行需要有它自己专属的内存空间&#xff0c;可以把这块内存空间简单的理解为进程。 每个应用至少有一个进程&#xff0c;进程之间相互独立&#xff0c;即使要通信&#xff0c;也需要双方同意。 1.2 线程 有了进程后&#xff0c;就可以运…

【讲座笔记】基于 Apache Calcite 的多引擎指标管理最佳实践|CommunityOverCode Asia 2023 | 字节开源

引言 三个问题 (问题解法) 1套SQL 2种语法 统一SQL的实践案例 虚拟列的实践案例 SQL Define Function 指标管理的实现 在这里插入图片描述

还不知道光场相机吗?

1.什么是光场&#xff1f; 光场&#xff08;light field&#xff09;&#xff1a;就是指光在每一个方向通过每一个点的光量。 从概念里&#xff0c;你至少可以得到两点信息&#xff1a; 光场包含光的方向光场包含一个点的光量 2.什么是光场相机 我们知道普通的相机拍照成像…

【MyBatisPlus】快速入门、常用注解、常用配置

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 MyBatisPlus 一、快速入门1.1 引入MyBatisP…

发挥服务器的无限潜能:创意项目、在线社区和更多

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 ✨特色专栏&#xff1a…

docker 安装 sftpgo

sftpgo 简介 sftpgo 是一个功能齐全且高度可配置的 SFTP 服务器&#xff0c;具有可选的 HTTP/S、FTP/S 和 WebDAV 支持。支持多种存储后端&#xff1a;本地文件系统、加密本地文件系统、S3&#xff08;兼容&#xff09;对象存储、Google 云存储、Azure Blob 存储、SFTP。 官…

Rust之自动化测试(三): 测试组合

开发环境 Windows 10Rust 1.73.0 VS Code 1.83.1 项目工程 这里继续沿用上次工程rust-demo 测试组合 正如本章开始时提到的&#xff0c;测试是一个复杂的学科&#xff0c;不同的人使用不同的术语和组织。Rust社区根据两个主要类别来考虑测试:单元测试和集成测试。单元测试很…

轻松搭建个人web站点:OpenWRT教程结合内网穿透技术实现公网远程访问

文章目录 前言1. 检查uhttpd安装2. 部署web站点3. 安装cpolar内网穿透4. 配置远程访问地址5. 配置固定远程地址 前言 uhttpd 是 OpenWrt/LuCI 开发者从零开始编写的 Web 服务器&#xff0c;目的是成为优秀稳定的、适合嵌入式设备的轻量级任务的 HTTP 服务器&#xff0c;并且和…

ubuntu启动模式介绍以及如何进入单用户模式和恢复模式

Ubuntu操作系统提供了多种启动模式&#xff0c;每种模式都有不同的用途和功能。下面将深入介绍Ubuntu的几种启动模式&#xff1a; 正常启动模式&#xff08;Normal boot&#xff09;&#xff1a;这是默认的启动模式&#xff0c;也是大多数用户使用的模式。在正常启动模式下&am…

mk语法示例

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

gitlab 离线安装问题解决:NOKEY,signature check fail

文章目录 1&#xff0c;安装gitlab-ce-161.1&#xff0c;rpm安装gitlab问题: NOKEY、signature check fail1.2, docker 启动 gitlab: ThreadError: cant create Thread: Operation not permitted 2&#xff0c;安装gitlab-ce-142.1 修改配置&#xff0c;重新编译2.2 root用户启…

陪诊小程序|陪诊小程序关爱健康,无忧陪伴

随着社会发展和人们生活水平的提高&#xff0c;健康问题成为人们关注的焦点。然而&#xff0c;在就医过程中&#xff0c;许多患者常常感到孤独和无助&#xff0c;缺乏得到家人陪伴的温暖与安慰。为了解决这一问题&#xff0c;我们公司开发了一款创新的陪诊小程序软件&#xff0…

迁移conda环境后,非root用户执行pip命令和jupyter命令报错/bad interpreter: Permission denied

移动conda环境&#xff0c;在移动的环境执行pip和jupyter 报错-bash: /data/home/用户名/anaconda3/envs/llm/bin/pip: /root/anaconda3/envs/llm/bin/python: bad interpreter: Permission denied 报错信息 一、原因 原因是当前的这个data/home/用户名/anaconda3/envs/环境名…

POSIX信号量

目录 信号量的原理 信号量函数 使用信号量实现线程互斥功能 基于环形队列的生产消费模型 生产者和消费者必须遵守的两个规则 信号量的原理 通过之前的学习&#xff0c;我们知道有的资源可能会被多个执行流同时申请访问&#xff0c;我们将这种资源叫做临界资源&#xff0c…

记录一次线下渗透电气照明系统(分析与实战)

项目地址:https://github.com/MartinxMax/S-Clustr 注意 本次行动未造成任何设备损坏,并在道德允许范围内测试 >ethical hacking< 发现过程 在路途中,发现一个未锁的配电柜,身为一个电工自然免不了好奇心(非专业人士请勿模仿,操作不当的话220V人就直了) 根据照片,简…