관리 메뉴

bright jazz music

todo-java 본문

Framework/ReactJs

todo-java

bright jazz music 2023. 5. 24. 22:22
package com.example.reactspringtodo.controller;

import com.example.reactspringtodo.dto.ResponseDTO;
import com.example.reactspringtodo.dto.UserDTO;
import com.example.reactspringtodo.entity.UserEntity;
import com.example.reactspringtodo.security.TokenProvider;
import com.example.reactspringtodo.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("/auth")
public class UserController {

    private UserService userService;
    private TokenProvider tokenProvider;

    private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    public UserController (UserService userService, TokenProvider tokenProvider) {
        this.userService = userService;
        this.tokenProvider = tokenProvider;
    }

    @PostMapping("/signup")
    public ResponseEntity<?> registerUser(@RequestBody UserDTO userDTO) {
        System.out.println("################################# signup#################################");

        try {//DB는 nullable이기 때문에, 비밀번호가 존재하는지를 컨트롤러에서 반드시 확인해야 한다.
            if(userDTO == null || userDTO.getPassword() == null) {
                throw new RuntimeException("Invalid Password value");
            }

            UserEntity user = UserEntity.builder()
                    .username(userDTO.getUsername())
                    //.password(userDTO.getPassword()) 암호화 후에는 아래와 같이 변
                    .password(passwordEncoder.encode(userDTO.getPassword())) //패스워드를 암호화하여 저장
                    .build();

            //UserEntity 값을 DB에 등록하고 등록한 값을 반환함.경
            UserEntity registeredUser = userService.create(user);

            UserDTO responseUserDTO = UserDTO.builder()
                    .id(registeredUser.getId())
                    .username(registeredUser.getUsername())
                    .build();

            return ResponseEntity.ok().body(responseUserDTO);

        }catch (Exception e) {
            //유저 정보는 항상 하나이므로 리스트로 만들어야 하는 ResponseDTO를 사용하지 않는다.
            //그냥 UserDTO를 리턴한다.

            ResponseDTO responseDTO = ResponseDTO.builder()
                    .error(e.getMessage())
                    .build();

            return ResponseEntity
                    .badRequest()
                    .body(responseDTO);
        }
    }

    @PostMapping("/signin")
    public ResponseEntity<?> authenticate(@RequestBody UserDTO userDTO) {
        System.out.println("################################# signin#################################");
        System.out.println(userDTO.getUsername());
        System.out.println(userDTO.getPassword());
        //DB에 등록되 값이 존재하는지 확인하고 존재하는 경우 UserEntity 값을 반환함.
        UserEntity user = userService.getByCredentials(
                userDTO.getUsername(),
                userDTO.getPassword(),
                //PasswordEncoder를 함께 넘긴다.
                passwordEncoder
        );

        //값이 존재하는 경우 UserDTO를 만들어 반환
        if(user != null) {
            //토큰 생성
            final String token = tokenProvider.create(user);
            System.out.println("###created Token: " + token);

            final UserDTO responseUserDTO = UserDTO.builder()
                    .username(user.getUsername())
                    .id(user.getId())
                    .token(token) //tokenProvider를 사용해 생성한 토큰을 UserDTO에 넣어준다.
                    .build();

            return ResponseEntity.ok().body(responseUserDTO);

        } else {
            // 로그인 정보가 존재하지 않는 경우 responseDTO를 생성하여 ResponseEntity의 body 값에 담아 반환한다.
            ResponseDTO<?> responseDTO = ResponseDTO.builder()
                    .error("Login failed.")
                    .build();

            return ResponseEntity.badRequest().body(responseDTO);
        }
    }
}

UserEntity.java

package com.example.reactspringtodo.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;

@Data
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(uniqueConstraints = {@UniqueConstraint(columnNames = "username")})
public class UserEntity {
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name="system-uuid", strategy = "uuid")
    private String id; //유저에게 고유하게 부여되는 id.

    @Column(nullable = false)
    private String username;

    // 패스워드. OAuth를 사용할 경우에는 null이다. null을 비허용할 경우 OAuth 구현에 문제가 발생한다.
    // DB에 null이 입력되는 대신, 컨트롤러에서 password를 반드시 입력하도록 만들어야 한다.
    private String password;

    //사용자의 롤. 예: 어드민, 일반 사용자
    private String role;

    // 이후 OAuth에서 사용할 유저 정보 제공자: github
    private String authProvider;

}

 

UserRepository.java

package com.example.reactspringtodo.persistence;

