Skip to content

Commit

Permalink
feat: 아이디, 패스워드로 회원가입/로그인 기능 추가 (#14)
Browse files Browse the repository at this point in the history
* feat: users 테이블에 일반 로그인 아이디 패스워드 방식의 칼럼 추가

* feat: 로그인 패스워드로 회원가입, 로그인 기능 추가
  • Loading branch information
gitchannn authored Nov 1, 2023
1 parent 62a05ec commit 08178ed
Show file tree
Hide file tree
Showing 19 changed files with 216 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,35 @@

import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
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;
import sallange.server.auth.api.request.AuthRequest;
import sallange.server.auth.api.request.UserJoinRequest;
import sallange.server.auth.api.response.AuthTokensResponse;
import sallange.server.auth.application.UserJoinService;
import sallange.server.auth.application.UserAuthService;

@RequiredArgsConstructor
@RestController
@RequestMapping("/test/users")
public class UserJoinController {
@RequestMapping("/api")
public class UserAuthController {

private final UserJoinService userJoinService;
private final UserAuthService userAuthService;

@PostMapping
@Transactional
@PostMapping("/join")
public ResponseEntity<AuthTokensResponse> join(@RequestBody final UserJoinRequest request) {
return ResponseEntity
.ok()
.body(userJoinService.join(request));
.body(userAuthService.join(request));
}

@PostMapping("/login")
public ResponseEntity<AuthTokensResponse> login(
@RequestBody AuthRequest request
) {
return ResponseEntity
.ok()
.body(userAuthService.login(request));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package sallange.server.auth.api.request;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public class AuthRequest {

private final String loginID;
private final String loginPassword;
}
Original file line number Diff line number Diff line change
@@ -1,42 +1,12 @@
package sallange.server.auth.api.request;

public class UserJoinRequest {

private final String name;
private final String oAuthProvider;
private final Long oAuthId;
private final Integer leftRentCount;

public UserJoinRequest(final String name, final String oAuthProvider, final Long oAuthId, final Integer leftRentCount) {
this.name = name;
this.oAuthProvider = oAuthProvider;
this.oAuthId = oAuthId;
this.leftRentCount = leftRentCount;
}

public String getName() {
return name;
}
import lombok.Getter;
import lombok.RequiredArgsConstructor;

public String getoAuthProvider() {
return oAuthProvider;
}

public Long getoAuthId() {
return oAuthId;
}

public Integer getLeftRentCount() {
return leftRentCount;
}
@Getter
@RequiredArgsConstructor
public class UserJoinRequest {

@Override
public String toString() {
return "UserJoinRequest{" +
"name='" + name + '\'' +
", oAuthProvider='" + oAuthProvider + '\'' +
", oAuthId=" + oAuthId +
", leftRentCount=" + leftRentCount +
'}';
}
private final String loginID;
private final String loginPassword;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package sallange.server.auth.application;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sallange.server.auth.api.request.AuthRequest;
import sallange.server.auth.api.request.UserJoinRequest;
import sallange.server.auth.api.response.AuthTokensResponse;
import sallange.server.auth.application.util.PasswordEncryptor;
import sallange.server.auth.util.AuthTokensGenerator;
import sallange.server.entity.User;
import sallange.server.repository.UserRepository;

import java.util.NoSuchElementException;

@RequiredArgsConstructor
@Service
@Transactional
public class UserAuthService {

private final UserRepository userRepository;
private final AuthTokensGenerator authTokensGenerator;

public AuthTokensResponse join(final UserJoinRequest request) {
final String loginId = request.getLoginID();
final String loginPassword = request.getLoginPassword();
if (userRepository.findByLoginId(loginId).isPresent()) {
throw new RuntimeException("[ERROR] 중복되는 아이디입니다.");
}

final String encryptedPassword = PasswordEncryptor.encrypt(loginPassword);

final User user = User.loginUserBuilder()
.loginId(loginId)
.encryptedPassword(encryptedPassword)
.build();

final Long id = userRepository.save(user).getId();
return authTokensGenerator.generate(id);
}

public AuthTokensResponse login(final AuthRequest request) {
final String loginId = request.getLoginID();
final String loginPassword = request.getLoginPassword();
final User user = userRepository.findByLoginId(loginId)
.orElseThrow(() -> new NoSuchElementException("[ERROR] 존재하지 않는 아이디입니다."));

user.checkPassword(PasswordEncryptor.encrypt(loginPassword));
return authTokensGenerator.generate(user.getId());
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package sallange.server.auth.application.util;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class PasswordEncryptor {

private static final String ALGORITHM = "SHA-256";

public static String encrypt(String password) {
try {
MessageDigest digest = MessageDigest.getInstance(ALGORITHM);
digest.update(password.getBytes());
return Base64.getEncoder().encodeToString(digest.digest());
} catch (NoSuchAlgorithmException exception) {
throw new IllegalArgumentException("암호화 알고리즘이 존재하지 않습니다.");
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ public class WebMvcConfig implements WebMvcConfigurer {
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(userAuthInterceptor)
.addPathPatterns("/api/**")
.excludePathPatterns("/api/login/**");
.excludePathPatterns(
"/api/login/**",
"/api/join/**"
);
}

@Override
Expand Down
26 changes: 25 additions & 1 deletion server/src/main/java/sallange/server/entity/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Builder;
import sallange.server.auth.OAuthProvider;
import sallange.server.exception.UnAuthorizationException;

import static jakarta.persistence.EnumType.STRING;
import static jakarta.persistence.GenerationType.IDENTITY;
Expand All @@ -26,16 +28,24 @@ public class User extends BaseDate {

@Column(name = "oauth_id")
private Long oAuthId;
private String loginId;
private String encryptedPassword;
private Integer leftRentCount;

public User(final Long id, final String name, final OAuthProvider oAuthProvider, final Long oAuthId, final Integer leftRentCount) {
public User(final Long id, final String name, final OAuthProvider oAuthProvider, final Long oAuthId, final String loginId, final String encryptedPassword, final Integer leftRentCount) {
this.id = id;
this.name = name;
this.oAuthProvider = oAuthProvider;
this.oAuthId = oAuthId;
this.loginId = loginId;
this.encryptedPassword = encryptedPassword;
this.leftRentCount = leftRentCount;
}

private User(final Long id, final String name, final OAuthProvider oAuthProvider, final Long oAuthId, final Integer leftRentCount) {
this(id, name, oAuthProvider, oAuthId, null, null, leftRentCount);
}

public User(final String name, final OAuthProvider oAuthProvider, final Long oAuthId, final Integer leftRentCount) {
this(null, name, oAuthProvider, oAuthId, leftRentCount);
}
Expand All @@ -44,6 +54,14 @@ public User(final String name, final OAuthProvider oAuthProvider, final Long oAu
this(null, name, oAuthProvider, oAuthId, 2);
}

@Builder(builderMethodName = "loginUserBuilder")
public User(
final String loginId,
final String encryptedPassword
) {
this(null, null, null, null, loginId, encryptedPassword, 2);
}

public User() {
}

Expand Down Expand Up @@ -74,4 +92,10 @@ public Long getoAuthId() {
public Integer getLeftRentCount() {
return leftRentCount;
}

public void checkPassword(final String encryptedPassword) {
if (!this.encryptedPassword.equals(encryptedPassword)) {
throw new UnAuthorizationException("[ERROR] 아이디와 패스워드가 올바르지 않습니다!");
}
}
}
33 changes: 31 additions & 2 deletions server/src/main/java/sallange/server/http/auth-request.http
Original file line number Diff line number Diff line change
@@ -1,4 +1,33 @@
### 카카오로 로그인 버튼 클릭
GET {{host}}/api/login/kakao
### 로그인 버튼 클릭
GET http://15.165.231.19:8080/api/login/kakao
Content-Type: application/json

### 살랑이 서버로부터 액세스 토큰 발급
GET http://15.165.231.19:8080/api/login/kakao/token?code=aH2sHl41OKXXCtyIRyU0CfDW3dgwl-16jTilcTDAvZJBGynZ9VXfLaBbgqQKKcleAAABi4oG62no6jj-qNQmaA
Content-Type: application/json

### 로컬 로그인 버튼 클릭
GET http://localhost:8080/api/login/kakao
Content-Type: application/json

### 로컬에서 액세스 토큰 발급
GET http://localhost:8080/api/login/kakao/token?code=iBKjkBdHJDU3a57ZiPM_344lHvMTjmgtUwqFdVrx5TSE1llY1hEj6tIKJxoKPXSYAAABi4oZjRr7Ewsnpgvovw
Content-Type: application/json

### 아이디, 패스워드로 회원가입
POST http://localhost:8080/api/join
Content-Type: application/json

{
"loginID": "gitchan",
"loginPassword": "gitchan1234"
}

### 아이디, 패스워드로 로그인
POST http://localhost:8080/api/login
Content-Type: application/json

{
"loginID": "gitchan",
"loginPassword": "gitchan1234"
}
24 changes: 23 additions & 1 deletion server/src/main/java/sallange/server/http/cycle-request.http
Original file line number Diff line number Diff line change
@@ -1,7 +1,29 @@
### 유저 로그인 (테스트용)
POST http://15.165.231.19:8080/test/users
Content-Type: application/json

{
"name": "깃짱",
"oAuthProvider": "KAKAO",
"oAuthId": 123,
"leftRentCount": 2
}

### 살랑이 생성 요청
POST http://15.165.231.19:8080/admin/cycles
Content-Type: application/json

### 살랑이 대여 요청
POST {{host}}/rent
POST http://15.165.231.19:8080/cycles/rent
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwiZXhwIjoxNjk4ODk4NjQyfQ.YfedMD0NFfKrFv7NdcfYUhhf90vGhk2Qd6hx1548Hs8099k9xlUdueD_VEddxr_H6vV11Q4gnE4cyOYHplxs-w

{
"cycleID": "1"
}

### 살랑이 반납 요청
POST http://15.165.231.19:8080/cycles/return-cycle
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwiZXhwIjoxNjk4ODk4NjQyfQ.YfedMD0NFfKrFv7NdcfYUhhf90vGhk2Qd6hx1548Hs8099k9xlUdueD_VEddxr_H6vV11Q4gnE4cyOYHplxs-w

Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
### 서버 헬스 체크 요청
GET {{host}}/health-check
GET http://15.165.231.19:8080/admin/health-check
Content-Type: application/json

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ Optional<Long> findIdByOAuthProviderAndOAuthId(
@Param("oAuthProvider") OAuthProvider oAuthProvider,
@Param("oAuthId") Long oAuthId
);

Optional<User> findByLoginId(String loginId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
alter table users
add `login_id` varchar(255);

alter table users
add `encrypted_password` varchar(255);
2 changes: 1 addition & 1 deletion server/src/main/resources/security
Loading

0 comments on commit 08178ed

Please sign in to comment.