本文,我们将 JWT
整合到 Spring Boot
中。
JWT 是什么?
JWT -> JSON Web Token
JWT
是一种开放标准(RFC 7519),用于在网络应用中传递声明信息。
JWT
到一大优势是它的可扩展性和自包含性。它可以在各个系统之间进行安全传输和验证,因为它包含了所有必要的信息,并且经过签名保证了数据的完整性。JWT
通常用于身份验证和授权机制,比如 Web
应用中通过 JWT
来验证用于的身份,下面我们就来实践一下。
本文的实践案例,基于本人之前的文章 Spring Boot 整合 Swagger 接口文档工具项目。
安装依赖
安装 JWT
依赖:
xml
<!-- 引入jwt-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.2</version>
</dependency>
添加 JWT 处理方法
我们这里使用用户字段 id
,name
和 password
来创建 token
。
1. 生成 token
java
// 生成 token
public static String createToken(User user) {
Date expireDate = new Date(System.currentTimeMillis() + EXPIRATION * 1000);
Map<String, Object> map = new HashMap<>();
map.put("alg", "HS256");
map.put("typ", "JWT");
System.out.println(user+"user");
String token = JWT.create()
.withClaim("id", user.getId())
.withClaim("name", user.getName())
.withClaim("password", user.getPassword())
.withExpiresAt(expireDate)
.withIssuedAt(new Date())
.sign(Algorithm.HMAC256(SECRET));
return token;
}
2. 验证 token
java
// 校验 token
public static Map<String, Claim> verifyToken(String token) {
DecodedJWT jwt = null;
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
jwt = verifier.verify(token);
} catch (Exception e) {
return null;
}
return jwt.getClaims();
}
完整的代码如下。我们在包 com.launch.util
下创建 JwtTokenUtils.java
文件:
java
package com.launch.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.launch.model.User;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class JwtTokenUtils {
private static final String SECRET = "jwtSECRET"; // 密钥
private static final long EXPIRATION = 3600L; // 3600 秒
// 生成 token
public static String createToken(User user) {
Date expireDate = new Date(System.currentTimeMillis() + EXPIRATION * 1000);
Map<String, Object> map = new HashMap<>();
map.put("alg", "HS256");
map.put("typ", "JWT");
System.out.println(user+"user");
String token = JWT.create()
.withClaim("id", user.getId())
.withClaim("name", user.getName())
.withClaim("password", user.getPassword())
.withExpiresAt(expireDate)
.withIssuedAt(new Date())
.sign(Algorithm.HMAC256(SECRET));
return token;
}
// 校验 token
public static Map<String, Claim> verifyToken(String token) {
DecodedJWT jwt = null;
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
jwt = verifier.verify(token);
} catch (Exception e) {
return null;
}
return jwt.getClaims();
}
}
创建过滤文件
我们紧接着创建拦截的过滤文件。我们在包 com.launch.config.authenticationhandler.jwt
下创建文件 JwtFilter.java
:
java
package com.launch.config.authenticationhandler.jwt;
import com.auth0.jwt.interfaces.Claim;
import com.launch.util.JwtTokenUtils;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
// /api/user/secure/* 的文件起作用
@WebFilter(filterName = "JwtFilter", urlPatterns = "/api/user/secure/*")
public class JwtFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
response.setCharacterEncoding("UTF-8");
final String token = request.getHeader("Auth");
if("OPTIONS".equals(request.getMethod())) { // 是否是 OPTIONS 请求
response.setStatus(HttpServletResponse.SC_OK);
chain.doFilter(request, response);
}
else {
if(token == null) {
response.getWriter().write("no token");
return;
}
Map<String, Claim> userData = JwtTokenUtils.verifyToken(token); // 检验 token
if(userData == null) {
response.getWriter().write("token illegal");
return;
}
Integer id = userData.get("id").asInt(); // 获取 id
String userName = userData.get("name").asString(); // 获取用户名
String password = userData.get("password").asString(); // 获取密码
request.setAttribute("id", id); // 设置 id
request.setAttribute("username", userName); // 设置用户名
request.setAttribute("password", password); // 设置密码
chain.doFilter(req, res); // 过滤成功
}
}
@Override
public void destroy() {}
}
这个文件做了什么事情呢?
urlPatterns = "/api/user/secure/*"
表示接口 /api/user/secure/*
下的接口需要经过验证才可以访问。
request.getHeader("Auth")
我们通过 request
请求的 header
中获取提前存在字段 Auth
上的 token
值。在真实登陆的时候就会存储进去 Auth
内。
request.setAttribute("id", id);
将获取的 id
值存在 request
请求上。username
,password
同理。
为了过滤器能够生效,我们需要在入口类添加注释 @ServletComponentScan(basePackages="com.launch.config.authenticationhandler.jwt")
。
验证
最后,我们验证下 token
是否集成生效。该操作在包 com.lauch.controller
下 UserController.java
文件中操作。
我们模拟登陆,生成 token
:
java
// 用户登陆
@GetMapping("/login")
String login(User user) {
// jimmy simulation
// {
// "id": 2,
// "name": "Jimmy",
// "age": 18,
// "password": "123456"
// }
String token = JwtTokenUtils.createToken(user);
return token;
}
下面我们来获取当前登陆的用户信息。
java
@GetMapping("/secure/current_registrant")
public String currentRegistrant(HttpServletRequest request) {
Integer id = (Integer) request.getAttribute("id");
String username = request.getAttribute("username").toString();
String password = request.getAttribute("password").toString();
return "当前用户信息: id="+id+" ,username="+username+" ,password="+password;
}
上面也提及到了,我们是要获取 request
中 header
上 Auth
的值。这里就有 Auth = eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXNzd29yZCI6IjEyMzQ1NiIsIm5hbWUiOiJKaW1teSIsImlkIjoyLCJleHAiOjE2OTExNjA0NjMsImlhdCI6MTY5MTE1Njg2M30.nIP23eI-vgIZC-Fw2FGDQw1GrXlA4mBVBb3vkSFySgc
。我们在 postman
上设置,并请求该接口:
参考
- JSON Web Token 入门教程
- 五分钟带你了解啥是JWT
- SpringBoot 快速集成 JWT 实现用户登录认证
- 《Spring Boot 实战派》