문제상황
: 포스트맨을 이용한 JWT인증은 정상적으로 수행되고 있으나, 프론트단에서 콘솔이나 브라우저를 이용한 요청을 전송할 때 Header에 JWT가 정상적으로 담겨 오지 않는다
즉, 디버깅을 해보면 요청 전송시 Header에서 NullpointerException이 발생한다.
원인
1. SpringBoot Security 측면
서버에서 응답으로 보내는 JWT 토큰의 이름(키값)과 요청으로 인증할 때 받는 JWT 이름(키값)은 다르게 세팅이 가능하므로 주의해야한다. 이에 따라 프론트에서 요청을 전송할 때 올바르지 않은 이름으로 전달한다면 NullpointerException이 될 수 있다.
1-1) JwtAuthenticationFilter
: response.setHeader안의 "Authorization"부분이 응답 Header로 보내주는 JWT 이름이 된다.
@Override
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain,
Authentication authResult) throws IOException, ServletException {
Member authenticatedMember = (Member) authResult.getPrincipal();
String accessToken = delegateAccessToken(authenticatedMember);
String refreshToken = delegateRefreshToken(authenticatedMember);
response.setHeader("Authorization", "Bearer " + accessToken);
response.setHeader("RefreshToken", refreshToken);
this.getSuccessHandler().onAuthenticationSuccess(request, response, authResult); // 추가
}
1-2) JwtVerificationFilter
: request.getHeader안의 "Authorization"부분이 요청을 받을때 인식하는 JWT이름이다.
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
try {
String header = request.getHeader("Authorization");
String jws = header.replace("bearer", "");
//토큰 검증
Map<String, Object> claims = verifyJws(request); //검증 부분, 파싱할때 Long이였던 memberId가 자동으로 Integer로 파싱됨..
//로그아웃 토큰 여부 확인, 정상적인 토큰일 경우만 로그아웃 여부 확인
verifyLoginToken(jws);
setSecurityContext(claims);
filterChain.doFilter(request, response);
}
2. React Axios 측면
1) React 요청 설정
요청을 전송할 때 'Authorization'부분은 1-2에서 설정한 SpringBoot에서 요청을 받을 때 필터에 설정한 이름이어야 한다.
혹은 Axios 디폴트 값으로 설정된 값을 사용한다.
반대로 값을 추출할 땐 1-1에서 설정한 필터에서 정의한 이름으로 작성해야한다.
맞추지 않으면 프론트에서는 401에러가, 백엔드 디버깅에서는 Header NullpointerException이 발생한다.
Axios.defaults.headers.common['Authorization'] = `Bearer ${res.payload.accessToken}`
const onLogin = () => {
var variables = {
"email": email,
"password": password
}
Axios.post('/auth/login', variables)
.then(res => {
setCookie('token', res.payload.accessToken)
setCookie('exp', res.payload.accessTokenExpiresIn)
// token이 필요한 API 요청 시 header Authorization에 token 담아서 보내기
Axios.defaults.headers.common['Authorization'] = `Bearer ${res.payload.accessToken}`
Axios.get('/user/me')
.then(res => {
console.log(res);
})
})
}
2) Axios 공식문서 방법
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN; // <== 이 부분
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
*Axios 공식문서 : https://axios-http.com/docs/config_defaults
'Java & Spring > Error' 카테고리의 다른 글
| [에러로그] JpaSystemException - 원인 : GenerateValue (2) | 2023.01.24 |
|---|---|
| [Ngrok] Cors 이슈 해결하기 (0) | 2022.12.03 |
| [SpringBoot] hibernateLazyInitializer 및 순환참조 에러 (0) | 2022.11.19 |
| [SpringBoot] Caused by: java.sql.SQLSyntaxErrorException: Can't DROP 'FKpvill444mvu6ace1wvwpc9iob'; check that column/key exists 에러 (0) | 2022.11.18 |
| [SpringBoot] httpmessagenotwritableexception 에러 (0) | 2022.11.17 |