-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: 소속 단위 선거 기본 정보 추가 기능 구현 s3 업로드 기능 global로 수정 필요 * feat: 소속 단위 선거 기본 정보 등록용 엔티티 추가 * 온프레미스 환경 회원가입/로그인 코드 추가 (#9) * feat: refreshtoken 저장 엔터티 추가 * feat: 패스워드 암호화 빈 추가 * feat: 회원 가입 로직 구현 * feat: 로그인 필터 추가 * feat: 온프레미스 서버 환경 로그인 기능 추가 (#10) * feat: refreshtoken 저장 엔터티 추가 * feat: 패스워드 암호화 빈 추가 * feat: 회원 가입 로직 구현 * feat: 로그인 필터 추가 * feat: UserDetailsService, dto 구현 * feat: 서울 기준 시 설정 * feat: JWT 발급 코드 추가 * feat: JWTFilter 추가 * feat: cors 설정 추가 * feat: userdetailsservice 예외처리 추가 * fix: url length 추가 length가 255이상 인 경우 오류 가능 수정 * fix: dto추가 requestparam dto로 수정 * feat:선거기본정보 에러코드 추가 * fix: validation, lombok, dto 추가 validation, lombok, dto 추가 * docs: 회원가입 api 스웨거 작성 (#12) * feat: refreshtoken 저장 엔터티 추가 * feat: 패스워드 암호화 빈 추가 * feat: 회원 가입 로직 구현 * feat: 로그인 필터 추가 * feat: UserDetailsService, dto 구현 * feat: 서울 기준 시 설정 * feat: JWT 발급 코드 추가 * feat: JWTFilter 추가 * feat: cors 설정 추가 * feat: userdetailsservice 예외처리 추가 * docs: 회원가입 api 스웨거 작성 * feat: 필터기반 로그인 -> 수동 인증 로직으로 수정 (#13) * feat: refreshtoken 저장 엔터티 추가 * feat: 패스워드 암호화 빈 추가 * feat: 회원 가입 로직 구현 * feat: 로그인 필터 추가 * feat: UserDetailsService, dto 구현 * feat: 서울 기준 시 설정 * feat: JWT 발급 코드 추가 * feat: JWTFilter 추가 * feat: cors 설정 추가 * feat: userdetailsservice 예외처리 추가 * docs: 회원가입 api 스웨거 작성 * feat: 필터기반 로그인 -> 수동 인증 로직으로 수정 * feat: refreshToken 저장 추가 (#14) * feat: refreshtoken 저장 엔터티 추가 * feat: 패스워드 암호화 빈 추가 * feat: 회원 가입 로직 구현 * feat: 로그인 필터 추가 * feat: UserDetailsService, dto 구현 * feat: 서울 기준 시 설정 * feat: JWT 발급 코드 추가 * feat: JWTFilter 추가 * feat: cors 설정 추가 * feat: userdetailsservice 예외처리 추가 * docs: 회원가입 api 스웨거 작성 * feat: 필터기반 로그인 -> 수동 인증 로직으로 수정 * feat: refreshToken 저장 추가 * feat: 회원가입 요청한 유저의 목록 조회 기능 구현 (#16) * feat:s3 bean추가 * fix:import수정 * infra: cicd 연결 테스트 --------- Co-authored-by: ssm00 <[email protected]> Co-authored-by: ssm00 <[email protected]> Co-authored-by: ssm00 <[email protected]>
- Loading branch information
1 parent
f87fd05
commit a06f15f
Showing
35 changed files
with
1,052 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
name: Java CI with Gradle | ||
|
||
# 동작 조건 설정 : main 브랜치에 push 혹은 pull request가 발생할 경우 동작한다. | ||
on: | ||
push: | ||
branches: [ "main" ] | ||
|
||
permissions: | ||
contents: read | ||
|
||
jobs: | ||
# Spring Boot 애플리케이션을 빌드하여 도커허브에 푸시하는 과정 | ||
build-docker-image: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
# 1. Java 21 세팅 | ||
- name: Set up JDK 21 | ||
uses: actions/setup-java@v3 | ||
with: | ||
java-version: '21' | ||
distribution: 'temurin' | ||
|
||
## create application-database.yaml | ||
- name: create application.properties file | ||
run: | | ||
mkdir ./src/main/resources | ||
touch ./src/main/resources/application.yml | ||
echo "${{ secrets.APPLICATION_YML }}" >> src/main/resources/application.yml | ||
## create firebase-service-key.json | ||
- name: create firebase_service_key.json file | ||
run: | | ||
mkdir ./src/main/resources/firebase | ||
touch ./src/main/resources/firebase/firebase_service_key.json | ||
echo "${{ secrets.FIREBASE_SERVICE_KEY }}" > src/main/resources/firebase/firebase_service_key.json | ||
- name: Grant execute permission for gradlew | ||
run: chmod +x ./gradlew | ||
shell: bash | ||
|
||
# 2. Spring Boot 애플리케이션 빌드 | ||
- name: Build with Gradle | ||
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1 | ||
with: | ||
arguments: clean bootJar | ||
|
||
# 3. Docker 이미지 빌드 | ||
- name: docker image build | ||
run: docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/studentvote . | ||
|
||
# 4. DockerHub 로그인 | ||
- name: docker login | ||
uses: docker/login-action@v2 | ||
with: | ||
username: ${{ secrets.DOCKERHUB_USERNAME }} | ||
password: ${{ secrets.DOCKERHUB_PASSWORD }} | ||
|
||
# 5. Docker Hub 이미지 푸시 | ||
- name: docker Hub push | ||
run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/studentvote | ||
|
||
run-docker-image-on-ec2: | ||
needs: build-docker-image | ||
runs-on: self-hosted | ||
|
||
steps: | ||
# 1. 최신 이미지를 풀받습니다 | ||
- name: docker pull | ||
run: sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/studentvote | ||
|
||
# 2. 기존의 컨테이너를 중지시킵니다 | ||
- name: docker stop container | ||
run: sudo docker stop $(sudo docker ps -q) 2>/dev/null || true | ||
|
||
# 3. 최신 이미지를 컨테이너화하여 실행시킵니다 | ||
- name: docker run new container | ||
run: sudo docker run --name studentvote --rm -d -p 8080:8080 ${{ secrets.DOCKERHUB_USERNAME }}/studentvote | ||
|
||
# 4. 미사용 이미지를 정리합니다 | ||
- name: delete old docker image | ||
run: sudo docker system prune -f |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
FROM openjdk:21 | ||
|
||
ARG JAR_FILE=build/libs/*.jar | ||
|
||
COPY ${JAR_FILE} app.jar | ||
|
||
EXPOSE 8080 | ||
|
||
ENTRYPOINT ["java", "-jar", "/app.jar"] |
50 changes: 50 additions & 0 deletions
50
src/main/java/com/studentvote/domain/admin/application/AdminService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package com.studentvote.domain.admin.application; | ||
|
||
import com.studentvote.domain.admin.dto.response.AccountsWaitingForApprovalResponse; | ||
import com.studentvote.domain.auth.dto.response.CustomUserDetails; | ||
import com.studentvote.domain.user.domain.ApprovalStatus; | ||
import com.studentvote.domain.user.domain.User; | ||
import com.studentvote.domain.user.domain.repository.UserRepository; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Optional; | ||
import java.util.stream.Collectors; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
@Transactional(readOnly = true) | ||
@RequiredArgsConstructor | ||
public class AdminService { | ||
|
||
private static final String MASTER_USERNAME = "ADMIN"; | ||
|
||
private final UserRepository userRepository; | ||
|
||
public List<AccountsWaitingForApprovalResponse> getAccountsWaitingForApproval(CustomUserDetails userDetails) { | ||
|
||
System.out.println("userDetails.getUsername() = " + userDetails.getUsername()); | ||
if (!userDetails.getUsername().equals(MASTER_USERNAME)) { | ||
throw new IllegalArgumentException("접근 권한이 없습니다."); | ||
} | ||
|
||
Optional<List<User>> allByApprovalStatus = userRepository.findAllByApprovalStatus(ApprovalStatus.PENDING); | ||
|
||
if (!allByApprovalStatus.isPresent()) { | ||
return new ArrayList<>(); | ||
} | ||
|
||
List<AccountsWaitingForApprovalResponse> accountsWaitingForApprovalResponses = allByApprovalStatus.get() | ||
.stream() | ||
.map(user -> new AccountsWaitingForApprovalResponse( | ||
user.getId(), | ||
user.getUsername(), | ||
"", | ||
user.getCreatedAt() | ||
)) | ||
.collect(Collectors.toList()); | ||
|
||
return accountsWaitingForApprovalResponses; | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
...in/java/com/studentvote/domain/admin/dto/response/AccountsWaitingForApprovalResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.studentvote.domain.admin.dto.response; | ||
|
||
import java.time.LocalDateTime; | ||
|
||
public record AccountsWaitingForApprovalResponse( | ||
Long userId, | ||
String username, | ||
String department, | ||
LocalDateTime requestDate | ||
) { | ||
} |
29 changes: 29 additions & 0 deletions
29
src/main/java/com/studentvote/domain/admin/presentation/AdminController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.studentvote.domain.admin.presentation; | ||
|
||
import com.studentvote.domain.admin.application.AdminService; | ||
import com.studentvote.domain.auth.dto.response.CustomUserDetails; | ||
import com.studentvote.global.payload.ResponseCustom; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.security.core.annotation.AuthenticationPrincipal; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@Tag(name = "Admin", description = "Admin API") | ||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/api/v1/admin") | ||
public class AdminController { | ||
|
||
private final AdminService adminService; | ||
|
||
@Operation(summary = "가입 승인 대기 계정 조회", description = "가입 승인 대기 중인 계정 목록을 마스터 계정이 조회합니다.") | ||
@GetMapping | ||
public ResponseCustom<?> getAccountsWaitingForApproval( | ||
@AuthenticationPrincipal CustomUserDetails userDetails | ||
) { | ||
return ResponseCustom.OK(adminService.getAccountsWaitingForApproval(userDetails)); | ||
} | ||
} |
96 changes: 96 additions & 0 deletions
96
src/main/java/com/studentvote/domain/auth/application/AuthService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package com.studentvote.domain.auth.application; | ||
|
||
import com.studentvote.domain.auth.domain.Token; | ||
import com.studentvote.domain.auth.domain.repository.TokenRepository; | ||
import com.studentvote.domain.auth.dto.request.SignInRequest; | ||
import com.studentvote.domain.auth.dto.request.SignUpRequest; | ||
import com.studentvote.domain.auth.dto.response.SignInResponse; | ||
import com.studentvote.domain.auth.exception.AlreadyExistIdException; | ||
import com.studentvote.domain.auth.exception.EmailNotFoundException; | ||
import com.studentvote.domain.auth.exception.InvalidPasswordException; | ||
import com.studentvote.domain.user.domain.Role; | ||
import com.studentvote.domain.user.domain.User; | ||
import com.studentvote.domain.user.domain.repository.UserRepository; | ||
import com.studentvote.global.config.security.jwt.JWTUtil; | ||
import com.studentvote.global.payload.Message; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.security.authentication.AuthenticationManager; | ||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | ||
import org.springframework.security.core.Authentication; | ||
import org.springframework.security.core.context.SecurityContextHolder; | ||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@RequiredArgsConstructor | ||
@Service | ||
@Transactional(readOnly = true) | ||
public class AuthService { | ||
|
||
private final UserRepository userRepository; | ||
private final BCryptPasswordEncoder bCryptPasswordEncoder; | ||
private final BCryptPasswordEncoder passwordEncoder; | ||
private final AuthenticationManager authenticationManager; | ||
private final TokenRepository tokenRepository; | ||
|
||
private final JWTUtil jwtUtil; | ||
|
||
@Transactional | ||
public Message signUp(SignUpRequest signUpRequest) { | ||
String email = signUpRequest.email(); | ||
String password = signUpRequest.password(); | ||
String name = signUpRequest.name(); | ||
|
||
Boolean isExist = userRepository.existsByEmail(email); | ||
|
||
if (isExist) { | ||
throw new AlreadyExistIdException(); | ||
} | ||
|
||
User user = User.of(email, bCryptPasswordEncoder.encode(password), name); | ||
|
||
userRepository.save(user); | ||
|
||
return Message | ||
.builder() | ||
.message("회원가입이 완료되었습니다.") | ||
.build(); | ||
} | ||
|
||
@Transactional | ||
public SignInResponse signIn(SignInRequest signInRequest) { | ||
String email = signInRequest.email(); | ||
String password = signInRequest.password(); | ||
|
||
User user = userRepository.findByEmail(email) | ||
.orElseThrow(() -> new EmailNotFoundException()); | ||
|
||
if (!passwordEncoder.matches(password, user.getPassword())) { | ||
throw new InvalidPasswordException(); | ||
} | ||
|
||
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken( | ||
email, password, null); | ||
|
||
Authentication authenticate = authenticationManager.authenticate(authToken); | ||
|
||
SecurityContextHolder.getContext().setAuthentication(authenticate); | ||
|
||
Role role = user.getRole(); | ||
|
||
String accessToken = jwtUtil.createJwt(email, role.toString(), 36000000000L); | ||
String refreshToken = jwtUtil.createJwt(email, role.toString(), 360000000000L); | ||
|
||
tokenRepository.save(Token.builder().email(email).refreshToken(refreshToken).build()); | ||
|
||
SignInResponse signInResponse = SignInResponse | ||
.builder() | ||
.accessToken(accessToken) | ||
.refreshToken(refreshToken) | ||
.tokenType("Bearer") | ||
.role(role) | ||
.build(); | ||
|
||
return signInResponse; | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
src/main/java/com/studentvote/domain/auth/application/CustomUserDetailsService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package com.studentvote.domain.auth.application; | ||
|
||
import com.studentvote.domain.auth.dto.response.CustomUserDetails; | ||
import com.studentvote.domain.auth.exception.EmailNotFoundException; | ||
import com.studentvote.domain.user.domain.User; | ||
import com.studentvote.domain.user.domain.repository.UserRepository; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.security.core.userdetails.UserDetails; | ||
import org.springframework.security.core.userdetails.UserDetailsService; | ||
import org.springframework.security.core.userdetails.UsernameNotFoundException; | ||
import org.springframework.stereotype.Service; | ||
|
||
@RequiredArgsConstructor | ||
@Service | ||
public class CustomUserDetailsService implements UserDetailsService { | ||
|
||
private final UserRepository userRepository; | ||
|
||
@Override | ||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { | ||
User user = userRepository.findByEmail(username) | ||
.orElseThrow(() -> new EmailNotFoundException()); | ||
|
||
|
||
if (user != null) { | ||
return new CustomUserDetails(user); | ||
} | ||
|
||
throw new UsernameNotFoundException(username); | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
src/main/java/com/studentvote/domain/auth/domain/Token.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package com.studentvote.domain.auth.domain; | ||
|
||
import com.studentvote.domain.common.BaseEntity; | ||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.Table; | ||
import lombok.AccessLevel; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Table(name = "token") | ||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@Entity | ||
public class Token extends BaseEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
@Column(name = "id", nullable = false) | ||
private Long id; | ||
|
||
@Column(name = "email", nullable = false) | ||
private String email; | ||
|
||
@Column(name = "refresh_token", nullable = false) | ||
private String refreshToken; | ||
|
||
public Token updateRefreshToken(String refreshToken) { | ||
this.refreshToken = refreshToken; | ||
return this; | ||
} | ||
|
||
@Builder | ||
public Token(String email, String refreshToken) { | ||
this.email = email; | ||
this.refreshToken = refreshToken; | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
src/main/java/com/studentvote/domain/auth/domain/repository/TokenRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.studentvote.domain.auth.domain.repository; | ||
|
||
import com.studentvote.domain.auth.domain.Token; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface TokenRepository extends JpaRepository<Token, Long> { | ||
} |
7 changes: 7 additions & 0 deletions
7
src/main/java/com/studentvote/domain/auth/dto/request/SignInRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.studentvote.domain.auth.dto.request; | ||
|
||
public record SignInRequest( | ||
String email, | ||
String password | ||
) { | ||
} |
8 changes: 8 additions & 0 deletions
8
src/main/java/com/studentvote/domain/auth/dto/request/SignUpRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.studentvote.domain.auth.dto.request; | ||
|
||
public record SignUpRequest( | ||
String email, | ||
String password, | ||
String name | ||
) { | ||
} |
Oops, something went wrong.