React.js+Spring Basic Auth认证问题:成功获取Token却仍未通过身份校验
问题核心原因
Basic Auth属于无状态认证机制,要求每次向后端发起请求都需要在请求头携带Authorization凭证。你当前仅在登录请求里配置了auth参数,后续的业务请求没有自动携带认证信息,所以后端校验不通过。Postman请求正常是因为你在Postman中单独配置了认证参数,或者Postman自动记住了上次的认证信息并在后续请求中携带。
排查思路
- 打开浏览器控制台「网络」标签,查看登录成功后发起的
/market/last等业务请求的请求头,确认是否存在Authorization: Basic xxx字段,90%以上的此类问题都是该字段缺失导致 - 打开Redux DevTools,确认登录成功后store中是否正确存储了username和password字段,排除状态存储异常的可能性
- 可以手动给
getMarketItemsSortByDate的axios请求临时加auth参数测试,如果请求成功即可100%确认是认证头缺失问题
解决方案
方案1:配置axios全局请求拦截器(推荐)
不需要修改原有接口调用逻辑,统一给所有请求自动携带认证信息,维护成本最低。在apiCalls文件中新增拦截器逻辑即可:
import axios from "axios"; import SecureLS from 'secure-ls'; const secureLS = new SecureLS(); // 新增全局请求拦截器 axios.interceptors.request.use(request => { const authInfo = secureLS.get('hoax-auth'); // 只有本地存在认证信息时才携带请求头 if (authInfo?.username && authInfo?.password) { request.auth = { username: authInfo.username, password: authInfo.password } } return request; }) // 原有接口代码保持不变 export const signup = (body) => { return axios.post('/users', body); }; export const login = creds => { return axios.post('/auth', {}, {auth:creds}); }; export const getMarketItemsSortByDate = () => { return axios.get("/market/last"); }
方案2:单个接口单独配置auth参数
如果不想使用全局拦截器,也可以给每个需要认证的接口单独传入auth参数,示例如下:
// 接口定义时增加creds参数 export const getMarketItemsSortByDate = (creds) => { return axios.get("/market/last", {auth: creds}); } // 组件调用接口时从Redux store中取出认证信息传入 const creds = {username: store.getState().username, password: store.getState().password} getMarketItemsSortByDate(creds)
该方案需要每个调用接口的位置都单独传参,维护成本较高,仅适合少数接口需要认证的场景。
额外优化建议
- 不要明文存储用户密码到本地存储,即使使用了SecureLS也存在泄露风险。可以在登录成功后将
username:password做Base64编码后存储,请求时直接将编码后的值放到Authorization头中即可,不需要存储原始密码 - 可以新增全局响应拦截器,捕获到401状态码时自动触发登出逻辑,清除本地存储的认证信息并跳转到登录页
内容的提问来源于stack exchange,提问作者onur
相关产品推荐
相关产品推荐

