SpringBoot 3.x 整合 JWT 、Swagger(使用springdoc)
·
1、目录结构

2、Maven
<!-- 使用 springdoc 生成 swagger 文档 -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.5.0</version>
</dependency>
<!-- jjwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.12.5</version>
</dependency>
3、JwtUtils(创建、解析token)
package com.dragon.springboot3vue3.utils;
import com.alibaba.fastjson2.JSON;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Encoders;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import java.util.Date;
import java.util.UUID;
@Component
public class JwtUtils {
// 设置有效期30min
private static final long JWT_EXPIRE = 30*60*1000L;
// 生成密钥
private static final SecretKey secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
// 密钥转 Base64 编码
private static final String base64Key = Encoders.BASE64.encode(secretKey.getEncoded());
/**
* 用jwt创建token
* @param data
* @return
*/
public String createToken(Object data){
// 当前时间
long currentTime=System.currentTimeMillis();
// 过期时间
long expireTime=currentTime+JWT_EXPIRE;
// 构建jwt
JwtBuilder builder= Jwts.builder()
.setId(UUID.randomUUID()+"")
.setSubject(JSON.toJSONString(data))
.setIssuer("system")
.setIssuedAt(new Date(currentTime))
.signWith(secretKey,SignatureAlgorithm.HS256)
.setExpiration(new Date(expireTime));
return builder.compact();
}
/**
* 解析token
* @param token
* @return
*/
public Claims parseToken(String token){
Claims body=Jwts.parser()
.setSigningKey(base64Key)
.build()
.parseClaimsJws(token)
.getBody();
return body;
}
/**
* 解析token,返回json格式对象
* @param token
* @param tClass
* @param <T>
* @return
*/
public <T> T parseToken(String token,Class<T> tClass){
Claims body=Jwts.parser()
.setSigningKey(base64Key)
.build()
.parseClaimsJws(token)
.getBody();
return JSON.parseObject(body.getSubject(),tClass);
}
}
4、ThreadLocalUtils(保存登录的用户信息)
package com.dragon.springboot3vue3.utils;
public class ThreadLocalUtils {
private static final ThreadLocal THREAD_LOCAL = new ThreadLocal();
public static <T> T get(){
return (T) THREAD_LOCAL.get();
}
public static void set(Object value){
THREAD_LOCAL.set(value);
}
public static void remove(){
THREAD_LOCAL.remove();
}
}
5、JwtInterceptor(JWT拦截器)
package com.dragon.springboot3vue3.interceptor;
import com.alibaba.fastjson2.JSON;
import com.dragon.springboot3vue3.controller.dto.RegisterOrLoginDto;
import com.dragon.springboot3vue3.entity.User;
import com.dragon.springboot3vue3.service.IUserService;
import com.dragon.springboot3vue3.utils.JwtUtils;
import com.dragon.springboot3vue3.utils.Result;
import com.dragon.springboot3vue3.utils.ThreadLocalUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@Slf4j
@Component
public class JwtInterceptor implements HandlerInterceptor {
@Autowired
private JwtUtils jwtUtils;
@Autowired
private IUserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token=request.getHeader("X-Token");
if(token!=null){
try {
String username = jwtUtils.parseToken(token, RegisterOrLoginDto.class).getUsername();
User user=userService.lambdaQuery().eq(User::getUsername,username).one();
// 把业务数据存储到ThreadLocal(ThreadLocal 线程安全,能实现数据共享)
ThreadLocalUtils.set(user);
return true;
} catch (Exception e) {
log.error(e.toString());
}
}
log.debug(request.getRequestURI()+" 验证token失败,禁止访问");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(JSON.toJSONString(Result.error(20000,"Token无效,请重新登录")));
return false;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
ThreadLocalUtils.remove();
}
}
6、SwaggerConfig(swagger配置类)
package com.dragon.springboot3vue3.config;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI openAPI() {
OpenAPI openAPI = new OpenAPI();
openAPI.info(new Info().title("前后端分离管理系统")
.description("使用springboot3-vue3等技术")
.version("v1.0.0")
.license(new License().name("Apache 2.0").url("https://springdoc.org")));
openAPI.externalDocs(new ExternalDocumentation().description("项目API文档")
.url("/"));
// 配置 Authorize 登录鉴权
Map<String, SecurityScheme> map = new HashMap<>();
map.put("X-Token", new SecurityScheme().type(SecurityScheme.Type.APIKEY).in(SecurityScheme.In.HEADER).name("X-Token"));
openAPI.components(new Components().securitySchemes(map));
map.keySet().forEach(key -> openAPI.addSecurityItem(new SecurityRequirement().addList(key)));
return openAPI;
}
}
7、InterceptorConfig(拦截器配置类)
package com.dragon.springboot3vue3.config;
import com.dragon.springboot3vue3.interceptor.JwtInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
private JwtInterceptor jwtInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor)
.excludePathPatterns(
"/user/register",
"/user/login",
"/user/logout",
"/swagger-ui/**",
"/v3/**"
);
}
}
8、Controller使用SpringDoc注解
package com.dragon.springboot3vue3.controller;
import com.dragon.springboot3vue3.controller.dto.RegisterOrLoginDto;
import com.dragon.springboot3vue3.entity.User;
import com.dragon.springboot3vue3.service.IUserService;
import com.dragon.springboot3vue3.utils.JwtUtils;
import com.dragon.springboot3vue3.utils.MD5Utils;
import com.dragon.springboot3vue3.utils.Result;
import com.dragon.springboot3vue3.utils.ThreadLocalUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@Tag(name = "用户接口")
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private IUserService userService;
@Autowired
private JwtUtils jwtUtils;
@Operation(summary = "注册")
@PostMapping("/register")
public Result register(@RequestBody @Validated RegisterOrLoginDto registerDto){
User user=userService.lambdaQuery().eq(User::getUsername,registerDto.getUsername()).one();
if(user!=null){
return Result.error("用户名被占用,请重新输入!");
}
userService.register(registerDto);
return Result.success();
}
@Operation(summary = "登录")
@PostMapping("/login")
public Result login(@RequestBody @Validated RegisterOrLoginDto loginDto){
User user=userService.lambdaQuery().eq(User::getUsername,loginDto.getUsername()).one();
if(user!=null && user.getPassword().equals(MD5Utils.encode(loginDto.getPassword()))){
String token =jwtUtils.createToken(loginDto);
return Result.success(token);
}
return Result.error("用户名或密码输入错误!");
}
@Operation(summary = "获取登录用户信息")
@GetMapping("/userInfo")
public Result userInfo(){
User user = ThreadLocalUtils.get();
return Result.success(user);
}
@Operation(summary = "更新用户基本信息")
@PutMapping("/update")
public Result update(@RequestBody User userDto){
User user = ThreadLocalUtils.get();
BeanUtils.copyProperties(userDto,user);
userService.updateById(user);
return Result.success();
}
}
9、swagger-ui地址:http://localhost:8080/swagger-ui/index.html

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)