springboot整合jwt和基础用法
springboot整合jwt和基础用法 项目地址 pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.zuke</groupId> <artifactId>springboot-jwt</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springboot-jwt</name> <description>springboot-jwt</description> <properties> <java.version>17</java.version> </properties> <dependencies> <!-- jdk1.8以上需要加入依赖 --> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>javax.activation</groupId> <artifactId>activation</artifactId> <version>1.1.1</version> </dependency> <!-- jwt依赖 --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> <!-- web开发包 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- springboot test --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project> src/main/resources/application.yml server: port: 8802 实体类 src/main/java/com/zuke/springbootjwt/entity/User.java import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * @author zukedog@163.com * @date 2024/8/4 12:54 */ @Data @AllArgsConstructor @NoArgsConstructor public class User { private String username; private String password; private String token; } jwt工具类(按需修改) src/main/java/com/zuke/springbootjwt/utils/JwtUtils.java public class JwtUtil { /** * 生成JWT * @param username 用户名 * @param role 用户角色 * @param validTime JWT有效期(毫秒) * @param signature 签名密钥 * @return 生成的JWT字符串 */ public static String generateToken(String username, String role, long validTime, String signature) { JwtBuilder jwtBuilder = Jwts.builder(); String token = jwtBuilder // Header .setHeaderParam("typ", "JWT") .setHeaderParam("alg", "HS256") // Payload .claim("username", username) .claim("role", role) .setExpiration(new Date(System.currentTimeMillis() + validTime)) .setId(UUID.randomUUID().toString()) // Signature .signWith(SignatureAlgorithm.HS256, signature) .compact(); return token; } /** * 校验并解析JWT * @param token JWT字符串 * @param signature 签名密钥 * @return 解析后的Claims对象,如果校验失败则返回null */ public static TokenValidationResult checkToken(String token, String signature) { if (StringUtils.isEmpty(token) || StringUtils.isEmpty(signature)) { return new TokenValidationResult(false, TokenValidationError.INVALID_TOKEN); } try { Claims claims = Jwts.parser() .setSigningKey(signature) .parseClaimsJws(token) .getBody(); return new TokenValidationResult(true, TokenValidationError.INVALID_TOKEN); } catch (ExpiredJwtException e) { // 令牌已过期 return new TokenValidationResult(false, TokenValidationError.EXPIRED_TOKEN); } catch (SignatureException e) { // 签名验证失败 return new TokenValidationResult(false, TokenValidationError.INVALID_SIGNATURE); } catch (MalformedJwtException e) { // 令牌构造不正确 return new TokenValidationResult(false, TokenValidationError.MALFORMED_TOKEN); } catch (JwtException e) { // 其他JWT相关异常 return new TokenValidationResult(false, TokenValidationError.INVALID_TOKEN); } } /** * 更新token的过期时间为1小时 * @param oldToken 原始token * @param signature 签名密钥 * @return 更新后的token,如果原token无效则返回null */ public static String updateTokenExpiration(String oldToken, String signature) { if (StringUtils.isEmpty(oldToken) || StringUtils.isEmpty(signature)) { return null; } try { // 解析原token Claims claims = Jwts.parser() .setSigningKey(signature) .parseClaimsJws(oldToken) .getBody(); // 获取原token中的信息 String username = claims.get("username", String.class); String role = claims.get("role", String.class); // 生成新token,有效期为1小时 long validTime = 1000 * 60 * 60; // 1小时 return generateToken(username, role, validTime, signature); } catch (JwtException e) { // JWT解析失败 e.printStackTrace(); return null; } } /** * 验证token中的角色类型是否在允许的角色类型列表中 * @param token JWT字符串 * @param signature 签名密钥 * @param roleTypes 允许的角色类型数组 * @throws JwtException 当token无效或角色类型不匹配时抛出 * @throws IllegalArgumentException 当参数为空时抛出 */ public static void validateTokenRole(String token, String signature, String[] roleTypes) { // 参数校验 if (StringUtils.isEmpty(token) || StringUtils.isEmpty(signature) || roleTypes == null || roleTypes.length == 0) { throw new IllegalArgumentException("Token, signature and roleTypes cannot be null or empty"); } try { // 解析token Claims claims = Jwts.parser() .setSigningKey(signature) .parseClaimsJws(token) .getBody(); // 获取token中的角色 String tokenRole = claims.get("role", String.class); if (StringUtils.isEmpty(tokenRole)) { throw new JwtException("Token does not contain role information"); } // 检查角色是否在允许的列表中 boolean roleMatched = false; for (String allowedRole : roleTypes) { if (tokenRole.equals(allowedRole)) { roleMatched = true; break; } } // 如果角色不匹配,抛出异常 if (!roleMatched) { throw new CustomException("此操作不允许使用此用户角色"); } } catch (JwtException e) { throw new CustomException(e.getMessage()); } } public static Claims parseToken(String token) { return Jwts.parser() .setSigningKey(Constant.JWT_SIGNATURE) .parseClaimsJws(token) .getBody(); } } 配置允许跨域 src/main/java/com/zuke/springbootjwt/config/CrosConfiguration.java import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * @author zukedog@163.com * @date 2024/8/4 13:45 */ @Configuration public class CrosConfiguration implements WebMvcConfigurer { //解决跨域问题 @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS") .allowCredentials(true) .maxAge(3600) .allowedHeaders("*"); } } 测试接口 src/main/java/com/zuke/springbootjwt/controller/UserController.java import com.zuke.springbootjwt.entity.User; import com.zuke.springbootjwt.utils.JwtUtils; import io.jsonwebtoken.Claims; import jakarta.servlet.http.HttpServletRequest; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; /** * @author zukedog@163.com * @date 2024/8/4 12:55 */ @RestController public class UserController { //模拟数据库密码 private final String USERNAME = "root"; private final String PASSWORD = "root"; private final String SIGNATURE = "root"; @PostMapping("/login") public String login(@RequestBody User user) { if (USERNAME.equals(user.getUsername()) && PASSWORD.equals(user.getPassword())){ //添加token return JwtUtils.generateToken(user.getUsername(),"user",1000*60*60,SIGNATURE); } return null; } @GetMapping("/checkToken") public boolean checkToken(HttpServletRequest request){ String token = request.getHeader("token"); return JwtUtils.checkToken(token,SIGNATURE); } }
