app网站建设需要什么软件,毕业设计做课程网站好,知名网站建设代理,网站建设人文环境第八章 项目实战
四、后台功能开发
1. 用户模块开发
1.1 jwt 和 token 介绍
1.1.1 token 介绍
令牌#xff08;Token#xff09;#xff1a;在计算机领域#xff0c;令牌是一种代表某种访问权限或身份认证信息的令牌。它可以是一串随机生成的字符或数字#xff0c;用…第八章 项目实战
四、后台功能开发
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 导入依赖
dependencygroupIdio.jsonwebtoken/groupIdartifactIdjjwt/artifactIdversion0.9.1/version
/dependencydependencygroupIdjavax.xml.bind/groupIdartifactIdjaxb-api/artifactIdversion2.3.0/version
/dependency1.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;JwsClaims 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 keytoken valuetoken值 - 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 ServiceImplUserMapper, Userimplements UserService{Autowiredprivate JwtHelper jwtHelper;Autowiredprivate UserMapper userMapper;/*** 登录业务实现* param user* return result封装*/Overridepublic Result login(User user) {//根据账号查询LambdaQueryWrapperUser 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 形式
usernamezhangsan响应数据 成功 {code:200,message:successdata:{}
}失败 {code:505,message:用户名占用data:{}
}1.4.3 代码实现
1.4.3.1 controller
/*** url地址user/checkUserName* 请求方式POST* 请求参数param形式* usernamezhangsan* 响应数据:* {* 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) {LambdaQueryWrapperUser 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:successdata:{}
}失败 {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) {LambdaQueryWrapperUser 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);
}