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的依赖:
- <!-- JWT依赖-->
- <dependency>
- <groupId>io.jsonwebtoken</groupId>
- <artifactId>jjwt</artifactId>
- <version>0.9.1</version>
- </dependency>
复制代码 在引入完JWT来赖后,就可以调用工具包中提供的API来完成JWT令牌的生成和校验。工具类:Jwts
2). 生成JWT代码实现:
- @Test
- public void testGenJwt() {
- Map<String, Object> claims = new HashMap<>();
- claims.put("id", 10);
- claims.put("username", "itheima");
-
- String jwt = Jwts.builder().signWith(SignatureAlgorithm.HS256, "aXRjYXN0")
- .addClaims(claims)
- .setExpiration(new Date(System.currentTimeMillis() + 12 * 3600 * 1000))
- .compact();
-
- System.out.println(jwt);
- }
复制代码 3). 实现了JWT令牌的生成,下面我们接着使用Java代码来校验JWT令牌(解析生成的令牌):
- @Test
- public void testParseJwt() {
- Claims claims = Jwts.parser().setSigningKey("aXRjYXN0")
- .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MTAsInVzZXJuYW1lIjoiaXRoZWltYSIsImV4cCI6MTcwMTkwOTAxNX0.N-MD6DmoeIIY5lB5z73UFLN9u7veppx1K5_N_jS9Yko")
- .getBody();
- System.out.println(claims);
- }
复制代码 完整测试版:
- package com.zidiu;
-
- import io.jsonwebtoken.Claims;
- import io.jsonwebtoken.Jwts;
- import io.jsonwebtoken.SignatureAlgorithm;
- import org.junit.jupiter.api.Test;
- import org.springframework.boot.test.context.SpringBootTest;
-
- import java.util.Date;
- import java.util.HashMap;
- import java.util.Map;
- @SpringBootTest
- public class JwtTest {
-
-
- /**
- * 生成JWT令牌 - Jwts.builder()
- */
- @Test
- public void testGenerateJwt(){
- Map<String, Object> dataMap = new HashMap<>();
- dataMap.put("id", 1);
- dataMap.put("username", "admin");
-
- String jwt = Jwts.builder()
- .signWith(SignatureAlgorithm.HS256, "aXRoZWltYQ==") //指定加密算法, 秘钥
- .addClaims(dataMap) //添加自定义信息
- .setExpiration(new Date(System.currentTimeMillis() + 60 * 1000)) //设置过期时间 60秒后过期
- .compact();//生成令牌
- System.out.println(jwt);
- }
-
- /**
- * 解析JWT令牌
- */
- @Test
- public void testParseJWT(){
- String token = "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJhZG1pbiIsImV4cCI6MTc2NDIwNzQxOH0.gL-xEurOln5MMHuWyqcTQuVngIZI23ueQHegAEDYGx4";
- Claims claims = Jwts.parser()
- .setSigningKey("aXRoZWltYQ==") //指定秘钥
- .parseClaimsJws(token) //解析令牌
- .getBody(); //获取自定义信息
- System.out.println(claims);
- }
-
- }
复制代码 通过以上测试,我们在使用JWT令牌时需要注意:
- JWT校验时使用的签名秘钥,必须和生成JWT令牌时使用的秘钥是配套的。
- 如果JWT令牌解析校验时报错,则说明 JWT令牌被篡改 或 失效了,令牌非法。
登录验证案例:
C层:
- package com.zidiu.controller;
-
- import com.zidiu.pojo.Emp;
- import com.zidiu.pojo.LoginInfo;
- import com.zidiu.pojo.Result;
- import com.zidiu.service.EmpService;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.PostMapping;
- import org.springframework.web.bind.annotation.RequestBody;
- import org.springframework.web.bind.annotation.RestController;
-
- @Slf4j
- @RestController
- public class LoginController {
-
- @Autowired
- private EmpService empService;
-
- @PostMapping("/login")
- public Result login(@RequestBody Emp emp){
- log.info("员工来登录啦 , {}", emp);
- LoginInfo loginInfo = empService.login(emp);
- if(loginInfo != null){
- return Result.success(loginInfo);
- }
- return Result.error("用户名或密码错误~");
- }
-
- }
复制代码 S层:
- package com.zidiu.service;
-
- import com.zidiu.pojo.Emp;
- import com.zidiu.pojo.EmpQueryParam;
- import com.zidiu.pojo.LoginInfo;
- import com.zidiu.pojo.PageResult;
-
- import java.time.LocalDate;
- import java.util.List;
-
- public interface EmpService {
- /**
- * 分页查询
- */
- PageResult<Emp> page(EmpQueryParam empQueryParam);
-
- /**
- * 添加员工
- * @param emp
- */
- void save(Emp emp);
-
- /**
- * 批量删除员工
- */
- void deleteByIds(List<Integer> ids);
-
- /**
- * 根据ID查询员工的详细信息
- */
- Emp getInfo(Integer id);
-
- /**
- * 修改员工信息
- */
- void update(Emp emp);
-
- /**
- * 登录
- */
- LoginInfo login(Emp emp);
- }
复制代码 实现层:
复制代码 M层:
- package com.zidiu.mapper;
-
- import com.zidiu.pojo.Emp;
- import com.zidiu.pojo.EmpQueryParam;
- import org.apache.ibatis.annotations.*;
-
- import java.time.LocalDate;
- import java.util.List;
- import java.util.Map;
-
- @Mapper
- public interface EmpMapper {
- /**
- * 查询所有的员工及其对应的部门名称
- */
- List<Emp> list(EmpQueryParam empQueryParam);
-
- /**
- * 新增员工数据
- */
- @Options(useGeneratedKeys = true, keyProperty = "id")
- @Insert("insert into emp(username, name, gender, phone, job, salary, image, entry_date, dept_id, create_time, update_time) " +
- "values (#{username},#{name},#{gender},#{phone},#{job},#{salary},#{image},#{entryDate},#{deptId},#{createTime},#{updateTime})")
- void insert(Emp emp);
-
- /**
- * 批量删除员工
- */
- void deleteByIds(List<Integer> ids);
-
- /**
- * 根据ID查询员工信息
- */
- Emp getById(Integer id);
-
- /**
- * 修改员工信息
- */
- void updateById(Emp emp);
-
- /**
- * 统计各个职位的员工人数
- */
- @MapKey("pos")
- List<Map<String,Object>> countEmpJobData();
-
- /**
- * 统计员工性别信息
- */
- @MapKey("name")
- List<Map> countEmpGenderData();
-
- /**
- * 根据用户名和密码查询员工信息
- */
- @Select("select * from emp where username = #{username} and password = #{password}")
- Emp getUsernameAndPassword(Emp emp);
- }
复制代码
SpringBoot3+Vue3开发综合实战项目:
JavaWeb(SpringBoot3+vue3)开发+教学管理系统项目实战
|