找回密码
 立即注册
查看: 19|回复: 0

JavaWeb(SpringBoot3+vue3)开发+教学管理系统项目实战之登录验证和JWT令牌

[复制链接]

73

主题

3

精华

77

金币

技术维护QQ:515138

积分
165
发表于 4 天前 | 显示全部楼层 |阅读模式
JavaWeb(SpringBoot3+vue3)开发+教学管理系统项目实战之登录验证和JWT令牌
  • JWT全称 JSON Web Token  (官网:https://jwt.io/),定义了一种简洁的、自包含的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。
    • 简洁:是指jwt就是一个简单的字符串。可以在请求参数或者是请求头当中直接传递。
    • 自包含:指的是jwt令牌,看似是一个随机的字符串,但是我们是可以根据自身的需求在jwt令牌中存储自定义的数据内容。如:可以直接在jwt令牌中存储用户的相关信息。
    • 简单来讲,jwt就是将原始的json数据格式进行了安全的封装,这样就可以直接基于jwt在通信双方安全的进行信息传输了。

JWT的组成: (JWT令牌由三个部分组成,三个部分之间使用英文的点来分割)
  • 第一部分:Header(头), 记录令牌类型、签名算法等。 例如:{"alg":"HS256","type":"JWT"}
  • 第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:{"id":"1","username":"Tom"}
  • 第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。

签名的目的就是为了防jwt令牌被篡改,而正是因为jwt令牌最后一个部分数字签名的存在,所以整个jwt 令牌是非常安全可靠的。一旦jwt令牌当中任何一个部分、任何一个字符被篡改了,整个令牌在校验的时候都会失败,所以它是非常安全可靠的。

https://base64.us/
游客,如果您要查看本帖隐藏内容请回复

1). 首先我们先来实现JWT令牌的生成。要想使用JWT令牌,需要先引入JWT的依赖:

  1. <!-- JWT依赖-->
  2. <dependency>
  3.     <groupId>io.jsonwebtoken</groupId>
  4.     <artifactId>jjwt</artifactId>
  5.     <version>0.9.1</version>
  6. </dependency>
复制代码
在引入完JWT来赖后,就可以调用工具包中提供的API来完成JWT令牌的生成和校验。工具类:Jwts
2). 生成JWT代码实现:
  1. @Test
  2. public void testGenJwt() {
  3.     Map<String, Object> claims = new HashMap<>();
  4.     claims.put("id", 10);
  5.     claims.put("username", "itheima");
  6.     String jwt = Jwts.builder().signWith(SignatureAlgorithm.HS256, "aXRjYXN0")
  7.         .addClaims(claims)
  8.         .setExpiration(new Date(System.currentTimeMillis() + 12 * 3600 * 1000))
  9.         .compact();
  10.     System.out.println(jwt);
  11. }
复制代码
3). 实现了JWT令牌的生成,下面我们接着使用Java代码来校验JWT令牌(解析生成的令牌):
  1. @Test
  2. public void testParseJwt() {
  3.     Claims claims = Jwts.parser().setSigningKey("aXRjYXN0")
  4.         .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MTAsInVzZXJuYW1lIjoiaXRoZWltYSIsImV4cCI6MTcwMTkwOTAxNX0.N-MD6DmoeIIY5lB5z73UFLN9u7veppx1K5_N_jS9Yko")
  5.         .getBody();
  6.     System.out.println(claims);
  7. }
复制代码
完整测试版:
  1. package com.zidiu;
  2. import io.jsonwebtoken.Claims;
  3. import io.jsonwebtoken.Jwts;
  4. import io.jsonwebtoken.SignatureAlgorithm;
  5. import org.junit.jupiter.api.Test;
  6. import org.springframework.boot.test.context.SpringBootTest;
  7. import java.util.Date;
  8. import java.util.HashMap;
  9. import java.util.Map;
  10. @SpringBootTest
  11. public class JwtTest {
  12.     /**
  13.      * 生成JWT令牌 - Jwts.builder()
  14.      */
  15.     @Test
  16.     public void testGenerateJwt(){
  17.         Map<String, Object> dataMap = new HashMap<>();
  18.         dataMap.put("id", 1);
  19.         dataMap.put("username", "admin");
  20.         String jwt = Jwts.builder()
  21.                 .signWith(SignatureAlgorithm.HS256, "aXRoZWltYQ==") //指定加密算法, 秘钥
  22.                 .addClaims(dataMap) //添加自定义信息
  23.                 .setExpiration(new Date(System.currentTimeMillis() + 60 * 1000)) //设置过期时间 60秒后过期
  24.                 .compact();//生成令牌
  25.         System.out.println(jwt);
  26.     }
  27.     /**
  28.      * 解析JWT令牌
  29.      */
  30.     @Test
  31.     public void testParseJWT(){
  32.         String token = "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJhZG1pbiIsImV4cCI6MTc2NDIwNzQxOH0.gL-xEurOln5MMHuWyqcTQuVngIZI23ueQHegAEDYGx4";
  33.         Claims claims = Jwts.parser()
  34.                 .setSigningKey("aXRoZWltYQ==") //指定秘钥
  35.                 .parseClaimsJws(token) //解析令牌
  36.                 .getBody(); //获取自定义信息
  37.         System.out.println(claims);
  38.     }
  39. }
