본문으로 바로가기

User JWT 적용

category Spring boot 2024. 11. 7. 17:27

UserController

package com.tenco.blog_v3.board;

import com.tenco.blog_jpa_step4.commom.errors.Exception403;
import com.tenco.blog_jpa_step4.commom.errors.Exception404;
import com.tenco.blog_jpa_step4.commom.utils.ApiUtil;
import com.tenco.blog_jpa_step4.commom.utils.Define;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

/**
 * UserController 사용자(User)와 관련된 HTTP 요청을 처리하는 컨트롤러 계층입니다.
 */
@Slf4j
@RestController
@RequiredArgsConstructor
public class UserController {

    private final UserService userService; // UserService 주입

    // 회원 정보 조회 -- > 추후 api/users/{id} 로 수정
    @GetMapping("/api/users/{id}")
    public ResponseEntity<ApiUtil<UserResponse.DTO>> userinfo(@PathVariable(name = "id") Integer id,
                                                              HttpServletRequest request) {
        // 인터셉터에서 설정한 사용자 정보를 가져오기
        User sessionUser = (User) request.getAttribute(Define.SESSION_USER);

        if (sessionUser == null) {
            throw new Exception404("사용자를 찾을 수 없습니다."); // 사용자가 존재하지 않는 경우 예외 던지기
        }

        UserResponse.DTO resDTO = userService.findUserById(sessionUser.getId());
        return ResponseEntity.ok(new ApiUtil<>(resDTO));
    }

    /**
     * 사용자 정보 수정 요청 처리
     *
     * @param id      수정할 사용자 ID
     * @param reqDTO  수정된 사용자 정보 DTO
     * @return 수정된 사용자 정보의 DTO
     */
    @PutMapping("/api/users/{id}")
    public ResponseEntity<ApiUtil<UserResponse.DTO>> updateUser(@PathVariable int id,
                                                                @RequestBody UserRequest.UpdateDTO reqDTO,
                                                                HttpServletRequest request) {

        // 인터셉터에서 설정한 사용자 정보를 가져오기
        User sessionUser = (User) request.getAttribute(Define.SESSION_USER);

        if (sessionUser == null) {
            throw new Exception404("사용자를 찾을 수 없습니다."); // 사용자가 존재하지 않는 경우 예외 던지기
        }

        if (sessionUser.getId() != id) {
            throw new Exception403("해당 사용자를 수정할 권한이 없습니다."); // 권한 없음 예외 던지기
        }

        UserResponse.DTO resDTO = userService.updateUser(id, reqDTO, sessionUser);
        return ResponseEntity.ok(new ApiUtil<>(resDTO));
    }

    @PostMapping("/join")
    public ResponseEntity<ApiUtil<UserResponse.DTO>> join(@RequestBody UserRequest.JoinDTO reqDTO) {
        UserResponse.DTO resDTO = userService.signUp(reqDTO);
        return ResponseEntity.ok(new ApiUtil<>(resDTO));
    }

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody UserRequest.LoginDTO reqDTO) {
        String jwt = userService.signIn(reqDTO);
        return ResponseEntity.ok()
                // 반드시 주의!!! Bearer 문자열 뒤에 반드시 한칸에 공백을 넣어 주세요 ~~
                .header("Authorization", "Bearer " + jwt)
                .body(new ApiUtil<>(null));
    }

    @GetMapping("/logout")
    public ResponseEntity<?> logout(HttpSession session) {
        session.invalidate();
        return ResponseEntity.ok(new ApiUtil<>(null));
    }
}

BoardService

package com.tenco.blog_v3.board;

import com.tenco.blog_jpa_step4.commom.errors.Exception400;
import com.tenco.blog_jpa_step4.commom.errors.Exception401;
import com.tenco.blog_jpa_step4.commom.errors.Exception404;
import com.tenco.blog_jpa_step4.commom.utils.JwtUtil;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.Optional;

@RequiredArgsConstructor
@Service // 서비스 계층으로 등록 및 IoC
public class UserService {

    private final UserJPARepository userJPARepository;

    /**
     * 회원 정보 조회 서비스
     *
     * @param id 조회할 사용자 ID
     * @return 조회된 사용자 객체의 DTO
     * @throws Exception404 사용자를 찾을 수 없는 경우 발생
     */
    public UserResponse.DTO findUserById(int id){
        User user = userJPARepository.findById(id)
                .orElseThrow(() -> new Exception404("회원정보를 찾을 수 없습니다"));
        return new UserResponse.DTO(user);
    }

    /**
     * 회원가입 서비스
     *
     * @param reqDTO 회원가입 요청 DTO
     * @return 회원가입 완료된 사용자 정보의 DTO
     * @throws Exception400 중복된 유저네임인 경우 발생
     */
    @Transactional // 트랜잭션 관리
    public UserResponse.DTO signUp(UserRequest.JoinDTO reqDTO) {
        // 1. 유저네임 중복검사 (DB 연결이 필요한 것은 Controller 에서 작성하지 말자)
        Optional<User> userOP = userJPARepository.findByUsername(reqDTO.getUsername());

        if (userOP.isPresent()) {
            throw new Exception400("중복된 유저네임입니다");
        }
        // 2. 회원가입
        User savedUser = userJPARepository.save(reqDTO.toEntity());
        return new UserResponse.DTO(savedUser);
    }

    /**
     * 로그인 서비스
     *
     * @throws Exception401 인증 실패 시 발생
     */
    // 리턴 타입 변경
    public String signIn(UserRequest.LoginDTO reqDTO) {
        User user = userJPARepository.findByUsernameAndPassword(reqDTO.getUsername(), reqDTO.getPassword())
                .orElseThrow(() -> new Exception401("인증되지 않았습니다"));


        // session.setAttribute("sessionUser", user); // 세션에 사용자 정보 저장
        // jwt 문자열 반환 처리
        return JwtUtil.create(user); // 로그인 시 이메일 정보 제외
    }

    /**
     * 회원 정보 수정 서비스
     *
     * @param id 수정할 사용자 ID
     * @param reqDTO 수정된 사용자 정보 DTO
     * @return 수정된 사용자 객체의 DTO
     * @throws Exception404 사용자를 찾을 수 없는 경우 발생
     */
    @Transactional // 트랜잭션 관리
    public UserResponse.DTO updateUser(int id, UserRequest.UpdateDTO reqDTO,  User sessionUser) {
        // 1. 사용자 조회 및 예외 처리
        User user = userJPARepository.findById(sessionUser.getId())
                .orElseThrow(() -> new Exception404("회원정보를 찾을 수 없습니다"));
        // 2. 사용자 정보 수정
        user.setPassword(reqDTO.getPassword());
        user.setEmail(reqDTO.getEmail());
        // 더티 체킹을 통해 변경 사항이 자동으로 반영됩니다.

        return new UserResponse.DTO(user);
    }
}

'Spring boot' 카테고리의 다른 글

Session이란 무엇인가  (0) 2025.01.07
Board JWT 적용  (3) 2024.11.07
JWT 인터셉터 적용  (1) 2024.11.07
JDBC란 뭘까? - 1  (1) 2024.11.07
Reply JWT 적용  (2) 2024.11.07