Java: JWT
测试JWT
package com.example.jwt;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.example.jwt.util.JWTUtil;
import org.junit.jupiter.api.Test;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.HashMap;
public class TestJwt{
@Test
void generate() throws InterruptedException{
HashMap<String, Object> hashMap = new HashMap<>();
LocalDateTime localDateTime = LocalDateTime.now().plusSeconds(3);
System.out.println("localDateTime = " + localDateTime);
String sign = JWT.create()
.withHeader(hashMap) // 可省略
.withClaim("id", 55)
.withClaim("name", "proofread")
.withExpiresAt(Date.from(localDateTime.toInstant(ZoneOffset.ofHours(8)))).sign(Algorithm.HMAC256("ruzz"));
System.out.println("\033[37;7m" + sign + "\033[0m");
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("ruzz")).build();
System.out.println("\033[37;7m" + sign + "\033[0m");
DecodedJWT decodedJWT = jwtVerifier.verify(sign);
Claim id = decodedJWT.getClaim("id");
System.out.println("\033[37;7m" + id.asInt() + "\033[0m");
Claim name = decodedJWT.getClaim("name");
System.out.println("\033[37;7m" + name.asString() + "\033[0m");
Date expiresAt = decodedJWT.getExpiresAt();
System.out.println("expiresAt = " + expiresAt);
Thread.sleep(3500);
try{
DecodedJWT decodedJWT1 = jwtVerifier.verify(sign);
}catch(JWTVerificationException e){
throw new RuntimeException(e);
}
}
}
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.19.1</version>
</dependency>
Springboot整合:
application.yaml
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/ssm?characterEncoding=UTF-8
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: coalesce
mvc:
servlet:
path: /servlet
# Mybatis
mybatis:
mapper-locations: classpath:mapper/*.xml # mapper配置文件位置
type-aliases-package: com.example.jwt.entity # 实体类包名, 默认别名: 类名首字母小写
# Logging
logging:
charset:
console: UTF-8
file: UTF-8
level:
root: info # 全局
org.springframework: info # 第三方
com.example.jwt: info
com.example.jwt.dao: debug
sql: debug
web: debug
server:
servlet:
context-path: /ctx
UserDAO.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.jwt.dao.UserDAO">
<select id="login" parameterType="User" resultType="User">
SELECT * FROM users WHERE name = #{name} AND password = #{password}
</select>
</mapper>
DAO层:
package com.example.jwt.dao;
import com.example.jwt.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserDAO{
User login(User user);
}
实体类
package com.example.jwt.entity;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class User{
private Integer id;
private String name;
private String password;
}
启动类
package com.example.jwt;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan(value = {"com.example.jwt.dao"})
public class JwtApplication{
public static void main(String[] args){
SpringApplication.run(JwtApplication.class, args);
}
}
工具类
package com.example.jwt.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.Map;
public class JWTUtil{
private static final String secret = "compound";
private static final Algorithm ALGORITHM = Algorithm.HMAC384(secret);
public static String getToken(Map<String, String> map){
// 默认7天过期
ZonedDateTime zonedDateTime = LocalDateTime.now().plusDays(7).atZone(ZoneId.systemDefault());
Date expireDate = Date.from(zonedDateTime.toInstant());
JWTCreator.Builder builder = JWT.create();
map.forEach(builder::withClaim); // 构建payload
return builder.withExpiresAt(expireDate).sign(ALGORITHM);
}
public static DecodedJWT verifyToken(String token){
return JWT.require(ALGORITHM).build().verify(token);
}
}
Service层:
UserService.java
package com.example.jwt.service;
import com.example.jwt.entity.User;
public interface UserService{
User login(User user);
}
UserServiceImpl.java
package com.example.jwt.service;
import com.example.jwt.dao.UserDAO;
import com.example.jwt.entity.User;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class UserServiceImpl implements UserService{
private final UserDAO userDAO;
public UserServiceImpl(UserDAO userDAO){
this.userDAO = userDAO;
}
@Override
public User login(User user){
User userFromDB = userDAO.login(user);
if(userFromDB != null)
return userFromDB;
throw new RuntimeException("login failed");
}
}
Controller
package com.example.jwt.controller;
import com.example.jwt.entity.User;
import com.example.jwt.service.UserService;
import com.example.jwt.util.JWTUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping(value = "user")
public class UserController{
private final UserService userService;
@Autowired
public UserController(UserService userService){
this.userService = userService;
}
@RequestMapping(value = "login")
public Map<String, Object> login(User user){
System.out.println("\033[37;7m" + user + "\033[0m");
HashMap<String, Object> hashMap = new HashMap<>();
try{
User userFromDB = userService.login(user);
HashMap<String, String> payload = new HashMap<>();
payload.put("id", String.valueOf(userFromDB.getId()));
payload.put("name", userFromDB.getName());
payload.put("password", userFromDB.getPassword());
String token = JWTUtil.getToken(payload);
JWTUtil.getToken(payload);
hashMap.put("state", true);
hashMap.put("msg", "success");
hashMap.put("token", token);
}catch(Exception e){
hashMap.put("state", false);
hashMap.put("msg", e.getMessage());
}
return hashMap;
}
@PostMapping(value = "test")
public Map<String, Object> test(String token){
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("state", true);
hashMap.put("msg", "success");
return hashMap;
}
}
HandlerInterceptor
package com.example.jwt.interceptor;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.example.jwt.util.JWTUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
public class JWTInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
HashMap<String, Object> hashMap = new HashMap<>();
String token = request.getHeader("token");
try{
JWTUtil.verifyToken(token);
return true;
}catch(SignatureVerificationException e){
e.printStackTrace();
hashMap.put("msg", "Signature has been modified"); // secret几乎不可能出错
}catch(TokenExpiredException e){
e.printStackTrace();
hashMap.put("msg", "Token has expired");
}catch(AlgorithmMismatchException e){
e.printStackTrace();
hashMap.put("msg", "Algorithm mismatched");
}catch(JWTDecodeException e){
e.printStackTrace();
hashMap.put("msg", "Token format invalid");
}catch(Exception e){
e.printStackTrace();
hashMap.put("msg", "Invalid token");
}
hashMap.put("state", false);
String json = new ObjectMapper().writeValueAsString(hashMap);
response.setContentType("application/json; charset=UTF-8");
response.getWriter().println(json);
return false;
}
}
添加HandlerInterceptor
package com.example.jwt.config;
import com.example.jwt.interceptor.JWTInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
// @Component
@Configuration
public class InterceptorConfig implements WebMvcConfigurer{
@Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(new JWTInterceptor())
.addPathPatterns("/user/**") // 与context-path & servlet.path无关
.excludePathPatterns("/user/login");
}
}