复制代码
通过以上测试,我们在使用JWT令牌时需要注意:
  • JWT校验时使用的签名秘钥,必须和生成JWT令牌时使用的秘钥是配套的。
  • 如果JWT令牌解析校验时报错,则说明 JWT令牌被篡改 或 失效了,令牌非法。

登录验证案例:
C层:
  1. package com.zidiu.controller;
  2. import com.zidiu.pojo.Emp;
  3. import com.zidiu.pojo.LoginInfo;
  4. import com.zidiu.pojo.Result;
  5. import com.zidiu.service.EmpService;
  6. import lombok.extern.slf4j.Slf4j;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.web.bind.annotation.PostMapping;
  9. import org.springframework.web.bind.annotation.RequestBody;
  10. import org.springframework.web.bind.annotation.RestController;
  11. @Slf4j
  12. @RestController
  13. public class LoginController {
  14.     @Autowired
  15.     private EmpService empService;
  16.     @PostMapping("/login")
  17.     public Result login(@RequestBody Emp emp){
  18.         log.info("员工来登录啦 , {}", emp);
  19.         LoginInfo loginInfo = empService.login(emp);
  20.         if(loginInfo != null){
  21.             return Result.success(loginInfo);
  22.         }
  23.         return Result.error("用户名或密码错误~");
  24.     }
  25. }
复制代码
S层:
  1. package com.zidiu.service;
  2. import com.zidiu.pojo.Emp;
  3. import com.zidiu.pojo.EmpQueryParam;
  4. import com.zidiu.pojo.LoginInfo;
  5. import com.zidiu.pojo.PageResult;
  6. import java.time.LocalDate;
  7. import java.util.List;
  8. public interface EmpService {
  9.       /**
  10.      * 分页查询
  11.      */
  12.     PageResult<Emp> page(EmpQueryParam empQueryParam);
  13.     /**
  14.      * 添加员工
  15.      * @param emp
  16.      */
  17.     void save(Emp emp);
  18.     /**
  19.      * 批量删除员工
  20.      */
  21.     void deleteByIds(List<Integer> ids);
  22.     /**
  23.      * 根据ID查询员工的详细信息
  24.      */
  25.     Emp getInfo(Integer id);
  26.     /**
  27.      * 修改员工信息
  28.      */
  29.     void update(Emp emp);
  30.     /**
  31.      * 登录
  32.      */
  33.     LoginInfo login(Emp emp);
  34. }
