diff --git a/pom.xml b/pom.xml index eecb39b..2451f1b 100644 --- a/pom.xml +++ b/pom.xml @@ -32,6 +32,11 @@ org.springframework.boot spring-boot-starter-aop + + com.github.binarywang + weixin-java-miniapp + 4.6.0 + org.springframework.boot diff --git a/src/main/java/cn/teammodel/config/exception/GlobalExceptionHandler.java b/src/main/java/cn/teammodel/config/exception/GlobalExceptionHandler.java index dc02b4b..1b4abcc 100644 --- a/src/main/java/cn/teammodel/config/exception/GlobalExceptionHandler.java +++ b/src/main/java/cn/teammodel/config/exception/GlobalExceptionHandler.java @@ -2,7 +2,7 @@ package cn.teammodel.config.exception; import cn.teammodel.common.ErrorCode; import cn.teammodel.common.R; -import cn.teammodel.manager.NotificationService; +import cn.teammodel.manager.notification.NotificationService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; import org.springframework.http.converter.HttpMessageNotReadableException; diff --git a/src/main/java/cn/teammodel/config/intercepter/UploadApiLogInterceptor.java b/src/main/java/cn/teammodel/config/intercepter/UploadApiLogInterceptor.java index 2f660a7..24a20d7 100644 --- a/src/main/java/cn/teammodel/config/intercepter/UploadApiLogInterceptor.java +++ b/src/main/java/cn/teammodel/config/intercepter/UploadApiLogInterceptor.java @@ -3,7 +3,7 @@ package cn.teammodel.config.intercepter; import cn.hutool.crypto.SecureUtil; import cn.hutool.extra.servlet.ServletUtil; import cn.hutool.jwt.JWTUtil; -import cn.teammodel.manager.NotificationService; +import cn.teammodel.manager.notification.NotificationService; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -11,6 +11,8 @@ import lombok.extern.slf4j.Slf4j; import okhttp3.*; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; @@ -32,13 +34,22 @@ import java.util.List; @Component @Slf4j public class UploadApiLogInterceptor implements HandlerInterceptor { + @Value("${spring.env}") + private String env; @Resource private NotificationService notificationService; private final ObjectMapper mapper = new ObjectMapper(); @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception { + if (!env.equals("dev")) { + doUploadLog(request); + } + return true; + } + + private void doUploadLog(@NotNull HttpServletRequest request) throws IOException { String ip = ServletUtil.getClientIP(request); String client = ""; String tokenSha = ""; @@ -115,7 +126,7 @@ public class UploadApiLogInterceptor implements HandlerInterceptor { okHttpClient.newCall(okRequest).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { - log.error("UploadApiLogIntercepter error" ) ; + log.error("UploadApiLogIntercepter error") ; notificationService.send("日志上传告警: 请求发送失败,检查请求发送客户端"); } @@ -129,6 +140,5 @@ public class UploadApiLogInterceptor implements HandlerInterceptor { } } }); - return true; } } diff --git a/src/main/java/cn/teammodel/controller/frontend/AiController.java b/src/main/java/cn/teammodel/controller/frontend/AiController.java index 141b7e4..db380ec 100644 --- a/src/main/java/cn/teammodel/controller/frontend/AiController.java +++ b/src/main/java/cn/teammodel/controller/frontend/AiController.java @@ -20,7 +20,7 @@ import java.util.List; import java.util.concurrent.CompletableFuture; @RestController -@RequestMapping("public/ai") +@RequestMapping("/ai/api") @Api(tags = "AI 能力") public class AiController { @Resource diff --git a/src/main/java/cn/teammodel/manager/DingAlertNotifier.java b/src/main/java/cn/teammodel/manager/notification/DingAlertNotifier.java similarity index 95% rename from src/main/java/cn/teammodel/manager/DingAlertNotifier.java rename to src/main/java/cn/teammodel/manager/notification/DingAlertNotifier.java index cdf5f22..96727d4 100644 --- a/src/main/java/cn/teammodel/manager/DingAlertNotifier.java +++ b/src/main/java/cn/teammodel/manager/notification/DingAlertNotifier.java @@ -1,44 +1,44 @@ -package cn.teammodel.manager; - -import com.dingtalk.api.DefaultDingTalkClient; -import com.dingtalk.api.DingTalkClient; -import com.dingtalk.api.request.OapiRobotSendRequest; -import com.taobao.api.ApiException; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -/** - * 钉钉告警服务 - * @author winter - * @create 2023-11-14 10:11 - */ -@Component -@Slf4j -public class DingAlertNotifier implements NotificationService{ - private final DingTalkClient client; - @Autowired - public DingAlertNotifier(@Value("${ding.server-url}") String dingServerUrl) { - this.client = new DefaultDingTalkClient(dingServerUrl); - } - - @Override - public void send(String message) { - OapiRobotSendRequest request = new OapiRobotSendRequest(); - // 文本消息 - request.setMsgtype("text"); - OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text(); - text.setContent(message); - request.setText(text); - // at 管理员提醒异常 - OapiRobotSendRequest.At atAll = new OapiRobotSendRequest.At(); - atAll.setIsAtAll(true); - request.setAt(atAll); - try { - client.execute(request); - } catch (ApiException e) { - log.error("钉钉 robot 推送消息渠道异常: {}", e.getMessage()); - } - } -} +package cn.teammodel.manager.notification; + +import com.dingtalk.api.DefaultDingTalkClient; +import com.dingtalk.api.DingTalkClient; +import com.dingtalk.api.request.OapiRobotSendRequest; +import com.taobao.api.ApiException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * 钉钉告警服务 + * @author winter + * @create 2023-11-14 10:11 + */ +@Component +@Slf4j +public class DingAlertNotifier implements NotificationService{ + private final DingTalkClient client; + @Autowired + public DingAlertNotifier(@Value("${ding.server-url}") String dingServerUrl) { + this.client = new DefaultDingTalkClient(dingServerUrl); + } + + @Override + public void send(String message) { + OapiRobotSendRequest request = new OapiRobotSendRequest(); + // 文本消息 + request.setMsgtype("text"); + OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text(); + text.setContent(message); + request.setText(text); + // at 管理员提醒异常 + OapiRobotSendRequest.At atAll = new OapiRobotSendRequest.At(); + atAll.setIsAtAll(true); + request.setAt(atAll); + try { + client.execute(request); + } catch (ApiException e) { + log.error("钉钉 robot 推送消息渠道异常: {}", e.getMessage()); + } + } +} diff --git a/src/main/java/cn/teammodel/manager/NotificationService.java b/src/main/java/cn/teammodel/manager/notification/NotificationService.java similarity index 83% rename from src/main/java/cn/teammodel/manager/NotificationService.java rename to src/main/java/cn/teammodel/manager/notification/NotificationService.java index f002ea4..e2c96da 100644 --- a/src/main/java/cn/teammodel/manager/NotificationService.java +++ b/src/main/java/cn/teammodel/manager/notification/NotificationService.java @@ -1,16 +1,16 @@ -package cn.teammodel.manager; - -/** - * 消息通知接口 - * @author winter - * @create 2023-11-14 10:08 - */ -public interface NotificationService { - - /** - * 发送消息 - * @author: winter - * @date: 2023/11/14 10:09 - */ - void send(String message); -} +package cn.teammodel.manager.notification; + +/** + * 消息通知接口 + * @author winter + * @create 2023-11-14 10:08 + */ +public interface NotificationService { + + /** + * 发送消息 + * @author: winter + * @date: 2023/11/14 10:09 + */ + void send(String message); +} diff --git a/src/main/java/cn/teammodel/manager/wx/MiniProgramSevice.java b/src/main/java/cn/teammodel/manager/wx/MiniProgramSevice.java new file mode 100644 index 0000000..aa9e914 --- /dev/null +++ b/src/main/java/cn/teammodel/manager/wx/MiniProgramSevice.java @@ -0,0 +1,12 @@ +package cn.teammodel.manager.wx; + +import org.springframework.stereotype.Service; + +/** + * @author winter + * @create 2024-03-26 11:08 + */ +@Service +public class MiniProgramSevice { + +} diff --git a/src/main/java/cn/teammodel/security/SecurityConfiguration.java b/src/main/java/cn/teammodel/security/SecurityConfiguration.java index 93c7ff3..17114fa 100644 --- a/src/main/java/cn/teammodel/security/SecurityConfiguration.java +++ b/src/main/java/cn/teammodel/security/SecurityConfiguration.java @@ -1,10 +1,12 @@ package cn.teammodel.security; +import cn.teammodel.security.filter.ApiAuthTokenFilter; import cn.teammodel.security.filter.AuthInnerTokenFilter; import cn.teammodel.security.handler.RestAccessDeniedHandler; import cn.teammodel.security.handler.RestAuthenticationEntryPoint; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; @@ -31,8 +33,11 @@ public class SecurityConfiguration { private RestAuthenticationEntryPoint restAuthenticationEntryPoint; @Resource private AuthInnerTokenFilter authInnerTokenFilter; + @Resource + private ApiAuthTokenFilter apiAuthTokenFilter; @Bean + @Order(2) public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http // CSRF禁用,因为不使用session @@ -64,7 +69,18 @@ public class SecurityConfiguration { .exceptionHandling() .authenticationEntryPoint(restAuthenticationEntryPoint) .accessDeniedHandler(restAccessDeniedHandler); - + return http.build(); + } + @Bean + @Order(1) + public SecurityFilterChain outterApiFilterChain(HttpSecurity http) throws Exception { + http. + antMatcher("/ai/api/**") + .authorizeRequests(authorizeRequests -> + authorizeRequests + .anyRequest().authenticated() + ) + .addFilterAfter(apiAuthTokenFilter, BearerTokenAuthenticationFilter.class); return http.build(); } @@ -86,8 +102,8 @@ public class SecurityConfiguration { } /** - * 跨域配置 - */ + * 跨域配置 + */ @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); diff --git a/src/main/java/cn/teammodel/security/filter/ApiAuthTokenFilter.java b/src/main/java/cn/teammodel/security/filter/ApiAuthTokenFilter.java new file mode 100644 index 0000000..92636f1 --- /dev/null +++ b/src/main/java/cn/teammodel/security/filter/ApiAuthTokenFilter.java @@ -0,0 +1,54 @@ +package cn.teammodel.security.filter; + +import cn.teammodel.security.utils.JwtTokenUtil; +import io.jsonwebtoken.Claims; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.annotation.Resource; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * 对外的 AI chat 接口的认证过滤器 + * @author winter + * @create 2023-11-09 10:43 + */ +@Component +@Slf4j +public class ApiAuthTokenFilter extends OncePerRequestFilter { + + @Resource + private JwtTokenUtil jwtTokenUtil; + + // todo: 修改 context 的值 + 写一下多过滤器链的复盘 + @Override + protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException { + SecurityContext context = SecurityContextHolder.getContext(); + // 验证 authToken 合法 + String token = request.getHeader("token"); + if (StringUtils.isBlank(token)) { + filterChain.doFilter(request, response); + return; + } + Claims claims = jwtTokenUtil.validAndGetClaims(token, "fXO6ko/qyXeYrkecPeKdgXnuLXf9vMEtnBC9OB3s+aA=", 315360000); + if (claims == null) { + SecurityContextHolder.clearContext(); // 验证失败不应该在此处抛出异常,应该维护好 context 的值,以便整个过滤器链正常运行 + filterChain.doFilter(request, response); + return; + } + // 组装 authToken 的 jwt 进 authentication + UsernamePasswordAuthenticationToken finalAuthentication = new UsernamePasswordAuthenticationToken(claims, null, null); + context.setAuthentication(finalAuthentication); + filterChain.doFilter(request, response); + } +} diff --git a/src/main/java/cn/teammodel/security/utils/JwtTokenUtil.java b/src/main/java/cn/teammodel/security/utils/JwtTokenUtil.java index 027388d..902467c 100644 --- a/src/main/java/cn/teammodel/security/utils/JwtTokenUtil.java +++ b/src/main/java/cn/teammodel/security/utils/JwtTokenUtil.java @@ -74,11 +74,15 @@ public class JwtTokenUtil { * @return claims或者null */ private Claims getClaimsFromToken(String token) { + return validAndGetClaims(token, secret, NEVER_EXPIRE); + } + + public Claims validAndGetClaims(String token, String key, long expire) { Claims claims = null; try { claims = Jwts.parser() - .setSigningKey(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256")) - .setAllowedClockSkewSeconds(NEVER_EXPIRE) + .setSigningKey(new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256")) + .setAllowedClockSkewSeconds(expire) .parseClaimsJws(token) .getBody(); } catch (Exception e) { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e505ad2..fe0b1d2 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,4 +1,5 @@ spring: + env: dev mvc: pathmatch: matching-strategy: ant_path_matcher diff --git a/src/test/java/cn/teammodel/TeamModelExtensionApplicationTests.java b/src/test/java/cn/teammodel/TeamModelExtensionApplicationTests.java index 855f9b8..da564bd 100644 --- a/src/test/java/cn/teammodel/TeamModelExtensionApplicationTests.java +++ b/src/test/java/cn/teammodel/TeamModelExtensionApplicationTests.java @@ -3,7 +3,7 @@ package cn.teammodel; import cn.teammodel.common.PK; import cn.teammodel.controller.admin.service.AdminAppraiseService; import cn.teammodel.repository.*; -import cn.teammodel.manager.DingAlertNotifier; +import cn.teammodel.manager.notification.DingAlertNotifier; import cn.teammodel.model.dto.admin.appraise.TimeRangeDto; import cn.teammodel.model.dto.admin.appraise.UpdateAchievementRuleDto; import cn.teammodel.model.entity.appraise.*; diff --git a/src/test/java/cn/teammodel/TestWithoutSpring.java b/src/test/java/cn/teammodel/TestWithoutSpring.java index 0bd297d..a047478 100644 --- a/src/test/java/cn/teammodel/TestWithoutSpring.java +++ b/src/test/java/cn/teammodel/TestWithoutSpring.java @@ -1,6 +1,5 @@ package cn.teammodel; -import cn.hutool.jwt.JWTUtil; import cn.teammodel.common.FiveEducations; import cn.teammodel.model.entity.appraise.Appraise; import cn.teammodel.model.entity.appraise.AppraiseTreeNode; @@ -12,9 +11,13 @@ import com.dingtalk.api.DingTalkClient; import com.dingtalk.api.request.OapiRobotSendRequest; import com.dingtalk.api.response.OapiRobotSendResponse; import com.taobao.api.ApiException; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; @@ -33,8 +36,20 @@ public class TestWithoutSpring { @Test public void testJwtDecode() { // 解析 JWT,不验证签 - Object roles = JWTUtil.parseToken("eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlR4OFo1d2lkT2VSdDVCSGdWX2lvdXpzbjd6OCJ9.eyJhdWQiOiI3MjY0MzcwNC1iMmU3LTRiMjYtYjg4MS1iZDU4NjVlN2E3YTUiLCJpc3MiOiJodHRwczovL2xvZ2luLnBhcnRuZXIubWljcm9zb2Z0b25saW5lLmNuLzQ4MDdlOWNmLTg3YjgtNDE3NC1hYTViLWU3NjQ5N2Q3MzkyYi92Mi4wIiwiaWF0IjoxNzEwNzQ0MzA4LCJuYmYiOjE3MTA3NDQzMDgsImV4cCI6MTcxMDc0ODIwOCwiYWlvIjoiNDJaZ1lPQS9KL0t0ZTIzdWFzN2dEMGFPdW80WHpmdjlmMXhUREp6ZlZsNzk0VWkwWndVQSIsImF6cCI6ImM3MzE3Zjg4LTdjZWEtNGU0OC1hYzU3LWExNjA3MWY3Yjg4NCIsImF6cGFjciI6IjEiLCJvaWQiOiJkNDliYjc4Mi02ZGMyLTQ5MzktODY3OC1kMzNjMjY3MTliZjkiLCJyaCI6IjAuREFJQXota0hTTGlIZEVHcVctZGtsOWM1S3dRM1pITG5zaVpMdUlHOVdHWG5wNlVCQUFBLiIsInJvbGVzIjpbIklFUyJdLCJzdWIiOiJkNDliYjc4Mi02ZGMyLTQ5MzktODY3OC1kMzNjMjY3MTliZjkiLCJ0aWQiOiI0ODA3ZTljZi04N2I4LTQxNzQtYWE1Yi1lNzY0OTdkNzM5MmIiLCJ1dGkiOiJ6MGhKdDg0c1UwMlpxNTJNdGNRS0FBIiwidmVyIjoiMi4wIn0.U9KWPccJQ4ZgfzHBNTK6swuEJvkZM8ebfrOpAl7uDoNynlVEsp8CcQ2a1PIO3V8X8tcNassCplc08qbCqcL49R3S5vP2bWTiucT7c_fyCogxMYpmRM0RmGz8RF1tFF3VAxG4_q1Gt9LgzLbNhxxCQcbgJuZhUMKAP246esHlJrkue88FwgmMxf_rwxDH8VwbAchHtSuIRbj3zYSzgKU0Lpmibrr88g_gQZ061f4RyRezTmKLoOqhoGjEosOOnXOdI67YyxpdMjm64uzc92fNUyC9PHvu8XbTTbdUlkU2lPgrk5xFfyVus9SdxWQXB4PCIDhcBsoVQQlWGmY-kvw_8w").getPayload("roles"); - System.out.println(roles); + // Object roles = JWTUtil.parseToken("eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlR4OFo1d2lkT2VSdDVCSGdWX2lvdXpzbjd6OCJ9.eyJhdWQiOiI3MjY0MzcwNC1iMmU3LTRiMjYtYjg4MS1iZDU4NjVlN2E3YTUiLCJpc3MiOiJodHRwczovL2xvZ2luLnBhcnRuZXIubWljcm9zb2Z0b25saW5lLmNuLzQ4MDdlOWNmLTg3YjgtNDE3NC1hYTViLWU3NjQ5N2Q3MzkyYi92Mi4wIiwiaWF0IjoxNzEwNzQ0MzA4LCJuYmYiOjE3MTA3NDQzMDgsImV4cCI6MTcxMDc0ODIwOCwiYWlvIjoiNDJaZ1lPQS9KL0t0ZTIzdWFzN2dEMGFPdW80WHpmdjlmMXhUREp6ZlZsNzk0VWkwWndVQSIsImF6cCI6ImM3MzE3Zjg4LTdjZWEtNGU0OC1hYzU3LWExNjA3MWY3Yjg4NCIsImF6cGFjciI6IjEiLCJvaWQiOiJkNDliYjc4Mi02ZGMyLTQ5MzktODY3OC1kMzNjMjY3MTliZjkiLCJyaCI6IjAuREFJQXota0hTTGlIZEVHcVctZGtsOWM1S3dRM1pITG5zaVpMdUlHOVdHWG5wNlVCQUFBLiIsInJvbGVzIjpbIklFUyJdLCJzdWIiOiJkNDliYjc4Mi02ZGMyLTQ5MzktODY3OC1kMzNjMjY3MTliZjkiLCJ0aWQiOiI0ODA3ZTljZi04N2I4LTQxNzQtYWE1Yi1lNzY0OTdkNzM5MmIiLCJ1dGkiOiJ6MGhKdDg0c1UwMlpxNTJNdGNRS0FBIiwidmVyIjoiMi4wIn0.U9KWPccJQ4ZgfzHBNTK6swuEJvkZM8ebfrOpAl7uDoNynlVEsp8CcQ2a1PIO3V8X8tcNassCplc08qbCqcL49R3S5vP2bWTiucT7c_fyCogxMYpmRM0RmGz8RF1tFF3VAxG4_q1Gt9LgzLbNhxxCQcbgJuZhUMKAP246esHlJrkue88FwgmMxf_rwxDH8VwbAchHtSuIRbj3zYSzgKU0Lpmibrr88g_gQZ061f4RyRezTmKLoOqhoGjEosOOnXOdI67YyxpdMjm64uzc92fNUyC9PHvu8XbTTbdUlkU2lPgrk5xFfyVus9SdxWQXB4PCIDhcBsoVQQlWGmY-kvw_8w").getPayload("roles"); + // System.out.println(roles); + + Claims claims = null; + try { + claims = Jwts.parser() + .setSigningKey(new SecretKeySpec("fXO6ko/qyXeYrkecPeKdgXnuLXf9vMEtnBC9OB3s+aA=".getBytes(StandardCharsets.UTF_8), "HmacSHA256")) + .setAllowedClockSkewSeconds(315360000) + .parseClaimsJws("eyJhbGciOiJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNobWFjLXNoYTI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ3d3cud2ludGVhY2guY24iLCJzdWIiOiI1NTUzMzMwNzQ1OTU4NzY4NjQiLCJleHAiOiIxNzExNjE1MDIxIiwibmFtZSI6IuWRqOWTjeWGmyIsInBpY3R1cmUiOm51bGwsImNkanhqeSI6eyJuaWNrbmFtZSI6IuWRqOWTjeWGmyIsInBpY3R1cmUiOm51bGwsImJpbmRJZCI6IjE4NDgyMTMzMDk0Iiwib3BlbmlkIjpudWxsLCJ1bmlvbmlkIjoiMWE4ZWFkNDYtY2JkMS00Y2VlLTg2NzEtZTU0NmMwZmQ4NTMyIn19._6ltuihVcWopQQqfgpSLo3aMVKE3MJhb28NQBSL_w7s") + .getBody(); + System.out.println(claims); + } catch (Exception e) { + log.warn("token 解析出错:{}",e.getMessage()); + } } @Test