informasi kontak saya
Surat[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Artikel ini terutama menjelaskan metode pengaturan informasi jwt di filter untuk menyimpan informasi identitas melalui kelas filter springboot.
Proses: Permintaan->Filter->Parsing informasi isi permintaan->Masukkan ke threadlocal
Tentukan filter: filter (Filter) menggunakan spesifikasi Servlet, yang didaftarkan melalui anotasi @WebFilter untuk mencegat semua permintaan HTTP yang cocok dengan jalur /api.
Anotasi @WebFilter("/api") menetapkan bahwa filter akan diterapkan ke semua permintaan yang mengakses jalur /api.
@Anotasi komponen:
@Component adalah anotasi kerangka Spring, yang menunjukkan bahwa JwtFilter adalah komponen Spring yang dapat dikelola oleh container Spring dan mendukung injeksi ketergantungan.
metode lakukanFilter:
Metode doFilter mendefinisikan bagaimana filter mencegat dan memproses permintaan dan respons yang memasuki wadah Servlet atau Servlet.
Tanda tangan metode:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException;
Metode ini menerima tiga parameter: permintaan ServletRequest, respons ServletResponse, dan rantai FilterChain.
Ini mungkin memunculkan IOException atau ServletException.
Permintaan dan tanggapan:
Dua parameter pertama dari metode doFilter mewakili objek permintaan dan respons saat ini. Anda dapat membaca data permintaan dan mengubah permintaan dan respons dalam metode ini.
Biasanya, di akhir metode doFilter, Anda perlu memanggil chain.doFilter(request, respon) untuk terus mengeksekusi filter atau sumber daya target berikutnya dalam rantai filter.
Jika Anda ingin memodifikasi ulang konten permintaan, Anda dapat menggunakan HttpServletRequestWrapper. HttpServletRequestWrapper adalah kelas wrapper yang memperluas antarmuka HttpServletRequest, memungkinkan Anda untuk memodifikasi atau memperluas pemrosesan permintaan. Tujuan penggunaan HttpServletRequestUriWrapper (yang mungkin merupakan kelas pembungkus khusus yang diwarisi dari HttpServletRequestWrapper) biasanya mencakup:
Ubah URI permintaan:
Anda mungkin ingin mengubah URI permintaan, tetapi bukan objek HttpServletRequest yang asli. Dengan menggunakan HttpServletRequestUriWrapper, Anda dapat menggabungkan permintaan asli dan memberikan URI yang dimodifikasi.
Biarkan permintaan awal tidak berubah:
Menggunakan wrapper menjaga objek permintaan asli tidak berubah sekaligus memungkinkan Anda mengubah aspek tertentu dari permintaan di beberapa titik dalam rantai pemfilteran.
Pemfilteran dan pra-pemrosesan:
Sebelum memanggil filterChain.doFilter, Anda dapat menambahkan logika prapemrosesan apa pun dalam metode doFilter, seperti mengubah parameter permintaan, mengubah jalur permintaan, menambahkan atau memodifikasi header permintaan, dll.
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
@WebFilter("/api")
@Component
@Slf4j
public class JwtFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
// noting to do
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
var httpRequest = (HttpServletRequest) servletRequest;
var requestBodyPayload = StreamUtils.copyToString(servletRequest.getInputStream(), StandardCharsets.UTF_8);
// 解析Body参数,并存入threadLocal管理
var jwtInfo = JwtUtil.getJwtInfoFromReq(requestBodyPayload);
JwtUtil.setJwtInfo(jwtInfo);
// 读取过body,需要重新设置body
var wrapper = new HttpServletRequestUriWrapper(httpRequest, httpRequest.getRequestURI(), requestBodyPayload);
// 将请求传递到下一个过滤器(或者最终到达控制器方法)
filterChain.doFilter(wrapper, servletResponse);
}
@Override
public void destroy() {
JwtUtil.removeJwtInfo();
MDC.clear();
}
}
informasi jwt:
@Slf4j
@Component
public class JwtUtil {
/** 线程jwt信息维护 */
private static final ThreadLocal<JwtInfo> REQUEST_BASE_INFO_THREAD_LOCAL = new ThreadLocal<>();
/** 解析jwt信息 */
public static JwtInfo getJwtInfoFromReq(String requestBodyPayload) {
var jwtInfo = new JwtInfo();
try {
var requestBody = JsonUtil.getJsonNode(requestBodyPayload);
log.info("[JwtUtil] RequestBody -> {}", requestBody);
// 解析requestBody,转为jwtInfo对象
jwtInfo.setRequestId(requestBody.get("RequestId") != null ? requestBody.get("RequestId").asText() : "");
jwtInfo.setRegion(requestBody.get("Region") != null ? requestBody.get("Region").asText() : "");
log.info("[JwtUtil] JwtInfo -> {}", jwtInfo);
} catch (Exception e) {
log.error("[JwtUtil] Parse RequestBodyInfo Error, Error Message -> {}", e.getMessage(), e);
}
return jwtInfo;
}
/** 获取jwt信息 */
public static JwtInfo getJwtInfo() {
var jwtInfo = REQUEST_BASE_INFO_THREAD_LOCAL.get();
if (Objects.isNull(jwtInfo)) {
final var requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (Objects.nonNull(requestAttributes)) {
var requestBodyPayload = "";
try {
requestBodyPayload = StreamUtils.copyToString(requestAttributes.getRequest().getInputStream(),
StandardCharsets.UTF_8);
} catch (Exception e) {
log.error("[JwtUtil] Parse RequestBodyInfo Error, Error Message -> {}", e.getMessage());
}
jwtInfo = getJwtInfoFromReq(requestBodyPayload);
setJwtInfo(jwtInfo);
}
}
return jwtInfo;
}
/** 将jwt信息存入threadLocal中 */
public static void setJwtInfo(JwtInfo jwtInfo) {
REQUEST_BASE_INFO_THREAD_LOCAL.set(jwtInfo);
// 将traceId写入日志变量
MDC.put("traceId", jwtInfo.getRequestId());
}
public static void setJwtInfo(String appId, String ownerUin) {
var jwtInfo = new JwtUtil.JwtInfo();
jwtInfo.setRequestId(UUID.randomUUID().toString());
setJwtInfo(jwtInfo);
}
/** 从threadLocal中删除jwt信息 */
public static void removeJwtInfo() {
REQUEST_BASE_INFO_THREAD_LOCAL.remove();
}
@Data
public static class JwtInfo {
@JsonPropertyDescription("请求requestId")
private String requestId;
@JsonPropertyDescription("请求的Region")
private String region;
}
}
Dapatkan konten dalam jwt dan kirim permintaan http lainnya:
public static JsonNode sendHttpRequest(String method, String action, String url, Map<String, Object> body)
throws IOException, InterruptedException {
// 设置通用参数
var jwtInfo = JwtUtil.getJwtInfo();
if (jwtInfo != null) {
body.put("RequestId", jwtInfo.getRequestId());
body.put("AppId", Integer.valueOf(jwtInfo.getAppId()));
body.put("Uin", jwtInfo.getUin());
body.put("Region", jwtInfo.getRegion());
}
// 设置action
body.put("Action", action);
// 发送http请求,拿到请求结果
HttpConnectUtil.ResponseInfo responseInfo = switch (method) {
case "GET" -> HttpConnectUtil.sendGetByJson(url, JsonUtil.toJson(body));
case "POST" -> HttpConnectUtil.sendPost(url, JsonUtil.toJson(body), new HashMap<>(2));
default -> new HttpConnectUtil.ResponseInfo();
};
// 检查Api3格式返回结果,并解析
var jsonResponse = JsonUtil.getJsonNode(responseInfo.getContent()).get("Response");
var jsonError = jsonResponse.get("Error");
if (jsonError != null) {
var errorCode = jsonError.get("Code").asText();
var errorMessage = jsonError.get("Message").asText();
throw new ApiException(ErrorCode.INTERNAL_ERROR,
String.format("错误码:[%s],错误信息:[%s]", errorCode, errorMessage));
}
return jsonResponse;
}