TodoList 프로젝트 - User 로그인/회원가입 API
1. User 로그인/회원가입 API
1-1. Entity
@Data
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "member",uniqueConstraints = {@UniqueConstraint(columnNames = "email")})
public class UserEntity {
@Id
@GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
private String id; // 유저에게 고유하게 부여되는 id.
@Column(nullable = false)
private String username; // 유저의 이름
@Column(nullable = false)
private String email; // 유저의 email, 아이디와 같은 기능을 한다.
@Column(nullable = false)
private String password; // 패스워드. null이 가능한 이유는 oAuth로 페이스북이나 트위터같은 제3의 어플리케이션을 통해 로그인 할 수 있게 하기 위함이다.
}
1-2. Repository
@Repository
public interface UserRepository extends JpaRepository<UserEntity, String> {
//이메일 찾기
UserEntity findByEmail(String email);
//이메일 값이 있는지 검사
Boolean existsByEmail(String email);
//이메일and패스워드 찾기
UserEntity findByEmailAndPassword(String email, String password);
}
1-3. 회원가입 API
1)Controller
@RestController
@RequestMapping("/auth")
public class UserController {
@Autowired
private UserService userService;
@Autowired
private TokenProvider tokenProvider;
// Bean으로 작성해도 됨.
private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
@PostMapping("/signup")
public ResponseEntity<?> registerUser(@RequestBody UserDTO userDTO) {
try {
// 리퀘스트를 이용해 저장할 유저 만들기
UserEntity user = UserEntity.builder()
.email(userDTO.getEmail())
.username(userDTO.getUsername())
.password(passwordEncoder.encode(userDTO.getPassword()))
.build();
System.out.println(user);
// 서비스를 이용해 리파지토리에 유저 저장
UserEntity registeredUser = userService.create(user);
UserDTO responseUserDTO = UserDTO.builder()
.email(registeredUser.getEmail())
.id(registeredUser.getId())
.username(registeredUser.getUsername())
.build();
// 유저 정보는 항상 하나이므로 그냥 리스트로 만들어야하는 ResponseDTO를 사용하지 않고 그냥 UserDTO 리턴.
return ResponseEntity.ok(responseUserDTO);
} catch (Exception e) {
// 예외가 나는 경우 bad 리스폰스 리턴.
ResponseDTO responseDTO = ResponseDTO.builder().error(e.getMessage()).build();
return ResponseEntity
.badRequest()
.body(responseDTO);
}
}
2)Service
@Slf4j
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public UserEntity create(final UserEntity userEntity) {
if(userEntity == null || userEntity.getEmail() == null ) {
throw new RuntimeException("Invalid arguments");
}
final String email = userEntity.getEmail();
if(userRepository.existsByEmail(email)) {
log.warn("Email already exists {}", email);
throw new RuntimeException("Email already exists");
}
return userRepository.save(userEntity);
}
1-3. 로그인 API
1)Controller
@PostMapping("/signin")
public ResponseEntity<?> authenticate(@RequestBody UserDTO userDTO) {
UserEntity user = userService.getByCredentials(
userDTO.getEmail(),
userDTO.getPassword(),
passwordEncoder);
if(user != null) {
// 토큰 생성
final String token = tokenProvider.create(user);
final UserDTO responseUserDTO = UserDTO.builder()
.username(user.getUsername())
.email(user.getEmail())
.id(user.getId())
.token(token)
.build();
return ResponseEntity.ok().body(responseUserDTO);
} else {
ResponseDTO responseDTO = ResponseDTO.builder()
.error("Login failed.")
.build();
return ResponseEntity
.badRequest()
.body(responseDTO);
}
}
2)Service
public UserEntity getByCredentials(final String email, final String password, final PasswordEncoder encoder) {
final UserEntity originalUser = userRepository.findByEmail(email);
// matches 메서드를 이용해 패스워드가 같은지 확인
if(originalUser != null && encoder.matches(password, originalUser.getPassword())) {
return originalUser;
}
return null;
}