目录
练习黑马的苍穹外卖时,因为黑马用的是springboot2,我打算使用springboot3写一个;于是下面就是springboot3整合jjwt:
项目环境:
SpringBoot:3.1.2
JDK:17
jjwt:0.12.3
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>${jjwt.version}</version> </dependency>引入这一个就行了
1.application.yml文件配置
ysy:
jwt:
# 设置jwt签名加密时使用的秘钥 HMAC-SHA算法32字节
admin-secret-key: ysyysyysyysyysyysyysyysyysyysyys
# 设置jwt过期时间
admin-ttl: 7200000
# 设置前端传递过来的令牌名称
admin-token-name: token
2.JwtUtil文件配置
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SecureDigestAlgorithm;
import lombok.extern.slf4j.Slf4j;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;
/**
* @ClassName JwtUtil工具类
* @project agriBlissMart_common
* @Description
* @Version 1.0
*/
@Slf4j
public class JwtUtil {
/**
* 生成jwt
* 使用Hs256算法,私钥使用固定密钥
* @param secretKey jwt密钥
* @param ttlMillis jwt过期时间,单位毫秒
* @param claims 设置的信息
* @return
*/
public static String createJWT(String secretKey, long ttlMillis, Map<String, Object> claims){
//指定加密算法
SecureDigestAlgorithm<SecretKey, SecretKey> algorithm = Jwts.SIG.HS256;
//生成JWT的时间
long expMillis = System.currentTimeMillis()+ttlMillis;
Date exp = new Date(expMillis);
//密钥实例
SecretKey key = Keys.hmacShaKeyFor(secretKey.getBytes());
String compact = Jwts.builder()
.signWith(key, algorithm) //设置签名使用的签名算法和签名使用的秘钥
//如果有私有声明,一点要先设置这个自己创建的私有的声明,这个是给builder的claims赋值,一旦卸载标准的声明赋值之后,就是覆盖了那些标准的声明的
.expiration(exp)
.claims(claims) //设置自定义负载信息
.compact();//设置过期时间
return compact;
}
/**
* 解析jwt
* @param token
* @param secretKey
* @return
*/
public static Jws<Claims> parseJWT(String token, String secretKey){
//密钥实例
SecretKey key = Keys.hmacShaKeyFor(secretKey.getBytes());
Jws<Claims> claimsJws = Jwts.parser()
.verifyWith(key) //设置签名的密钥
.build()
.parseSignedClaims(token); //设置要解析的jwt
return claimsJws;
}
}
3.JwtTokenAdminInterceptor拦截器
import cn.ysy.constant.JwtClaimsConstant;
import cn.ysy.context.BaseContext;
import cn.ysy.properties.JwtProperties;
import cn.ysy.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
@Component
@Slf4j
public class JwtTokenAdminInterceptor implements HandlerInterceptor {
@Autowired
private JwtProperties jwtProperties;
/**
* 拦截器 校验jwt
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
//判断当前拦截到的是Controller的方法还是其他资源
if(!(handler instanceof HandlerMethod)){
//当前拦截到的不是动态方法,直接放行
return true;
}
//从请求头中获取令牌
String token = request.getHeader(jwtProperties.getAdminTokenName());
//校验令牌
try{
log.info("jwt校验:{}",token);
Jws<Claims> claimsJws = JwtUtil.parseJWT(token, jwtProperties.getAdminSecretKey());
Long farId = Long.valueOf(claimsJws.getPayload().get(JwtClaimsConstant.FAR_ID).toString());
log.info("当前农户id:{}",farId);
BaseContext.setCurrentId(farId); //设置当前登录的用户id
//放行
return true;
}catch (Exception e){
//不通过,响应401状态码
response.setStatus(HttpStatus.SC_UNAUTHORIZED);
return false;
}
}
}
4.WebMvcConfiguration配置类
这里面也定义了knife4j;具体的springboot3整合knife4j可以去我主页看看,也是有的
import cn.ysy.interceptor.JwtTokenAdminInterceptor;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
/**
* 配置类,注册web层相关组件
* @ClassName WebMvcConfiguration
* @Description WebMvcConfiguration
* @Version 1.0
*/
@Slf4j
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
@Autowired
private JwtTokenAdminInterceptor jwtTokenAdminInterceptor;
/**
* 注册拦截器
* @param registry
*/
protected void addInterceptors(InterceptorRegistry registry) {
log.info("开始注册自定义拦截器。。。");
registry.addInterceptor(jwtTokenAdminInterceptor)
.addPathPatterns("/admin/**")
.excludePathPatterns("/admin/farmer/login");
}
/**
* 创建OpenAPI对象
* @return OpenAPI
*/
@Bean
public OpenAPI springShopOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("农智云后台管理系统接口文档") // 接口文档标题
.description("这是基于Knife4j OpenApi3的农智云后台管理系统的接口文档") // 接口文档简介
.version("1.0") // 接口文档版本
.contact(new Contact()
.name("乆乄") //开发者
.email("1234567896@qq.com")
)
); // 开发者联系方式
}
/**
* 添加静态资源映射
* @param registry
*/
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
5.Controller层
import cn.ysy.constant.JwtClaimsConstant;
import cn.ysy.dto.FarmerDTO;
import cn.ysy.dto.FarmerLoginDTO;
import cn.ysy.entity.Farmer;
import cn.ysy.properties.JwtProperties;
import cn.ysy.result.Result;
import cn.ysy.service.FarmerService;
import cn.ysy.utils.JwtUtil;
import cn.ysy.vo.FarmerLoginVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@Slf4j
@Tag(name = "农户管理")
@RequestMapping("/admin/farmer")
public class FarmerController {
@Autowired
private FarmerService farmerService;
@Autowired
private JwtProperties jwtProperties;
@PostMapping("/login")
@Operation(description = "农户登录")
public Result<FarmerLoginVO> login(@RequestBody FarmerLoginDTO farmerLoginDTO){
log.info("登录请求参数:{}",farmerLoginDTO);
Farmer farmer = farmerService.login(farmerLoginDTO);
//登录成功后,生成jwt令牌
Map<String, Object> claims = new HashMap<>();
claims.put(JwtClaimsConstant.FAR_ID,farmer.getId());
String token = JwtUtil.createJWT(
jwtProperties.getAdminSecretKey(),
jwtProperties.getAdminTtl(),
claims);
FarmerLoginVO farmerLoginVO = FarmerLoginVO.builder()
.name(farmer.getName())
.token(token)
.id(farmer.getId())
.build();
return Result.success(farmerLoginVO);
}
/**
* 农户退出
* @return
*/
@PostMapping("/logout")
@Operation(description = "农户退出")
public Result<String> logout(){
return Result.success();
}
@PostMapping
@Operation(description = "新增农户")
public Result save(@RequestBody FarmerDTO farmerDTO){
log.info("新增请求参数:{}",farmerDTO);
farmerService.save(farmerDTO);
return Result.success();
}
}
6.测试农户户登录和添加农户
启动项目。浏览器输入:http://localhost:8080/doc.html
6.1.测试登录:
6.2.将token配置到全局参数里
6.3.测试添加农户操作
不勾选时:
不勾选时后台是拿不到token的,所以不要忘记勾选
勾选时:
响应成功,刷新数据库查看信息;