From c29abb1b832368380c3c67b69d74a4ca7a81984c Mon Sep 17 00:00:00 2001 From: wangjianhong <546732225seven@gmail.com> Date: Thu, 24 Jul 2025 10:46:10 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=94=A8=E6=88=B7=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/LoginController.java | 35 +++++ .../filter/JwtRequestFilter.java | 132 ++++++++++++++---- .../store/UserDetailsServiceStore.java | 2 +- src/main/resources/application.yml | 2 +- src/main/resources/templates/login.html | 2 +- 5 files changed, 141 insertions(+), 32 deletions(-) create mode 100644 src/main/java/com/arrokoth/standalone/authorization/controller/LoginController.java diff --git a/src/main/java/com/arrokoth/standalone/authorization/controller/LoginController.java b/src/main/java/com/arrokoth/standalone/authorization/controller/LoginController.java new file mode 100644 index 0000000..1fb2a0a --- /dev/null +++ b/src/main/java/com/arrokoth/standalone/authorization/controller/LoginController.java @@ -0,0 +1,35 @@ +package com.arrokoth.standalone.authorization.controller; + +import com.arrokoth.basic.properties.SecurityWebProperties; +import com.arrokoth.basic.request.LoginRequest; +import com.arrokoth.basic.response.Token; +import com.arrokoth.basic.service.AuthorizationService; +import io.swagger.v3.oas.annotations.Operation; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RequestMapping +@RestController +@RequiredArgsConstructor +public class LoginController { + + private final AuthorizationService authorizationService; + private final AuthenticationManager authenticationManager; + + @Operation(summary = "登录", description = "获取登录Token信息") + @PostMapping(SecurityWebProperties.AXIOS_LOGIN_PROCESSING_URL) + public Token homeLogin(@Valid @RequestBody LoginRequest loginRequest) { + UsernamePasswordAuthenticationToken passwordAuthenticationToken = new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()); + Authentication authenticate = authenticationManager.authenticate(passwordAuthenticationToken); + SecurityContextHolder.getContext().setAuthentication(authenticate); + return authorizationService.login(loginRequest); + } +} 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 8e2da5c..0a1ebc1 100644 --- a/src/main/java/com/arrokoth/standalone/authorization/filter/JwtRequestFilter.java +++ b/src/main/java/com/arrokoth/standalone/authorization/filter/JwtRequestFilter.java @@ -7,6 +7,7 @@ import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; @@ -15,8 +16,9 @@ import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; +import java.util.Enumeration; - +@Slf4j @Component @RequiredArgsConstructor public class JwtRequestFilter extends OncePerRequestFilter { @@ -26,47 +28,119 @@ public class JwtRequestFilter extends OncePerRequestFilter { private final RedisTokenService redisTokenService; @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws ServletException, IOException { - final String authorizationHeader = request.getHeader("Authorization"); + logRequestDetails(request); + + try { + String jwt = extractJwtFromRequest(request); + if (jwt == null) { + chain.doFilter(request, response); + return; + } + + String username = extractUsernameFromToken(jwt); + if (username == null) { + chain.doFilter(request, response); + return; + } + + if (isTokenBlacklisted(jwt, response)) { + return; + } + + if (isUserNotAuthenticated(username)) { + authenticateUser(jwt, username); + } + + chain.doFilter(request, response); + + } catch (Exception ex) { + logger.warn("Error occurred during JWT filter processing", ex); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + } + } + + + + private String extractJwtFromRequest(HttpServletRequest request) { String jwt = null; - String username = null; + // 1. 先从 Authorization Header 中提取 + String authorizationHeader = request.getHeader("Authorization"); if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { jwt = authorizationHeader.substring(7); - try { - username = JwtUtils.extractUsername(jwt); - } catch (Exception e) { - logger.warn("Failed to extract username from token"); - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid token"); - return; - } + } + + // 2. 如果 Header 中没有,则尝试从 URL 参数中获取(如 X-Token) + if (jwt == null || jwt.isEmpty()) { + jwt = request.getParameter("X-Token"); + } + + return jwt; + } + + private String extractUsernameFromToken(String jwt) { + try { + return JwtUtils.extractUsername(jwt); + } catch (Exception e) { + logger.warn("Failed to extract username from token", e); + throw new RuntimeException("Failed to extract username from token"); + } + } + + 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; + } + + private boolean isUserNotAuthenticated(String username) { + return SecurityContextHolder.getContext().getAuthentication() == null || + !SecurityContextHolder.getContext().getAuthentication().isAuthenticated() || + !SecurityContextHolder.getContext().getAuthentication().getName().equals(username); + } + + private void authenticateUser(String jwt, String username) { + UserDetails userDetails = userDetailsService.loadUserByUsername(username); + + if (JwtUtils.validateToken(jwt, userDetails.getUsername())) { + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + userDetails, null, userDetails.getAuthorities()); + SecurityContextHolder.getContext().setAuthentication(authentication); } else { - // 没有 token,继续链(可能是登录接口等不需要认证的路径) - chain.doFilter(request, response); - return; + throw new RuntimeException("Token is expired or invalid"); } + } - if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { - if (redisTokenService.isBlacklisted(jwt)) { - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token is blacklisted"); - return; - } - UserDetails userDetails = userDetailsService.loadUserByUsername(username); - if (JwtUtils.validateToken(jwt, userDetails.getUsername())) { - UsernamePasswordAuthenticationToken authentication = - new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); - SecurityContextHolder.getContext().setAuthentication(authentication); - } else { - // token 无效或已过期 - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token is expired or invalid"); - return; + /** + * 封装的打印请求详情方法 + */ + private void logRequestDetails(HttpServletRequest request) { + String requestURL = request.getRequestURL().toString(); + String queryString = request.getQueryString(); + + // 打印基本信息 + if (log.isInfoEnabled()) { + log.info("Request URL: {}", requestURL); + if (queryString != null) { + log.info("Query Parameters: {}", queryString); } } - chain.doFilter(request, response); + // 打印参数(GET/POST 通用) + Enumeration paramNames = request.getParameterNames(); + while (paramNames.hasMoreElements()) { + String paramName = paramNames.nextElement(); + String[] paramValues = request.getParameterValues(paramName); + for (String value : paramValues) { + log.debug("Request Param: {} = {}", paramName, value); + } + } } } \ No newline at end of file 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 953c73d..7076773 100644 --- a/src/main/java/com/arrokoth/standalone/authorization/store/UserDetailsServiceStore.java +++ b/src/main/java/com/arrokoth/standalone/authorization/store/UserDetailsServiceStore.java @@ -15,7 +15,7 @@ public class UserDetailsServiceStore { @Bean public UserDetailsService users(PasswordEncoder passwordEncoder) { UserDetails user = User.withUsername("admin") - .password(passwordEncoder.encode("password")) + .password(passwordEncoder.encode("123456")) .roles("admin", "normal") .authorities("app", "web") .build(); diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index c61d17b..e7ded75 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -62,7 +62,7 @@ logging: root: INFO com.arrokoth: DEBUG org.springdoc: INFO - org.springframework: INFO + org.springframework: DEBUG #mybatis: # type-aliases-package: com.arrokoth.**.domain diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html index 128beee..f6eee02 100644 --- a/src/main/resources/templates/login.html +++ b/src/main/resources/templates/login.html @@ -257,7 +257,7 @@
+ value="123456">