前端Axios调用SpringBoot接口出现403权限问题求助
问题排查与解决方案
核心问题1:Axios请求头拼写错误
前端图书列表组件的请求中,Headers是大写开头,但Axios的配置项要求小写的headers,这直接导致Authorization头没有被正确携带到后端,触发403权限验证失败。
修正后的前端请求代码:
export default function Books(){ const [books, setBooks] = useState([]); const [page, setPage] = useState(0); const username = localStorage.getItem('username'); const access_token = localStorage.getItem('accessToken'); const history = useHistory(); useEffect(() => { // 修正:Headers → headers api.get('api/book/v1', { headers: { Authorization: `Bearer ${access_token}` }, params: { page: 0, size: 10, direction: 'asc' } }).then(response => { setBooks(response.data._embedded.bookVOList) }).catch(err => { console.error('请求失败:', err); }) }, []) // 补充空依赖数组,避免useEffect无限执行 }
核心问题2:前后端端口不匹配
你描述后端运行在localhost:8000,但Axios的baseURL配置的是http://localhost:8080,这会导致请求发送到错误端口。务必确认:
- 后端启动日志显示的实际端口
- 若后端确实是8000,修改Axios配置:
const api = axios.create({ baseURL: 'http://localhost:8000' });
后端配置补充检查
1. 验证JwtConfigurer有效性
确保JwtConfigurer正确实现token解析逻辑,比如从请求头提取Authorization信息、验证签名、解析用户身份,核心实现示例:
public class JwtConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> { private TokenProvider tokenProvider; public JwtConfigurer(TokenProvider tokenProvider) { this.tokenProvider = tokenProvider; } @Override public void configure(HttpSecurity http) throws Exception { JwtTokenFilter customFilter = new JwtTokenFilter(tokenProvider); http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class); } } // JwtTokenFilter核心逻辑 public class JwtTokenFilter extends OncePerRequestFilter { private TokenProvider tokenProvider; public JwtTokenFilter(TokenProvider tokenProvider) { this.tokenProvider = tokenProvider; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = resolveToken(request); if (StringUtils.hasText(token) && tokenProvider.validateToken(token)) { Authentication authentication = tokenProvider.getAuthentication(token); SecurityContextHolder.getContext().setAuthentication(authentication); } filterChain.doFilter(request, response); } private String resolveToken(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7); } return null; } }
2. 简化跨域配置避免冲突
由于SecurityConfig中已启用.cors(),可直接在Security内配置跨域,移除WebConfig的跨域配置防止冲突:
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .httpBasic().disable() .csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() .antMatchers("/auth/signin", "/auth/refresh", "/api-docs/**", "/swagger-ui.html**").permitAll() .antMatchers("/api/**").authenticated() .antMatchers("/users").denyAll() .and() .cors().configurationSource(corsConfigurationSource()) .and() .apply(new JwtConfigurer(tokenProvider)); } private CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000")); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type")); configuration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } }
额外调试建议
- 打开浏览器开发者工具(F12),查看Network标签下的/api/book/v1请求,确认Request Headers中是否存在
Authorization: Bearer xxx - 后端在JwtTokenFilter中添加日志,打印提取到的token,确认是否正确接收
- 用JWT解析工具检查accessToken的过期时间、签名、用户权限等信息
内容的提问来源于stack exchange,提问作者João Vitor Menezes
相关产品推荐
相关产品推荐

