@RequiredArgsConstructor
@RestController
@RequestMapping("api/v1/members")
@Slf4j
public class MemberController {

private final MemberService memberService;

@PostMapping("/sign-up")
public ApiResult<MemberDto> signUp(@RequestBody MemberJoinDto joinDto){
log.debug("joinDto : {}", joinDto.toString());
return OK(memberService.createUser(joinDto.getEmail(), joinDto.getPassword()));
}
@GetMapping("/{userId}")
public ApiResult<MemberDto> getMemberInfo(@AuthenticationPrincipal JwtAuthentication authentication,
@PathVariable Long userId){
log.info("/api/v1/members/userId called.");
log.info(authentication.toString());

return OK(this.memberService.getUser(userId));
}
}


Controller 에서 AuthenticationPrincipal 어노테이션 이용해서 인증 정보를 받게 했어.


JwtAuthentication은 JwtAuthenticationFilter 쪽에서

Authorization Header 를 추출해서 Access token 일 경우 verify 를 성공했을 경우 

JwtAuthenticationToken 을 생성해서 SecurityContextHolder.getContext().setAuthentication( jwtAuthenticationToken)

이런식으로 지정해줬어.


private void accessTokenAuthentication(HttpServletRequest request, DecodedJWT jwt){
Member member = Member.builder()
.id(jwt.getClaim("user_id").asLong())
.email(jwt.getClaim("email").asString())
.role(Role.of(jwt.getClaim("role").asString()))
.build();
saveAuthentication(request, member);
}
private void saveAuthentication(HttpServletRequest request, Member member){
// log.info("save authentication!.");
JwtAuthenticationToken authenticated = new JwtAuthenticationToken(
new JwtAuthentication(member.getId(), member.getEmail(), member.getAuthorities()),
null,
member.getAuthorities()
);
authenticated.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticated);
}
@AllArgsConstructor
@ToString
public class JwtAuthentication {

public final Long userId;

public final String email;

public final Collection<? extends GrantedAuthority> authorities;

}

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
http.csrf().disable()
.cors().disable()
.formLogin().disable()
.httpBasic().disable()
.headers().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.authenticationEntryPoint(entryPointUnauthorizedHandler)
.and()
.authorizeHttpRequests()
.requestMatchers(toH2Console()).permitAll()
.requestMatchers(AUTHENTICATION_WHITE_LIST).permitAll()
.requestMatchers("/api/v1/members/**").authenticated()
.anyRequest().permitAll();

http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

return http.build();
}


security 설정은 이렇게 해줬고

화이트리스트에 /api/v1/members/sign-up url 만 추가되어있음.


/api/v1/members/{userId} 엔드포인트 쪽에 

@AuthenticationPrincipal 어노테이션을 적용해서

JwtAuthentication 을 받아 올 경우에


Postman에서 header 에 Authorization: Bearer 토큰


이렇게 해서 줄때는 잘 동작하는데,  이 Authorization Header를 아예 지우고 리퀘스트를 날리면

엔드포인트 접근을 못할줄 알았는데

엔드포인트 접근한 다음에 authentication.toString() 부분에서 NullPointerException 이 발생하더라고

어노테이션 소스코드 타고 들어가면서 확인해봤는데 문제 파악을 못하겠어서.