τα στοιχεία επικοινωνίας μου
Ταχυδρομείο[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Αυτό το άρθρο περιγράφει κυρίως τη μέθοδο ρύθμισης πληροφοριών jwt στο φίλτρο για αποθήκευση πληροφοριών ταυτότητας μέσω της κλάσης φίλτρου του springboot.
Διαδικασία: Αίτημα->Φίλτρο->Ανάλυση των πληροφοριών σώματος του αιτήματος->Τοποθετήστε το σε νήμα
Ορισμός φίλτρου: ένα φίλτρο (Φίλτρο) που χρησιμοποιεί την προδιαγραφή Servlet, το οποίο καταχωρείται μέσω του σχολιασμού @WebFilter για να υποκλέψει όλα τα αιτήματα HTTP που ταιριάζουν με τη διαδρομή /api.
Ο σχολιασμός @WebFilter("/api") καθορίζει ότι το φίλτρο θα εφαρμοστεί σε όλα τα αιτήματα που έχουν πρόσβαση στη διαδρομή /api.
@Σχολιασμός στοιχείου:
Το @Component είναι ένας σχολιασμός του πλαισίου Spring, υποδεικνύοντας ότι το JwtFilter είναι ένα στοιχείο Spring που μπορεί να διαχειρίζεται το κοντέινερ Spring και υποστηρίζει την ένεση εξάρτησης.
Μέθοδος doFilter:
Η μέθοδος doFilter καθορίζει τον τρόπο με τον οποίο το φίλτρο παρεμποδίζει και επεξεργάζεται αιτήματα και αποκρίσεις που εισέρχονται στο κοντέινερ Servlet ή Servlet.
Υπογραφή μεθόδου:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException;
Αυτή η μέθοδος δέχεται τρεις παραμέτρους: αίτημα ServletRequest, Απόκριση ServletResponse και αλυσίδα FilterChain.
Μπορεί να ρίξει IOException ή ServletException.
Αίτημα και απάντηση:
Οι δύο πρώτες παράμετροι της μεθόδου doFilter αντιπροσωπεύουν το τρέχον αίτημα και τα αντικείμενα απόκρισης Μπορείτε να διαβάσετε δεδομένα αιτήματος και να τροποποιήσετε αιτήματα και απαντήσεις σε αυτήν τη μέθοδο.
Συνήθως, στο τέλος της μεθόδου doFilter, πρέπει να καλέσετε το chain.doFilter(αίτημα, απάντηση) για να συνεχίσετε την εκτέλεση του επόμενου φίλτρου ή πόρου στόχου στην αλυσίδα φίλτρου.
Εάν θέλετε να τροποποιήσετε ξανά το περιεχόμενο του αιτήματος, μπορείτε να χρησιμοποιήσετε το HttpServletRequestWrapper Το HttpServletRequestWrapper είναι μια κλάση περιτυλίγματος που επεκτείνει τη διεπαφή HttpServletRequest, επιτρέποντάς σας να τροποποιήσετε ή να επεκτείνετε την επεξεργασία αιτημάτων. Οι σκοποί για τη χρήση του HttpServletRequestUriWrapper (το οποίο μπορεί να είναι μια προσαρμοσμένη κλάση περιτυλίγματος που κληρονομείται από το HttpServletRequestWrapper) συνήθως περιλαμβάνουν:
Τροποποίηση URI αιτήματος:
Μπορεί να θέλετε να τροποποιήσετε το URI αιτήματος, αλλά όχι το αρχικό αντικείμενο HttpServletRequest. Χρησιμοποιώντας το HttpServletRequestUriWrapper, μπορείτε να αναδιπλώσετε το αρχικό αίτημα και να παρέχετε ένα τροποποιημένο URI.
Διατηρήστε το αρχικό αίτημα αμετάβλητο:
Η χρήση ενός περιτυλίγματος διατηρεί το αρχικό αντικείμενο αίτησης αμετάβλητο, ενώ σας επιτρέπει να τροποποιήσετε ορισμένες πτυχές του αιτήματος σε κάποιο σημείο της αλυσίδας φιλτραρίσματος.
Φιλτράρισμα και προεπεξεργασία:
Πριν καλέσετε το filterChain.doFilter, μπορείτε να προσθέσετε οποιαδήποτε λογική προεπεξεργασίας στη μέθοδο doFilter, όπως τροποποίηση παραμέτρων αιτήματος, αλλαγή διαδρομών αιτήματος, προσθήκη ή τροποποίηση κεφαλίδων αιτημάτων κ.λπ.
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();
}
}
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;
}
}
Λάβετε το περιεχόμενο σε jwt και στείλτε άλλα αιτήματα http:
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;
}