一、JWT出现的背景
jwt令牌出现的背景,比如我们通过一个路由访问网站的时候,有些游客在知道url的情况下会跳过用户登录直接访问其他网页,这样不仅在逻辑上说不通(我没登陆咋就能使用其他功能?)还会造成信息泄露和访问不安全。这时候jwt令牌的出现就填充了这一空白。
具体地,在用户登陆之后生成一个JWT令牌,然后将该令牌下发给客户端,客户端将该令牌存储起来,在之后的每一次请求都将令牌带到服务端,服务端接受该请求之后对这个请求进行统一拦截,获取到令牌并验证真伪,如果令牌无效,直接拦截,如果有效则放行。
二、实战
首先项目目录如下,项目所需文件红框圈出:
2.1 pom.xml: 将JWT的依赖包引入pom文件中:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
有需要自取:pom.xml一些必不可少的配置-CSDN博客
2.2 JwtUtils:工具类,用于jwt令牌的创建和解码
package com.bytedance.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.Map;
public class JwtUtils {
private static String signKey = "itheima";
private static Long expire = 43200000L; // 24小时候过期
/**
* 生成JWT令牌
* @param claims JWT第二部分负载 payload 中存储的内容
* @return
*/
public static String generateJwt(Map<String, Object> claims){
String jwt = Jwts.builder()
.addClaims(claims)
.signWith(SignatureAlgorithm.HS256, signKey)
.setExpiration(new Date(System.currentTimeMillis() + expire))
.compact();
return jwt;
}
/**
* 解析JWT令牌
* @param jwt JWT令牌
* @return JWT第二部分负载 payload 中存储的内容
*/
public static Claims parseJWT(String jwt){
Claims claims = Jwts.parser()
.setSigningKey(signKey)
.parseClaimsJws(jwt)
.getBody();
return claims;
}
}
2.3 LoginController.java : 创建登陆界面的接口,由前端提交员工信息(这里是一个Emp对象其实只需要username和password参数),当调empService这个bean对象的方法时传入,empService又调用empMapper的bean对象去数据库里检索是否有这个username和password,有的话则生成令牌并将生成的令牌作为返回信息返回即可,否则返回错误提示。
package com.bytedance.controller; // 改成自己包名
import com.bytedance.pojo.Emp;
import com.bytedance.pojo.Result;
import com.bytedance.service.EmpService;
import com.bytedance.utils.JwtUtils;
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;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@RestController
public class LoginController {
@Autowired
private EmpService empService;
@PostMapping("/login")
public Result login(@RequestBody Emp emp){
log.info("员工登陆的信息:{}",emp);
Emp e = empService.login(emp);
// 如果登陆成功,生成令牌,下发令牌
if (e != null){
Map<String,Object> claims = new HashMap<>();
claims.put("id",e.getId());
claims.put("name",e.getName());
claims.put("username",e.getUsername());
String jwtcode = JwtUtils.generateJwt(claims);
return Result.success(jwtcode);
}
// 登陆失败,返回错误信息
else{
return Result.error("用户名或密码失败~");
}
}
}
2.4 EmpService.java : 这是一个接口,定义了login方法给实现类去实现。
package com.bytedance.service;
import com.bytedance.pojo.Emp;
import com.bytedance.pojo.PageBean;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;
import java.util.List;
public interface EmpService {
Emp login(Emp emp);
}
2.5 EmpServicelmpl.java : EmpService的实现类,实现了login函数。这个login方法将接收到的emp对象传入empMapper类中的getByUsernameAndPassword方法,该方法去数据库中查询是否有一致的username和password。
package com.bytedance.service.impl;
import com.bytedance.mapper.EmpMapper;
import com.bytedance.pojo.Emp;
import com.bytedance.pojo.PageBean;
import com.bytedance.service.EmpService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class EmpServicelmpl implements EmpService {
@Autowired
private EmpMapper empMapper;
@Override
public Emp login(Emp emp) {
return empMapper.getByUsernameAndPassword(emp);
}
}
2.6 EmpMapper.java : 里面的getByUsernameAndPassword方法负责查询是否存在登陆的信息并返回结果。
package com.bytedance.mapper;
import com.bytedance.pojo.Emp;
import org.apache.ibatis.annotations.*;
import java.time.LocalDate;
import java.util.List;
@Mapper
public interface EmpMapper {
@Select("select * from emp where username = #{username} and password = #{password}")
Emp getByUsernameAndPassword(Emp emp);
}
三、验证
这样在前端页面就不能跳过登陆访问其他功能啦~