Spring Boot 프로젝트에서 기존 JWT 토큰에 사용자의 nickname 정보를 추가하는 과정과 마주친 트러블슈팅을 공유합니다.
기획팀에서 사용자 정보에 nickname이 필요하다는 요청이 들어왔습니다.
먼저 User 엔티티에 nickname 필드를 추가했습니다.
@Getter
@Entity
@NoArgsConstructor
@Table(name = "users")
public class User extends Timestamped {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true)
private String email;
private String password;
@Enumerated(EnumType.STRING)
private UserRole userRole;
private String nickname; // ✅ 새로 추가
// 기존 생성자 유지 (호환성)
public User(String email, String password, UserRole userRole) {
this(email, password, userRole, null);
}
// nickname 포함 생성자 추가
public User(String email, String password, UserRole userRole, String nickname) {
this.email = email;
this.password = password;
this.userRole = userRole;
this.nickname = nickname;
}
// fromAuthUser 메서드도 수정
private User(Long id, String email, UserRole userRole, String nickname) {
this.id = id;
this.email = email;
this.userRole = userRole;
this.nickname = nickname;
}
public static User fromAuthUser(AuthUser authUser) {
return new User(authUser.getId(), authUser.getEmail(),
authUser.getUserRole(), authUser.getNickname());
}
}
JwtUtil 클래스의 토큰 생성 메서드에 nickname을 추가했습니다.
@Component
public class JwtUtil {
public String createToken(Long userId, String email, UserRole userRole, String nickname) {
Date date = new Date();
return BEARER_PREFIX +
Jwts.builder()
.setSubject(String.valueOf(userId))
.claim("email", email)
.claim("userRole", userRole)
.claim("nickname", nickname) // ✅ nickname 클레임 추가
.setExpiration(new Date(date.getTime() + TOKEN_TIME))
.setIssuedAt(date)
.signWith(key, signatureAlgorithm)
.compact();
}
}
회원가입 시 nickname을 받을 수 있도록 DTO를 수정했습니다.
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class SignupRequest {
@NotBlank @Email
private String email;
@NotBlank
private String password;
@NotBlank
private String userRole;
@NotBlank
private String nickname; // ✅ 추가
}
인증된 사용자 정보를 담는 AuthUser에도 nickname을 추가했습니다.
@Getter
public class AuthUser {
private final Long id;
private final String email;
private final UserRole userRole;
private final String nickname; // ✅ 추가
public AuthUser(Long id, String email, UserRole userRole, String nickname) {
this.id = id;
this.email = email;
this.userRole = userRole;
this.nickname = nickname;
}
}
회원가입과 로그인 로직에서 nickname을 처리하도록 수정했습니다.
@Service
@RequiredArgsConstructor
public class AuthService {
@Transactional
public SignupResponse signup(SignupRequest signupRequest) {
// 기존 validation 로직...
User newUser = new User(
signupRequest.getEmail(),
encodedPassword,
userRole,
signupRequest.getNickname() // ✅ nickname 추가
);
User savedUser = userRepository.save(newUser);
String bearerToken = jwtUtil.createToken(
savedUser.getId(),
savedUser.getEmail(),
userRole,
savedUser.getNickname() // ✅ nickname 포함
);
return new SignupResponse(bearerToken);
}
public SigninResponse signin(SigninRequest signinRequest) {
User user = userRepository.findByEmail(signinRequest.getEmail())
.orElseThrow(() -> new InvalidRequestException("가입되지 않은 유저입니다."));
// 비밀번호 검증...
String bearerToken = jwtUtil.createToken(
user.getId(),
user.getEmail(),
user.getUserRole(),
user.getNickname() // ✅ nickname 포함
);
return new SigninResponse(bearerToken);
}
}
마지막으로 JWT 파싱과 AuthUser 생성 부분을 수정했습니다.
// JwtFilter.java
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// JWT 파싱 로직...
httpRequest.setAttribute("userId", Long.parseLong(claims.getSubject()));
httpRequest.setAttribute("email", claims.get("email"));
httpRequest.setAttribute("userRole", claims.get("userRole"));
httpRequest.setAttribute("nickname", claims.get("nickname")); // ✅ 추가
// 나머지 로직...
}
// AuthUserArgumentResolver.java
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
Long userId = (Long) request.getAttribute("userId");
String email = (String) request.getAttribute("email");
UserRole userRole = UserRole.of((String) request.getAttribute("userRole"));
String nickname = (String) request.getAttribute("nickname"); // ✅ 추가
return new AuthUser(userId, email, userRole, nickname);
}
문제: User 엔티티에 nickname을 추가하면서 기존 생성자와 충돌
해결방법:
public User(String email, String password, UserRole userRole) {
this(email, password, userRole, null); // 기본값 null로 체이닝
}
문제: createToken 메서드에 nickname 파라미터 추가 후 기존 호출부에서 에러
해결방법:
createToken 호출부를 찾아서 nickname 파라미터 추가문제: 이미 발급된 토큰에는 nickname 클레임이 없어서 파싱 에러
해결방법:
String nickname = (String) claims.get("nickname");
if (nickname == null) {
nickname = ""; // 기본값 설정
}
문제: 기존 DB에는 nickname 컬럼이 없어서 애플리케이션 실행 시 에러
해결방법:
spring.jpa.hibernate.ddl-auto=update 설정 또는 수동 DDL 실행POST /auth/signup
{
"email": "test@example.com",
"password": "password123",
"userRole": "USER",
"nickname": "테스터"
}
{
"sub": "1",
"email": "test@example.com",
"userRole": "USER",
"nickname": "테스터",
"exp": 1640995200,
"iat": 1640991600
}
이 포스팅이 JWT에 새로운 필드를 추가하는 과정에서 도움이 되었기를 바랍니다! 궁금한 점이 있다면 댓글로 남겨주세요. 😊