复制代码
实现层:
  1. package com.zidiu.service.impl;
  2. import com.github.pagehelper.Page;
  3. import com.github.pagehelper.PageHelper;
  4. import com.zidiu.mapper.EmpExprMapper;
  5. import com.zidiu.mapper.EmpMapper;
  6. import com.zidiu.pojo.*;
  7. import com.zidiu.service.EmpService;
  8. import com.zidiu.utils.JwtUtils;
  9. import org.springframework.beans.factory.annotation.Autowired;
  10. import org.springframework.stereotype.Service;
  11. import org.springframework.transaction.annotation.Transactional;
  12. import org.springframework.util.CollectionUtils;
  13. import java.time.LocalDate;
  14. import java.time.LocalDateTime;
  15. import java.util.Arrays;
  16. import java.util.HashMap;
  17. import java.util.List;
  18. import java.util.Map;
  19. @Service
  20. public class EmpServiceImpl implements EmpService {
  21.     @Autowired
  22.     private EmpMapper empMapper;
  23.     @Autowired
  24.     private EmpExprMapper empExprMapper;
  25.     /**
  26.      * 查询员工列表
  27.      */
  28.     @Override
  29.     public PageResult page(EmpQueryParam empQueryParam) {
  30.         //1. 设置PageHelper分页参数
  31.         PageHelper.startPage(empQueryParam.getPage(), empQueryParam.getPageSize());
  32.         //2. 执行查询
  33.         List<Emp> empList = empMapper.list(empQueryParam);
  34.         //3. 封装分页结果
  35.         Page<Emp> p = (Page<Emp>)empList;
  36.         return new PageResult(p.getTotal(), p.getResult());
  37.     }
  38.     /**
  39.      * 添加员工
  40.      * @param emp
  41.      */
  42.     @Transactional
  43.     @Override
  44.     public void save(Emp emp) {
  45.         //1.补全基础属性
  46.         emp.setCreateTime(LocalDateTime.now());
  47.         emp.setUpdateTime(LocalDateTime.now());
  48.         //2.保存员工基本信息
  49.         empMapper.insert(emp);
  50.         int i = 1/0;
  51.         //3. 保存员工的工作经历信息 - 批量
  52.         Integer empId = emp.getId();
  53.         List<EmpExpr> exprList = emp.getExprList();
  54.         if(!CollectionUtils.isEmpty(exprList)){
  55.             exprList.forEach(empExpr -> empExpr.setEmpId(empId));
  56.             empExprMapper.insertBatch(exprList);
  57.         }
  58.     }
  59.     /**
  60.      * 批量删除员工
  61.      */
  62.     @Transactional(rollbackFor = {Exception.class})
  63.     @Override
  64.     public void deleteByIds(List<Integer> ids) {
  65.         //1. 根据ID批量删除员工基本信息
  66.         empMapper.deleteByIds(ids);
  67.         //2. 根据员工的ID批量删除员工的工作经历信息
  68.         empExprMapper.deleteByEmpIds(ids);
  69.     }
  70.     @Override
  71.     public Emp getInfo(Integer id) {
  72.         return empMapper.getById(id);
  73.     }
  74.     @Transactional(rollbackFor = Exception.class)
  75.     @Override
  76.     public void update(Emp emp) {
  77.         //1. 根据ID更新员工基本信息
  78.         emp.setUpdateTime(LocalDateTime.now());
  79.         empMapper.updateById(emp);
  80.         //2. 根据员工ID删除员工的工作经历信息 【删除老的】
  81.         empExprMapper.deleteByEmpIds(Arrays.asList(emp.getId()));
  82.         //3. 新增员工的工作经历数据 【新增新的】
  83.         Integer empId = emp.getId();
  84.         List<EmpExpr> exprList = emp.getExprList();
  85.         if(!CollectionUtils.isEmpty(exprList)){
  86.             exprList.forEach(empExpr -> empExpr.setEmpId(empId));
  87.             empExprMapper.insertBatch(exprList);
  88.         }
  89.     }
  90.     /**
  91.      * 员工登录
  92.      */
  93.     @Override
  94.     public LoginInfo login(Emp emp) {
  95.         Emp empLogin = empMapper.getUsernameAndPassword(emp);
  96.         if(empLogin != null){
  97.             // 生成JWT令牌
  98.             Map<String, Object> dataMap = new HashMap<>();
  99.             dataMap.put("id", empLogin.getId());
  100.             dataMap.put("username", empLogin.getUsername());
  101.             String jwt = JwtUtils.generateJwt(dataMap);
  102.             LoginInfo loginInfo = new LoginInfo(empLogin.getId(), empLogin.getUsername(), empLogin.getName(), jwt);
  103.             return loginInfo;
  104.         }
  105.         return null;
  106.     }
  107. }
复制代码
M层:
  1. package com.zidiu.mapper;
  2. import com.zidiu.pojo.Emp;
  3. import com.zidiu.pojo.EmpQueryParam;
  4. import org.apache.ibatis.annotations.*;
  5. import java.time.LocalDate;
  6. import java.util.List;
  7. import java.util.Map;
  8. @Mapper
  9. public interface EmpMapper {
  10.     /**
  11.      * 查询所有的员工及其对应的部门名称
  12.      */
  13.     List<Emp> list(EmpQueryParam empQueryParam);
  14.     /**
  15.      * 新增员工数据
  16.      */
  17.     @Options(useGeneratedKeys = true, keyProperty = "id")
  18.     @Insert("insert into emp(username, name, gender, phone, job, salary, image, entry_date, dept_id, create_time, update_time) " +
  19.             "values (#{username},#{name},#{gender},#{phone},#{job},#{salary},#{image},#{entryDate},#{deptId},#{createTime},#{updateTime})")
  20.     void insert(Emp emp);
  21.     /**
  22.      * 批量删除员工
  23.      */
  24.     void deleteByIds(List<Integer> ids);
  25.     /**
  26.      * 根据ID查询员工信息
  27.      */
  28.     Emp getById(Integer id);
  29.     /**
  30.      * 修改员工信息
  31.      */
  32.     void updateById(Emp emp);
  33.     /**
  34.      * 统计各个职位的员工人数
  35.      */
  36.     @MapKey("pos")
  37.     List<Map<String,Object>> countEmpJobData();
  38.     /**
  39.      * 统计员工性别信息
  40.      */
  41.     @MapKey("name")
  42.     List<Map> countEmpGenderData();
  43.     /**
  44.      * 根据用户名和密码查询员工信息
  45.      */
  46.     @Select("select * from emp where username = #{username} and password = #{password}")
  47.     Emp getUsernameAndPassword(Emp emp);
  48. }
复制代码

SpringBoot3+Vue3开发综合实战项目:
JavaWeb(SpringBoot3+vue3)开发+教学管理系统项目实战

网站建设,公众号小程序开发,系统定制,软件App开发,技术维护【联系我们】手机/微信:17817817816 QQ:515138

QQ|Archiver|自丢网 ( 粤ICP备2024252464号-1 )

GMT+8, 2025-12-1 07:01

专注于网站建设,公众号小程序制作,商城小程序,系统定制,软件App开发

【联系我们】手机/微信:17817817816 QQ:515138

快速回复 返回顶部 返回列表