|
|
@ -9,6 +9,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
|
|
|
import jakarta.servlet.http.HttpServletResponse;
|
|
|
|
import jakarta.servlet.http.HttpServletResponse;
|
|
|
|
import lombok.NonNull;
|
|
|
|
import lombok.NonNull;
|
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
import org.springframework.http.HttpStatus;
|
|
|
|
import org.springframework.http.HttpStatus;
|
|
|
|
import org.springframework.http.MediaType;
|
|
|
|
import org.springframework.http.MediaType;
|
|
|
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
|
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
|
@ -22,7 +23,7 @@ import org.springframework.stereotype.Component;
|
|
|
|
import org.springframework.web.filter.OncePerRequestFilter;
|
|
|
|
import org.springframework.web.filter.OncePerRequestFilter;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.IOException;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Slf4j
|
|
|
|
@Component
|
|
|
|
@Component
|
|
|
|
@RequiredArgsConstructor
|
|
|
|
@RequiredArgsConstructor
|
|
|
|
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|
|
|
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|
|
@ -43,6 +44,15 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|
|
|
|
|
|
|
|
|
|
|
// 获取 Authorization 头
|
|
|
|
// 获取 Authorization 头
|
|
|
|
String authHeader = request.getHeader("Authorization");
|
|
|
|
String authHeader = request.getHeader("Authorization");
|
|
|
|
|
|
|
|
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
|
|
|
|
|
|
|
log.info("用户未携带token信息,请求路径:{}", request.getRequestURI());
|
|
|
|
|
|
|
|
if (permitAllRequest) {
|
|
|
|
|
|
|
|
filterChain.doFilter(request, response);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
writeTokenErrorResponse(response, "用户未登录,请登录");
|
|
|
|
|
|
|
|
return; // 直接返回,不放行
|
|
|
|
|
|
|
|
}
|
|
|
|
// 提取 token(去掉 "Bearer " 前缀)
|
|
|
|
// 提取 token(去掉 "Bearer " 前缀)
|
|
|
|
String token = authHeader.substring(7);
|
|
|
|
String token = authHeader.substring(7);
|
|
|
|
String username;
|
|
|
|
String username;
|
|
|
@ -51,58 +61,59 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
username = jwtUtils.getUsernameFromToken(token);
|
|
|
|
username = jwtUtils.getUsernameFromToken(token);
|
|
|
|
} catch (Exception e) {
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
|
|
log.error("token认证失败,请求路径:{},permitRequest is {}", request.getRequestURI(),permitAllRequest,e);
|
|
|
|
if (permitAllRequest) {
|
|
|
|
if (permitAllRequest) {
|
|
|
|
filterChain.doFilter(request, response);
|
|
|
|
filterChain.doFilter(request, response);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
writeTokenErrorResponse(response, "Token 无效或已过期,请重新登录");
|
|
|
|
writeTokenErrorResponse(response, "Token 无效或已过期,请重新登录");
|
|
|
|
return; // 中断
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3:成功解析出用户名,且当前 SecurityContext 未认证
|
|
|
|
// 3:成功解析出用户名,且当前 SecurityContext 未认证
|
|
|
|
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
|
|
|
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
// 从 UserDetailsService 加载用户信息
|
|
|
|
|
|
|
|
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
|
|
|
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
|
|
|
|
|
|
|
|
|
|
|
// 验证 Token 是否未过期(你可以根据需要添加更多验证,如登录时间)
|
|
|
|
// 验证 Token 是否仍然有效(时间戳、登录时间等)
|
|
|
|
if (!jwtUtils.isTokenExpired(token)) {
|
|
|
|
if (!jwtUtils.isTokenExpired(token)) {
|
|
|
|
// 创建认证对象
|
|
|
|
|
|
|
|
|
|
|
|
//认证成功:设置 SecurityContext
|
|
|
|
UsernamePasswordAuthenticationToken authToken =
|
|
|
|
UsernamePasswordAuthenticationToken authToken =
|
|
|
|
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
|
|
|
|
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
|
|
|
|
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
|
|
|
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
|
|
|
|
|
|
|
|
|
|
|
// 设置到 SecurityContext
|
|
|
|
|
|
|
|
SecurityContextHolder.getContext().setAuthentication(authToken);
|
|
|
|
SecurityContextHolder.getContext().setAuthentication(authToken);
|
|
|
|
|
|
|
|
log.info("用户 {} token认证成功,请求路径:{}", userDetails.getUsername(), request.getRequestURI());
|
|
|
|
// 认证成功!放行到 Controller
|
|
|
|
//成功后放行,进入 Controller
|
|
|
|
filterChain.doFilter(request, response);
|
|
|
|
filterChain.doFilter(request, response);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
|
|
|
|
//Token 过期 或 登录态不一致
|
|
|
|
|
|
|
|
log.info("用户 {} token认证失败,请求路径:{},permitRequest is {}", userDetails.getUsername(), request.getRequestURI(),permitAllRequest);
|
|
|
|
if (permitAllRequest) {
|
|
|
|
if (permitAllRequest) {
|
|
|
|
filterChain.doFilter(request, response);
|
|
|
|
filterChain.doFilter(request, response);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Token 已过期
|
|
|
|
writeTokenErrorResponse(response, "登录已过期,请重新登录");
|
|
|
|
writeTokenErrorResponse(response, "Token 已过期,请重新登录");
|
|
|
|
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} catch (UsernameNotFoundException e) {
|
|
|
|
} catch (UsernameNotFoundException e) {
|
|
|
|
|
|
|
|
log.error("token认证失败,请求路径:{},permitRequest is {}", request.getRequestURI(),permitAllRequest,e);
|
|
|
|
if (permitAllRequest) {
|
|
|
|
if (permitAllRequest) {
|
|
|
|
filterChain.doFilter(request, response);
|
|
|
|
filterChain.doFilter(request, response);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 用户不存在
|
|
|
|
writeTokenErrorResponse(response, "用户不存在");
|
|
|
|
writeTokenErrorResponse(response, "用户不存在或已被删除");
|
|
|
|
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
} catch (Exception e) {
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
|
|
log.error("token认证失败,请求路径:{},permitRequest is {}", request.getRequestURI(),permitAllRequest,e);
|
|
|
|
if (permitAllRequest) {
|
|
|
|
if (permitAllRequest) {
|
|
|
|
filterChain.doFilter(request, response);
|
|
|
|
filterChain.doFilter(request, response);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 其他加载异常
|
|
|
|
writeTokenErrorResponse(response, "用户认证异常:" + e.getMessage());
|
|
|
|
writeTokenErrorResponse(response, "用户信息加载失败:" + e.getMessage());
|
|
|
|
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|