From 417856b7beba498ae727b27ddfdd19bf783324d7 Mon Sep 17 00:00:00 2001 From: wangjianhong <546732225seven@gmail.com> Date: Wed, 6 Aug 2025 15:54:19 +0800 Subject: [PATCH] no message --- README.md | 15 ++ pom.xml | 10 +- .../config/SecurityWebAutoConfigurer.java | 2 +- .../filter/JwtRequestFilter.java | 130 +++++++++++------- .../store/UserDetailsServiceStore.java | 10 +- src/main/resources/application.yml | 2 +- 6 files changed, 108 insertions(+), 61 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..060cbfc --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ + +## Getting started + +## + + +``` + +mvn versions:display-dependency-updates + +mvn versions:update-properties + +mvn versions:set -DnewVersion=1.2.0.RELEASE +``` + diff --git a/pom.xml b/pom.xml index 138b5f4..ac8a5d0 100644 --- a/pom.xml +++ b/pom.xml @@ -5,12 +5,12 @@ org.springframework.boot spring-boot-starter-parent - 3.5.3 + 4.0.0-M1 com.arrokoth authorization-server-standalone - 0.0.1-SNAPSHOT + 1.2.0.RELEASE authorization-server-standalone authorization-server-standalone @@ -34,8 +34,8 @@ 17 3.5.3 - 1.1.0.RELEASE - 1.1.0.RELEASE + 1.2.0.RELEASE + 1.2.0.RELEASE @@ -50,7 +50,7 @@ com.arrokoth.framework basic-authorization-server - 1.0.1-RELEASE + 1.2.0.RELEASE diff --git a/src/main/java/com/arrokoth/standalone/authorization/config/SecurityWebAutoConfigurer.java b/src/main/java/com/arrokoth/standalone/authorization/config/SecurityWebAutoConfigurer.java index 61de936..c40e95e 100644 --- a/src/main/java/com/arrokoth/standalone/authorization/config/SecurityWebAutoConfigurer.java +++ b/src/main/java/com/arrokoth/standalone/authorization/config/SecurityWebAutoConfigurer.java @@ -50,7 +50,7 @@ public class SecurityWebAutoConfigurer { .logout(logout -> logout .logoutUrl(SecurityWebProperties.AXIOS_LOGOUT_PROCESSING_URL) - .logoutSuccessUrl(securityWebProperties.getLogoutSuccessUrl()) +// .logoutSuccessUrl(securityWebProperties.getLogoutSuccessUrl()) .invalidateHttpSession(true) // 注销时销毁 session .deleteCookies("JSESSIONID", "Authorization") .permitAll() diff --git a/src/main/java/com/arrokoth/standalone/authorization/filter/JwtRequestFilter.java b/src/main/java/com/arrokoth/standalone/authorization/filter/JwtRequestFilter.java index 06696bc..c9b25e2 100644 --- a/src/main/java/com/arrokoth/standalone/authorization/filter/JwtRequestFilter.java +++ b/src/main/java/com/arrokoth/standalone/authorization/filter/JwtRequestFilter.java @@ -12,6 +12,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; @@ -28,92 +29,113 @@ public class JwtRequestFilter extends OncePerRequestFilter { private final RedisTokenService redisTokenService; @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { - - logRequestDetails(request); + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) + throws ServletException, IOException { try { + // 1. 提取 JWT Token String jwt = extractJwtFromRequest(request); if (jwt == null) { chain.doFilter(request, response); return; } - String username = extractUsernameFromToken(jwt); - if (username == null) { - chain.doFilter(request, response); + // 2. 解析用户名 + String username = JwtUtils.extractUsername(jwt); + if (username == null || username.isBlank()) { + log.warn("JWT token does not contain a valid username: {}", maskToken(jwt)); + sendUnauthorizedResponse(response, "Invalid token"); return; } - if (isTokenBlacklisted(jwt, response)) { + // 3. 检查 Token 是否被拉黑(退出登录状态) + if (redisTokenService.isBlacklisted(jwt)) { + log.warn("Token is blacklisted: {}", maskToken(jwt)); + sendUnauthorizedResponse(response, "Token is blacklisted"); return; } + // 4. 若用户未认证,则进行认证 if (isUserNotAuthenticated(username)) { - authenticateUser(jwt, username); + authenticateUser(jwt, username, request); } + // 5. 继续过滤链 chain.doFilter(request, response); } catch (Exception ex) { - logger.warn("Error occurred during JWT filter processing", ex); - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + log.warn("JWT filter processing failed for request: {}", request.getRequestURI(), ex); + sendUnauthorizedResponse(response, "Unauthorized: " + ex.getMessage()); } } - + /** + * 从请求中提取 JWT Token + */ private String extractJwtFromRequest(HttpServletRequest request) { - - String jwt = null; - - // 1. 先从 Authorization Header 中提取 - String authorizationHeader = request.getHeader("Authorization"); - if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { - jwt = authorizationHeader.substring(7); + // 优先从 Authorization: Bearer + String bearerToken = request.getHeader("Authorization"); + if (bearerToken != null && bearerToken.startsWith("Bearer ")) { + return bearerToken.substring(7).trim(); } - // 2. 如果 Header 中没有,则尝试从 URL 参数中获取(如 X-Token) - if (jwt == null || jwt.isEmpty()) { - jwt = request.getParameter("X-Token"); + // 其次尝试从 X-Token 参数获取(URL 或表单) + String tokenParam = request.getParameter("X-Token"); + if (tokenParam != null && !tokenParam.isBlank()) { + return tokenParam.trim(); } - return jwt; - } - - private String extractUsernameFromToken(String jwt) { - try { - return JwtUtils.extractUsername(jwt); - } catch (Exception e) { - throw new RuntimeException(e.getMessage()); - } - } - - private boolean isTokenBlacklisted(String jwt, HttpServletResponse response) throws IOException { - if (redisTokenService.isBlacklisted(jwt)) { - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token is blacklisted"); - return true; - } - return false; + return null; } + /** + * 判断当前上下文是否已认证为指定用户 + */ private boolean isUserNotAuthenticated(String username) { - return SecurityContextHolder.getContext().getAuthentication() == null || - !SecurityContextHolder.getContext().getAuthentication().isAuthenticated() || - !SecurityContextHolder.getContext().getAuthentication().getName().equals(username); + var authentication = SecurityContextHolder.getContext().getAuthentication(); + return authentication == null + || !authentication.isAuthenticated() + || !username.equals(authentication.getName()); } - private void authenticateUser(String jwt, String username) { - UserDetails userDetails = userDetailsService.loadUserByUsername(username); + /** + * 对用户进行身份认证并设置 SecurityContext + */ + private void authenticateUser(String jwt, String username, HttpServletRequest request) { + UserDetails userDetails; + try { + userDetails = userDetailsService.loadUserByUsername(username); + } catch (Exception e) { + log.warn("User not found during JWT authentication: {}", username); + throw new RuntimeException("Invalid token or user does not exist"); + } - if (JwtUtils.validateToken(jwt, userDetails.getUsername())) { - UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( - userDetails, null, userDetails.getAuthorities()); - SecurityContextHolder.getContext().setAuthentication(authentication); - } else { + if (!JwtUtils.validateToken(jwt, userDetails.getUsername())) { + log.warn("JWT token validation failed for user: {}", username); throw new RuntimeException("Token is expired or invalid"); } + + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + userDetails, null, userDetails.getAuthorities()); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authentication); + log.debug("Authenticated user: {} via JWT", username); } + /** + * 发送 401 响应 + */ + private void sendUnauthorizedResponse(HttpServletResponse response, String message) throws IOException { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, message); + } + + /** + * 日志脱敏:隐藏长 Token 的中间部分 + */ + private String maskToken(String token) { + if (token == null || token.length() <= 10) return token; + return token.substring(0, 5) + "..." + token.substring(token.length() - 5); + } /** * 封装的打印请求详情方法 @@ -123,10 +145,10 @@ public class JwtRequestFilter extends OncePerRequestFilter { String queryString = request.getQueryString(); // 打印基本信息 - if (log.isInfoEnabled()) { - log.info("Request URL: {}", requestURL); + if (log.isDebugEnabled()) { + log.debug("Request URL: {}", requestURL); if (queryString != null) { - log.info("Query Parameters: {}", queryString); + log.debug("Query Parameters: {}", queryString); } } @@ -135,8 +157,10 @@ public class JwtRequestFilter extends OncePerRequestFilter { while (paramNames.hasMoreElements()) { String paramName = paramNames.nextElement(); String[] paramValues = request.getParameterValues(paramName); - for (String value : paramValues) { - log.debug("Request Param: {} = {}", paramName, value); + if (log.isDebugEnabled()) { + for (String value : paramValues) { + log.debug("Request Param: {} = {}", paramName, value); + } } } } diff --git a/src/main/java/com/arrokoth/standalone/authorization/store/UserDetailsServiceStore.java b/src/main/java/com/arrokoth/standalone/authorization/store/UserDetailsServiceStore.java index 7076773..46a180a 100644 --- a/src/main/java/com/arrokoth/standalone/authorization/store/UserDetailsServiceStore.java +++ b/src/main/java/com/arrokoth/standalone/authorization/store/UserDetailsServiceStore.java @@ -19,7 +19,15 @@ public class UserDetailsServiceStore { .roles("admin", "normal") .authorities("app", "web") .build(); - return new InMemoryUserDetailsManager(user); + + + + UserDetails user2 = User.withUsername("guest") + .password(passwordEncoder.encode("yyds@8848")) + .roles("normal") + .authorities("app") + .build(); + return new InMemoryUserDetailsManager(user,user2); } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 9805174..cc54724 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -69,7 +69,7 @@ mybatis: mapper-locations: classpath*:com.arrokoth/**/mapper/xml/*.xml configuration: map-underscore-to-camel-case: true - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl +# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl mybatis-plus: type-aliases-package: com.arrokoth.**.domain mapper-locations: classpath*:com.arrokoth/**/mapper/xml/*.xml