Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
import java.util.List;

public class JwtAuthentication extends AbstractAuthenticationToken {
private final String email;
private final Long userId;

public JwtAuthentication(String email) {

public JwtAuthentication(Long userId) {
super(List.of(new SimpleGrantedAuthority("ROLE_USER")));
this.email = email;
this.userId = userId;
setAuthenticated(true);
}

@Override public Object getCredentials() { return ""; }
@Override public Object getPrincipal() { return email; }
@Override public Object getPrincipal() { return userId; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,16 @@ protected void doFilterInternal(HttpServletRequest req,
String token = header.substring(7);

if (jwtProvider.validateToken(token)) {
String email = jwtProvider.getEmail(token);
var authentication = new JwtAuthentication(email);
Long userId = jwtProvider.getUserId(token);
var authentication = new JwtAuthentication(userId);
SecurityContextHolder.getContext().setAuthentication(authentication);
} else {
// 토큰이 유효하지 않으면 Context 클리어
SecurityContextHolder.clearContext();
}
} else {
// Authorization 헤더가 아예 없을 때도 Context 클리어
SecurityContextHolder.clearContext();
}

chain.doFilter(req, res);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,54 @@
import com.wayble.server.common.config.security.JwtProperties;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Date;

@Component
@RequiredArgsConstructor
public class JwtTokenProvider {
private final JwtProperties jwtProperties;
private final Key signingKey;

private Key getSigningKey() {
return Keys.hmacShaKeyFor(jwtProperties.getSecret().getBytes());
public JwtTokenProvider(JwtProperties jwtProperties) {
this.jwtProperties = jwtProperties;
this.signingKey = Keys.hmacShaKeyFor(
jwtProperties.getSecret().getBytes(StandardCharsets.UTF_8)
);
}

public String generateToken(String email, String role) {
public String generateToken(Long userId, String role) {
return Jwts.builder()
.setSubject(email)
.setSubject(String.valueOf(userId))
.claim("role", role)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + jwtProperties.getAccessExp()))
.signWith(getSigningKey(), SignatureAlgorithm.HS256)
.signWith(signingKey, SignatureAlgorithm.HS256)
.compact();
}

public boolean validateToken(String token) {
try {
Jwts.parserBuilder().setSigningKey(getSigningKey()).build().parseClaimsJws(token);
Jwts.parserBuilder().setSigningKey(signingKey).build().parseClaimsJws(token);
return true;
} catch (JwtException | IllegalArgumentException e) {
return false;
}
}

public String getEmail(String token) {
return Jwts.parserBuilder().setSigningKey(getSigningKey()).build()
.parseClaimsJws(token).getBody().getSubject();
// userId 파싱 메서드 추가
public Long getUserId(String token) {
if (!validateToken(token)) {
throw new IllegalArgumentException("Invalid token");
}
String subject = Jwts.parserBuilder()
.setSigningKey(signingKey)
.build()
.parseClaimsJws(token)
.getBody()
.getSubject();
return Long.parseLong(subject);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.wayble.server.user.dto;

import com.wayble.server.user.entity.LoginType;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

public record UserLoginRequestDto(
@NotBlank(message = "이름 또는 닉네임은 필수입니다")
Expand All @@ -12,5 +14,8 @@ public record UserLoginRequestDto(
String email,

@NotBlank(message = "비밀번호는 필수입니다")
String password
String password,

@NotNull(message = "로그인 타입은 필수입니다")
LoginType loginType
) {}
7 changes: 5 additions & 2 deletions src/main/java/com/wayble/server/user/entity/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@SQLDelete(sql = "UPDATE user SET deleted_at = now() WHERE id = ?")
@SQLRestriction("deleted_at IS NULL")
@Table(name = "user")
@Table(
name = "user",
uniqueConstraints = @UniqueConstraint(columnNames = {"email", "login_type"})
)
public class User extends BaseEntity {

@Id
Expand All @@ -30,7 +33,7 @@ public class User extends BaseEntity {

private String username;

@Column(nullable = false, unique = true)
@Column(nullable = false)
private String email;

// TODO: 비밀번호 암호화 필요
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.wayble.server.user.repository;

import com.wayble.server.user.entity.LoginType;
import com.wayble.server.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface UserRepository extends JpaRepository<User, Long> {

Optional<User> findByEmail(String email);

boolean existsByEmail(String email);
boolean existsByEmailAndLoginType(String email, LoginType loginType);
Optional<User> findByEmailAndLoginType(String email, LoginType loginType);
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class UserService {

// 회원가입
public void signup(UserRegisterRequestDto req) {
if (userRepository.existsByEmail(req.email())) {
if (userRepository.existsByEmailAndLoginType(req.email(), req.loginType())) {
throw new ApplicationException(UserErrorCase.USER_ALREADY_EXISTS);
}
User user = User.createUser(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ public class AuthService {
private final JwtTokenProvider jwtProvider;

public TokenResponseDto login(UserLoginRequestDto req) {
User user = userRepository.findByEmail(req.email())
User user = userRepository.findByEmailAndLoginType(req.email(), req.loginType())
.orElseThrow(() -> new ApplicationException(UserErrorCase.INVALID_CREDENTIALS));
if (!encoder.matches(req.password(), user.getPassword())) {
throw new ApplicationException(UserErrorCase.INVALID_CREDENTIALS);
}
String token = jwtProvider.generateToken(user.getEmail(), user.getUserType().name());
String token = jwtProvider.generateToken(user.getId(), user.getUserType().name());
return new TokenResponseDto(token);
}
}
Loading