import com.example.reactspringtodo.entity.UserEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends JpaRepository<UserEntity, String> {

    UserEntity findByUsername(String username);
    Boolean existsByUsername(String username);
    UserEntity findByUsernameAndPassword(String username, String password);
}

 

UserService.java

package com.example.reactspringtodo.service;

import com.example.reactspringtodo.entity.UserEntity;
import com.example.reactspringtodo.persistence.UserRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class UserService {

    private UserRepository userRepository;
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public UserEntity create(final UserEntity userEntity) {
        if(userEntity == null || userEntity.getUsername() == null) {
            throw new RuntimeException("Invalid argument");
        }

        final String username = userEntity.getUsername();

        if(userRepository.existsByUsername(username)){ //존재한다면
            log.warn("Username already exists {}", username);
            throw new RuntimeException("Username already exists");
        }

        return userRepository.save(userEntity);
    }

    public UserEntity getByCredentials(final String username, final String password) {
        return userRepository.findByUsernameAndPassword(username, password);
    }
}

 

UserDto.java

package com.example.reactspringtodo.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserDTO {
    private String token;
    private String username;
    private String password;
    private String id;
}

 

UserController.java

package com.example.reactspringtodo.controller;

import com.example.reactspringtodo.dto.ResponseDTO;
import com.example.reactspringtodo.dto.UserDTO;
import com.example.reactspringtodo.entity.UserEntity;
import com.example.reactspringtodo.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("/auth")
public class UserController {

    private UserService userService;

    public UserController (UserService userService) {
        this.userService = userService;
    }

    @PostMapping("/signup")
    public ResponseEntity<?> registerUser(@RequestBody UserDTO userDTO) {
        System.out.println("################################# signup#################################");

        try {//DB는 nullable이기 때문에, 비밀번호가 존재하는지를 컨트롤러에서 반드시 확인해야 한다.
            if(userDTO == null || userDTO.getPassword() == null) {
                throw new RuntimeException("Invalid Password value");
            }

            UserEntity user = UserEntity.builder()
                    .username(userDTO.getUsername())
                    .password(userDTO.getPassword())
                    .build();

            UserEntity registeredUser = userService.create(user);
            UserDTO responseUserDTO = UserDTO.builder()
                    .id(registeredUser.getId())
                    .username(registeredUser.getUsername())
                    .build();

            return ResponseEntity.ok().body(responseUserDTO);

        }catch (Exception e) {
            //유저 정보는 항상 하나이므로 리스트로 만들어야 하는 ResponseDTO를 사용하지 않는다.
            //그냥 UserDTO를 리턴한다.

            ResponseDTO responseDTO = ResponseDTO.builder()
                    .error(e.getMessage())
                    .build();

            return ResponseEntity
                    .badRequest()
                    .body(responseDTO);
        }
    }

    @PostMapping("/signin")
    public ResponseEntity<?> authenticate(@RequestBody UserDTO userDTO) {
        System.out.println("################################# signin#################################");
        UserEntity user = userService.getByCredentials(
                userDTO.getUsername(),
                userDTO.getPassword()
        );

        if(user != null) {
            UserDTO responseUserDTO = UserDTO.builder()
                    .username(user.getUsername())
                    .id(user.getId())
                    .build();

            return ResponseEntity.ok().body(responseUserDTO);

        } else {
            ResponseDTO<?> responseDTO = ResponseDTO.builder()
                    .error("Login failed.")
                    .build();

            return ResponseEntity.badRequest().body(responseDTO);
        }
    }
}

 

TokenProvider.java

package com.example.reactspringtodo.security;

import com.example.reactspringtodo.entity.UserEntity;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;

@Slf4j
@Service
public class TokenProvider {
    private static final String SECRET_KEY="FlRpX30pMqDbiAkmlfArbrmVkDD4RqISskGZmBFax5oGVxzXXWUz TR5JyskiHMIV9M1Oicegkpi46AdvrcX1E6CmTUBc6IFbTPiD";

    public String create(UserEntity userEntity) {
     //기한을 하루로 설정
        Date expiryDate = Date.from(Instant.now().plus(1, ChronoUnit.DAYS));

        return Jwts.builder()
                //header에 들어갈 내용 및 서명을 기하 위한 Secret Key
                .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
                .setSubject(userEntity.getId()) //sub
                .setIssuer("demo app") //iss
                .setIssuedAt(new Date()) //iat
                .setExpiration(expiryDate) //exp
                .compact();
    }
}
Comments