-
Notifications
You must be signed in to change notification settings - Fork 0
feat: oauth2 로그인 #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bde5bb8
0eed631
8ed4711
413afa2
8471148
ca98821
82a66d3
c31b69c
9559084
4491559
70fd898
f5ae2bb
78a4e2f
67d1930
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -42,4 +42,5 @@ secrets.yml | |
|
|
||
| .idea | ||
| .env | ||
| src/test/resources/application.yml | ||
| src/test/resources/application.yml | ||
| /uploads | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| .PHONY: all build down re | ||
|
|
||
| all: build copy up | ||
|
|
||
| build: | ||
| @./gradlew clean build | ||
|
|
||
| copy: | ||
| @cp ./build/libs/backend-0.0.1-SNAPSHOT.jar ./app.jar | ||
|
|
||
| up: | ||
| @docker compose up --build -d | ||
|
|
||
| down: | ||
| @docker compose down | ||
|
|
||
| re: down up | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| services: | ||
| db: | ||
| image: postgres:15 | ||
| restart: unless-stopped | ||
| container_name: runners_db | ||
| env_file: .env | ||
| ports: | ||
| - "5432:5432" | ||
| volumes: | ||
| - runners_db:/var/lib/postgresql/data | ||
|
|
||
| app: | ||
| image: openjdk:17-slim | ||
| container_name: runners_app | ||
| env_file: .env | ||
| ports: | ||
| - "8080:8080" | ||
| volumes: | ||
| - ./app.jar:/app/app.jar | ||
| - ./uploads:/app/uploads | ||
| depends_on: | ||
| - db | ||
| restart: unless-stopped | ||
| command: [ "java", "-jar", "/app/app.jar" ] | ||
|
|
||
| volumes: | ||
| runners_db: | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| package run.backend.domain.auth.controller; | ||
|
|
||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.web.bind.annotation.PathVariable; | ||
| import org.springframework.web.bind.annotation.PostMapping; | ||
| import org.springframework.web.bind.annotation.RequestBody; | ||
| import org.springframework.web.bind.annotation.RequestHeader; | ||
| import org.springframework.web.bind.annotation.RequestMapping; | ||
| import org.springframework.web.bind.annotation.RequestPart; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
| import org.springframework.web.multipart.MultipartFile; | ||
| import run.backend.domain.auth.dto.request.CodeRequest; | ||
| import run.backend.domain.auth.dto.request.SignupRequest; | ||
| import run.backend.domain.auth.dto.response.SignupResponse; | ||
| import run.backend.domain.auth.dto.response.TokenResponse; | ||
| import run.backend.domain.auth.service.AuthService; | ||
| import run.backend.global.common.response.CommonResponse; | ||
|
|
||
| @RestController | ||
| @RequestMapping("/api/v1/auth") | ||
| @RequiredArgsConstructor | ||
| public class AuthController { | ||
|
|
||
| private final AuthService authService; | ||
|
|
||
| @PostMapping("/{provider}") | ||
| public ResponseEntity<CommonResponse<SignupResponse>> socialLogin( | ||
| @PathVariable String provider, @RequestBody CodeRequest codeRequest) { | ||
|
|
||
| SignupResponse response = authService.socialLogin(provider, codeRequest.code()); | ||
|
|
||
| return ResponseEntity.ok(new CommonResponse<>("소셜 로그인 요청에 성공했습니다.", response)); | ||
| } | ||
|
|
||
| @PostMapping("/signup") | ||
| public ResponseEntity<CommonResponse<TokenResponse>> signup( | ||
| @RequestPart("signupRequest") SignupRequest signupRequest, | ||
| @RequestPart(value = "profileImage", required = false) MultipartFile profileImage) { | ||
|
|
||
| TokenResponse response = authService.completeSignup(signupRequest, profileImage); | ||
|
|
||
| return ResponseEntity.ok(new CommonResponse<>("회원가입이 완료되었습니다.", response)); | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. accessToken 만료 되었을 때 재발급하는 api 가 없어서 이것만 있으면 될거 같아요!!
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 재발급 api 까먹,, RTR 방식 찾아보고 수정할게요!! |
||
|
|
||
| @PostMapping("/refresh") | ||
| public ResponseEntity<CommonResponse<TokenResponse>> refresh( | ||
| @RequestHeader("Authorization") String authorizationHeader) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 오 대박 이렇게 가지고 올 수 있는거 처음 알았어요 |
||
|
|
||
| TokenResponse response = authService.refreshTokens(authorizationHeader); | ||
|
|
||
| return ResponseEntity.ok(new CommonResponse<>("토큰이 갱신되었습니다.", response)); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package run.backend.domain.auth.dto.request; | ||
|
|
||
| public record CodeRequest(String code) { | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package run.backend.domain.auth.dto.request; | ||
|
|
||
| import run.backend.domain.member.enums.Gender; | ||
|
|
||
| public record SignupRequest(String signupToken, String nickname, Gender gender, int age) { | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package run.backend.domain.auth.dto.response; | ||
|
|
||
| public record SignupResponse(boolean isNewUser, String signupToken, String email, String name, | ||
| String provider, TokenResponse tokens) { | ||
|
|
||
| public static SignupResponse forExistingUser(TokenResponse tokens) { | ||
| //기존 회원은 토큰만 리턴 | ||
| return new SignupResponse(false, null, null, null, null, tokens); | ||
| } | ||
|
|
||
| public static SignupResponse forNewUser(String signupToken, String email, String name, | ||
| String provider) { | ||
| //신규 회원은 회원가입을 위한 정보와 임시 토큰 리턴 | ||
| return new SignupResponse(true, signupToken, email, name, provider, null); | ||
| } | ||
| } | ||
|
Comment on lines
+3
to
+16
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. null이 많긴 하지만 좋은거 같아요!! |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package run.backend.domain.auth.dto.response; | ||
|
|
||
| public record TokenResponse(String accessToken, String refreshToken) { | ||
|
|
||
| } | ||
|
Comment on lines
+3
to
+5
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 토큰 헤더에 안 넣고 body에 담아서 보내주는게 더 나을까요??
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 앱은 어떻게 처리해야 될 지 몰라서 우선 body에 담았는데 한번 찾아볼게요!! |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| package run.backend.domain.auth.entity; | ||
|
|
||
| import jakarta.persistence.Column; | ||
| import jakarta.persistence.Entity; | ||
| import jakarta.persistence.FetchType; | ||
| import jakarta.persistence.GeneratedValue; | ||
| import jakarta.persistence.GenerationType; | ||
| import jakarta.persistence.Id; | ||
| import jakarta.persistence.JoinColumn; | ||
| import jakarta.persistence.ManyToOne; | ||
| import jakarta.persistence.Table; | ||
| import java.time.LocalDateTime; | ||
| import lombok.AccessLevel; | ||
| import lombok.Builder; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
| import run.backend.domain.member.entity.Member; | ||
|
|
||
| @Entity | ||
| @Table(name = "refresh_tokens") | ||
| @Getter | ||
| @NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
| public class RefreshToken { | ||
|
|
||
| @Id | ||
| @GeneratedValue(strategy = GenerationType.IDENTITY) | ||
| private Long id; | ||
|
|
||
| @Column(nullable = false, unique = true) | ||
| private String token; | ||
|
|
||
| @ManyToOne(fetch = FetchType.LAZY) | ||
| @JoinColumn(name = "member_id", nullable = false) | ||
| private Member member; | ||
|
|
||
| @Column(nullable = false) | ||
| private LocalDateTime expiresAt; | ||
|
|
||
| @Builder | ||
| public RefreshToken(String token, Member member, LocalDateTime expiresAt) { | ||
| this.token = token; | ||
| this.member = member; | ||
| this.expiresAt = expiresAt; | ||
| } | ||
|
|
||
| public boolean isExpired() { | ||
| return LocalDateTime.now().isAfter(expiresAt); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package run.backend.domain.auth.repository; | ||
|
|
||
| import java.util.Optional; | ||
| import org.springframework.data.jpa.repository.JpaRepository; | ||
| import org.springframework.data.jpa.repository.Modifying; | ||
| import org.springframework.data.jpa.repository.Query; | ||
| import org.springframework.data.repository.query.Param; | ||
| import run.backend.domain.auth.entity.RefreshToken; | ||
| import run.backend.domain.member.entity.Member; | ||
|
|
||
| public interface RefreshTokenRepository extends JpaRepository<RefreshToken, Long> { | ||
|
|
||
| Optional<RefreshToken> findByToken(String token); | ||
|
|
||
| @Modifying | ||
| @Query("DELETE FROM RefreshToken rt WHERE rt.member = :member") | ||
| void deleteByMember(@Param("member") Member member); | ||
|
|
||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
혹시 makefile 어디에 사용되는건가요??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이거 빌드하고 docker compose 돌리는거 귀찮아서 만들었어요😅