Tiny Star

📌TIL [Today I Learn]

[TIL] 23년 6월 26일 월요일

청크 2023. 6. 26. 21:24

23년 6월 26일 월요일

오늘의 목표 : 숙련주차 개인과제

 

오늘 공부한 내용🤓

지난주부터 시작한 Spring 숙련 과제!

필수 요구 사항들은 오늘 다 구현했다!!

다른 것보다 Token이 진짜 너무 어려웠다...

 

Jwt secret key 발급하는 방법을 몰라서 튜터님께 여쭤봤는데 그냥 내가 마음대로 만들면 되는거라고....하하

리눅스에 [openssl rand -hex 64] 이렇게 작성하면 Base64 방식으로 Encode한 Key가 손쉽게 발급된다!

@Value("${jwt.secret.key}")
    // Base64 Encode 한 SecretKey
    // Application.properties 에 넣어놓은 값을 가져옴

    private String secretKey;
    private Key key; // Token 생성 시 넣을 Key 값
    private final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

    //로그
    public static final Logger logger = LoggerFactory.getLogger("JWT 로그");

그래서 완성할 수 있었던 JwtUil class!

 

아직 구현해야 할 것들이 산더미처럼 남아있지만

일단 오늘 회원 가입 , 로그인 API 두가지 필수 요구사항은 다 되었으니 만족스러운 월요일이다.

[User Controller]

package com.sparta.blogapi.controller;

import com.sparta.blogapi.dto.LoginRequestDto;
import com.sparta.blogapi.dto.SignupRequestDto;
import com.sparta.blogapi.dto.UserResponseDto;
import com.sparta.blogapi.service.UserService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;

@Slf4j
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor  //생성자 주입으로 userService에 대한 생성자를 생성하지 않아도 됨
public class UserController {

    private final UserService userService;


//    1. 회원 가입 API
    @PostMapping("/user/signup")
    public UserResponseDto signup(@RequestBody SignupRequestDto requestDto,HttpServletResponse res){
        return userService.signup(requestDto,res);
    }



//2. 로그인 API
    @PostMapping("/user/login")
    public UserResponseDto login(@RequestBody LoginRequestDto requestDto, HttpServletResponse res) throws IOException {

        return userService.login(requestDto,res);
    }
}

[User Service]

package com.sparta.blogapi.service;


import com.sparta.blogapi.dto.LoginRequestDto;
import com.sparta.blogapi.dto.SignupRequestDto;
import com.sparta.blogapi.dto.UserResponseDto;
import com.sparta.blogapi.entity.User;
import com.sparta.blogapi.jwt.JwtUtil;
import com.sparta.blogapi.repository.UserRepository;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.IOException;
import java.util.Optional;

@Service //Service 사용
@RequiredArgsConstructor //생성자 주입으로 데이터베이스에 대한 생성자를 생성하지 않아도 됨
@RequestMapping("/api")
public class UserService {

    private final UserRepository userRepository; // userRepository 주입
    private final PasswordEncoder passwordEncoder; //비밀번호 암호화 인터페이스
    private final JwtUtil jwtUtil;

    //    1. 회원 가입 API
    public UserResponseDto signup(SignupRequestDto requestDto,HttpServletResponse res) {
        // username, password를 Client에서 전달받기
        String username = requestDto.getUsername();
        String password = passwordEncoder.encode(requestDto.getPassword());

        // 유저 중복확인
        Optional<User> checkUsername = userRepository.findByUsername(username);
        if (checkUsername.isPresent()) { // isPresent()는 Optional 객체가 비어있지 않은 경우에 true를 반환하고, 값이 존재하지 않는 경우에 false를 반환
            //중복된 유저네임이 존재 할 경우 예외처리
            throw new IllegalArgumentException("중복된 사용자가 존재합니다.");
        }

        // 유저 등록
        userRepository.save(new User(username,password));

        UserResponseDto userResponseDto = new UserResponseDto("회원가입이 완료되었습니다.", 200);
        //    - DB에 중복된 username 이 없다면 회원을 저장하고 Client 로 성공했다는 메시지, 상태코드 반환하기
        return userResponseDto;
    }


    //    2. 로그인 API
    @Transactional(readOnly = true)
    public UserResponseDto login(LoginRequestDto requestDto, HttpServletResponse res) throws IOException {
        //    - username, password를 Client에서 전달받기
        String username = requestDto.getUsername();
        String password = requestDto.getPassword();
        //username 확인
        //    - DB에서 username을 사용하여 저장된 회원의 유무를 확인하고 있다면 password 비교하기
        User user = userRepository.findByUsername(username).orElseThrow(
                ()-> new IllegalArgumentException("회원가입 된 사용자가 없습니다."));

        //password 확인
        if (!user.getPassword().equals(password)) {
            throw new IllegalArgumentException("비밀번호가 일치하지 않습니다.");
        }

        //로그인에 성공한 유저의 정보와 JWT를 활용하여 토큰을 발급
        //JWT Token 생성 및 쿠키에 저장
        String token = jwtUtil.createToken(user.getUsername());

        //Response 객체에 추가,
        jwtUtil.addJwtToCookie(token, res);

        // 로그인 성공
        UserResponseDto userResponseDto = new UserResponseDto("로그인에 성공하였습니다.",HttpServletResponse.SC_OK);
        return userResponseDto;
    }



}

 

어려웠던 내용😵‍💫

토큰이 진짜 제일 어렵다.

단 한가지도 이해 못한게 있다면.. 그건 바로 토큰...

궁금&부족한 내용❓

필수 요구 사항들은 전부 구현했지만 아직 선택 요구 사항들이 남아 있다.

선택 요구 사항의 내용이 대부분 토큰을 이용한 것들이라 다 구현할 수 있을지 모르겠당..

 

느낀 점💡

요새 21시 캠프 종료 이후  동기분이랑 스터디를 주 5일 내내 하고 있다.

어쩔 수 없이 강의와 과제에 밀려서 후다닥 지나가버린 것들을 천천히 공부하면서 다 이해하자는 취지에서 시작한건데

공부에 정말 큰 도움이 된다.

 

강의에서 몰랐던 내용도 과제를 하면서 구글링하고 코드 많이 썼다 지웠다 하면서 구조가 슬슬 눈에 익는다.아직 많이 어렵지만 매일매일 성장하는 내가 너무 뿌듯하다!!

 

'📌TIL [Today I Learn]' 카테고리의 다른 글

[TIL] 23년 6월 28일 수요일  (0) 2023.06.28
[TIL] 23년 6월 27일 화요일  (0) 2023.06.27
[TIL] 23년 6월 22일 목요일  (0) 2023.06.22
[TIL] 23년 6월 19일 월요일  (0) 2023.06.20
[TIL] 23년 6월 16일 금요일  (0) 2023.06.16