文章目录
- 一、JWT使用步骤
- 二、SpringBoot整合JWT
一、JWT使用步骤
- 引入依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
- 生成token
//用来给令牌设置过期时间
Calendar instance = Calendar.getInstance();
instance.add(Calendar.SECOND, 90); //令牌存活90秒
//生成令牌
String token = JWT.create()
//无需设置令牌Header,使用默认值即可,使用withHeader(HashMap对象)可设置
.withClaim("username", "张三") //设置负载
.withExpiresAt(instance.getTime()) //设置过期时间(可选、尽量设置)
.sign(Algorithm.HMAC256("Q2W#E$RW")); //设置自定义签名及签名算法
//输出令牌
System.out.println(token);
- 根据令牌和签名解析数据
//创建验证对象,参数是指定的签名及密钥
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("Q2W#E$RW")).build();
//创建解码后的JWT对象
DecodedJWT decodedJWT = jwtVerifier.verify(token); //参数是上一步生成的JWT字符串
System.out.println("用户名: " + decodedJWT.getClaim("username").asString());
//数值型使用asInt()
System.out.println("过期时间: "+decodedJWT.getExpiresAt());
- 常见的异常信息
二、SpringBoot整合JWT
- 创建工具类
public class JWTUtils {
//自定义密钥,创建JWT和验证时都需要使用
private static final String SING = "!Q@W3e4r%T^Y";
//方法一:创建令牌,参数是载荷部分
public static String getToken(Map<String,String> map){
//设置令牌过期时间
Calendar instance = Calendar.getInstance();
instance.add(Calendar.DATE,7); //7天过期
//创建JWT Builder,使用此对象可向令牌中添加标头、载荷、签名
JWTCreator.Builder builder = JWT.create();
//添加载荷
map.forEach((k,v)->{
builder.withClaim(k,v);
});
//设置过期时间和签名并生成Token
String token = builder.withExpiresAt(instance.getTime()) //指定令牌过期时间
.sign(Algorithm.HMAC256(SING)); //设置签名
return token;
}
//方法二:验证令牌并返回解码后的JWT数据
public static DecodedJWT verify(String token){
//一旦验证失败此方法会抛出异常
return JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
}
}
- 项目引入需要的坐标、配置application文件连接数据库
- 思路:前端带上用户名和密码访问后端的接口查询数据库,判断用户是否存在,若存在则创建 JWT字符串,将id和用户名作为JWT的有效载荷部分,并将创建出的JWT字符串返回给 前端,之后前端发送的请求都需要包含JWT去访问令牌所允许的资源等
- 创建数据库
- 创建实体类
@Data
public class User {
private String id;
private String name;
private String password;
}
- 创建DAO接口及对应的Mapper.xml文件,并在配置文件中进行注册
@Mapper
public interface UserDAO {
User login(User user);
}
<select id="login" parameterType="User" resultType="User">
select * from user where name=#{name} and password = #{password}
</select>
- 创建Service接口及实现类
public interface UserService {
User login(User user);
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDAO userDAO;
@Override
public User login(User user) {
//根据接收的用户名和密码查询数据库
User userDB = userDAO.login(user);
if(userDB!=null){ return userDB; }
throw new RuntimeException("认证失败~~");
}
}
- 创建Controller
@RestController
@Slf4j
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/user/login")
public Map<String,Object> login(User user) {
Map<String,Object> result = new HashMap<>(); //封装结果状态及信息
try {
//查询成功,返回结果及创建JWT字符串
User userDB = userService.login(user);
Map<String, String> map = new HashMap<>();//用来存放payload
map.put("id",userDB.getId());
map.put("username", userDB.getName());
//密码等重要信息并不放在载荷中
String token = JWTUtils.getToken(map);
result.put("state",true);
result.put("msg","登录成功!!!");
result.put("token",token); //成功返回token信息
} catch (Exception e) {
//查询失败
e.printStackTrace();
result.put("state","false");
result.put("msg",e.getMessage());
}
return result;
}
}
- 进行测试
- 创建验证接口
@PostMapping("/test/test")
public Map<String, Object> test(String token) {
Map<String, Object> map = new HashMap<>(); //封装结果状态及信息
try {
JWTUtils.verify(token);
map.put("msg", "验证通过~~~");
map.put("state", true);
} catch (TokenExpiredException e) {
map.put("state", false);
map.put("msg", "Token已经过期!!!");
} catch (SignatureVerificationException e){
map.put("state", false);
map.put("msg", "签名错误!!!");
} catch (AlgorithmMismatchException e){
map.put("state", false);
map.put("msg", "加密算法不匹配!!!");
} catch (Exception e) {
e.printStackTrace();
map.put("state", false);
map.put("msg", "无效token~~");
}
return map;
}