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
6 changes: 4 additions & 2 deletions refrigerator/.idea/modules/refrigerator.main.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package moja.refrigerator.aggregate.user;

import jakarta.persistence.*;
import lombok.Data;

@Entity
@Table(name = "tbl_token_blacklist")
@Data
public class TokenBlacklist {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long blacklistPk;

@Column(nullable = false)
private String blacklistToken;
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package moja.refrigerator.config;

import jakarta.servlet.http.HttpServletResponse;
import moja.refrigerator.jwt.JWTFilter;
import moja.refrigerator.jwt.JWTUtil;
import moja.refrigerator.jwt.LoginFilter;
import moja.refrigerator.jwt.LogoutFilter;
import moja.refrigerator.repository.user.TokenBlacklistRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
Expand All @@ -21,10 +24,14 @@ public class SecurityConfig {
private final AuthenticationConfiguration authenticationConfiguration;
// JWTUtil 주입
private final JWTUtil jwtUtil;
private final LogoutFilter logoutFilter;
private final TokenBlacklistRepository tokenBlacklistRepository;

public SecurityConfig(AuthenticationConfiguration authenticationConfiguration, JWTUtil jwtUtil) {
public SecurityConfig(AuthenticationConfiguration authenticationConfiguration, JWTUtil jwtUtil, LogoutFilter logoutFilter, TokenBlacklistRepository tokenBlacklistRepository) {
this.authenticationConfiguration = authenticationConfiguration;
this.jwtUtil = jwtUtil;
this.logoutFilter = logoutFilter;
this.tokenBlacklistRepository = tokenBlacklistRepository;
}

@Bean
Expand Down Expand Up @@ -66,11 +73,22 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); // JWT 사용을 위한 세션리스 설정

// 로그인 필터 추가
http
.addFilterBefore(new JWTFilter(jwtUtil), LoginFilter.class);
http
.addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration), jwtUtil), UsernamePasswordAuthenticationFilter.class);

http
.addFilterAfter(new JWTFilter(jwtUtil, tokenBlacklistRepository), LoginFilter.class);

http
.logout(logout -> logout
.logoutUrl("/logout")
.addLogoutHandler(logoutFilter)
.logoutSuccessHandler((request, response, authentication) -> {
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().write("로그아웃 되었습니다.");
}));

return http.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package moja.refrigerator.controller.user;

import jakarta.servlet.http.HttpServletRequest;
import moja.refrigerator.dto.user.request.UserCreateRequest;
import moja.refrigerator.service.user.UserService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
Expand All @@ -23,7 +25,8 @@ public String getMainPage() {

// 회원 가입 처리
@PostMapping("/auth/join")
public void joinProcess(@RequestBody UserCreateRequest request) {
public ResponseEntity<?> join(@RequestBody UserCreateRequest request) {
userService.createUser(request);
return ResponseEntity.ok().body("회원가입이 완료되었습니다.");
}
}
11 changes: 10 additions & 1 deletion refrigerator/src/main/java/moja/refrigerator/jwt/JWTFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import jakarta.servlet.http.HttpServletResponse;
import moja.refrigerator.aggregate.user.User;
import moja.refrigerator.dto.user.CustomUserDetails;
import moja.refrigerator.repository.user.TokenBlacklistRepository;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
Expand All @@ -15,9 +16,11 @@

public class JWTFilter extends OncePerRequestFilter {
private final JWTUtil jwtUtil;
private final TokenBlacklistRepository tokenBlacklistRepository;

public JWTFilter(JWTUtil jwtUtil) {
public JWTFilter(JWTUtil jwtUtil, TokenBlacklistRepository tokenBlacklistRepository) {
this.jwtUtil = jwtUtil;
this.tokenBlacklistRepository = tokenBlacklistRepository;
}

@Override
Expand All @@ -33,6 +36,12 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse

String token = authorization.split(" ")[1];

// 블랙리스트 체크
if (tokenBlacklistRepository.existsByBlacklistToken(token)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return;
}

// 토큰 소멸 시간 검증
if (jwtUtil.isExpired(token)) {
// 만료된 토큰이면 그냥 통과
Expand Down
34 changes: 34 additions & 0 deletions refrigerator/src/main/java/moja/refrigerator/jwt/LogoutFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package moja.refrigerator.jwt;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import moja.refrigerator.aggregate.user.TokenBlacklist;
import moja.refrigerator.repository.user.TokenBlacklistRepository;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.stereotype.Component;

@Component
public class LogoutFilter implements LogoutHandler {
private final TokenBlacklistRepository tokenBlacklistRepository;

public LogoutFilter(TokenBlacklistRepository tokenBlacklistRepository) {
this.tokenBlacklistRepository = tokenBlacklistRepository;
}

@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
String authorization = request.getHeader("Authorization");

if (authorization == null || !authorization.startsWith("Bearer ")) {
throw new IllegalArgumentException("토큰이 유효하지 않습니다.");
}

String token = authorization.split(" ")[1];

// 토큰을 블랙리스트에 추가
TokenBlacklist blacklist = new TokenBlacklist();
blacklist.setBlacklistToken(token);
tokenBlacklistRepository.save(blacklist);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package moja.refrigerator.repository.user;

import moja.refrigerator.aggregate.user.TokenBlacklist;
import org.springframework.data.jpa.repository.JpaRepository;

public interface TokenBlacklistRepository extends JpaRepository<TokenBlacklist, Long> {
boolean existsByBlacklistToken(String blacklistToken);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package moja.refrigerator.service.user;

import jakarta.servlet.http.HttpServletRequest;
import moja.refrigerator.dto.user.request.UserCreateRequest;

public interface UserService {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package moja.refrigerator.service.user;

import jakarta.servlet.http.HttpServletRequest;
import moja.refrigerator.aggregate.user.TokenBlacklist;
import moja.refrigerator.aggregate.user.User;
import moja.refrigerator.dto.user.request.UserCreateRequest;
import moja.refrigerator.exception.user.DuplicateUserException;
import moja.refrigerator.repository.user.TokenBlacklistRepository;
import moja.refrigerator.repository.user.UserRepository;
import org.modelmapper.ModelMapper;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
Expand All @@ -17,11 +20,13 @@ public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final BCryptPasswordEncoder passwordEncoder;
private final ModelMapper modelMapper;
private final TokenBlacklistRepository tokenBlacklistRepository;

public UserServiceImpl(UserRepository userRepository, BCryptPasswordEncoder passwordEncoder, ModelMapper modelMapper) {
public UserServiceImpl(UserRepository userRepository, BCryptPasswordEncoder passwordEncoder, ModelMapper modelMapper, TokenBlacklistRepository tokenBlacklistRepository) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
this.modelMapper = modelMapper;
this.tokenBlacklistRepository = tokenBlacklistRepository;
}

@Override
Expand All @@ -40,7 +45,6 @@ public void createUser(UserCreateRequest request) {
userRepository.save(user);
}


private void checkDuplicateUser(UserCreateRequest request) {
List<String> errors = new ArrayList<>();
if (userRepository.existsByUserId(request.getUserId())) {
Expand Down