Skip to content

Commit

Permalink
feat: 회원 Authorization Grant와 페이지 반환 기능 구현 (#18)
Browse files Browse the repository at this point in the history
* feat: 회원 엔티티 생성 및 테스트코드 추가

* feat: 카카오 OAuth 환경변수 추가 및 클래스 바인딩

* feat: authorization code를 받기 위한 queryString generator 추가

* feat: Authorization code의 parameter 만드는 로직 분리 및 테스트 코드 추가

* feat: 회원 가입/로그인 요청 api 및 소셜 로그인 페이지 반환

* refactor: member관련 클래스 네이밍과 폴더 위치 변경

* refactor: 로그인 페이지 요청 방식 Resttemplate -> response (redirect)하도록 변경

* style: 코드 포맷 재적용 및 사용하지 않는 클래스 삭제

* chore: config 파일 업데이트

* refactor: 테스트 코드 추가 및 코드 포맷 재적용

* refactor: 사용하지 않는 코드 제거

* refactor: CRLF -> LF로 변경

* fix: config 커밋, config 최근 커밋으로 변경

* feat: 테스트 코드 추가 및 패키지 구조 변경

* refactor: revert merge

* fix: merge confilt해결 및 예외처리 추가

* test: oauth properties가 없을 때의 테스트코드 추가

* feat: 코드리뷰에 따른 기능 분리 및 테스트 코드 변경

* fix: 테스트코드 관련 code smell 제거
  • Loading branch information
parksey authored Oct 31, 2023
1 parent 4e1f0cc commit 136beea
Show file tree
Hide file tree
Showing 19 changed files with 570 additions and 3 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,4 @@ gradle-app.setting
logs/
application-*.yml
src/main/resources/config
!application-test.yml
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ dependencies {

// H2
implementation 'com.h2database:h2'

// Configuration Binding
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
}

tasks.named('test') {
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/moabam/MoabamServerApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;

@ConfigurationPropertiesScan
@SpringBootApplication
public class MoabamServerApplication {

public static void main(String[] args) {
SpringApplication.run(MoabamServerApplication.class, args);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.moabam.api.application;

import static com.moabam.global.common.util.OAuthParameterNames.*;

import java.io.IOException;

import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;

import com.moabam.api.dto.AuthorizationCodeRequest;
import com.moabam.api.mapper.OAuthMapper;
import com.moabam.global.common.util.GlobalConstant;
import com.moabam.global.config.OAuthConfig;
import com.moabam.global.error.exception.BadRequestException;
import com.moabam.global.error.model.ErrorMessage;

import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class AuthenticationService {

private final OAuthConfig oAuthConfig;

private String getAuthorizaionCodeUri() {
AuthorizationCodeRequest authorizationCodeRequest = OAuthMapper.toAuthorizationCodeRequest(oAuthConfig);
return generateQueryParamsWith(authorizationCodeRequest);
}

private String generateQueryParamsWith(AuthorizationCodeRequest authorizationCodeRequest) {
UriComponentsBuilder authorizationCodeUri = UriComponentsBuilder
.fromUriString(oAuthConfig.provider().authorizationUri())
.queryParam(RESPONSE_TYPE, CODE)
.queryParam(CLIENT_ID, authorizationCodeRequest.clientId())
.queryParam(REDIRECT_URI, authorizationCodeRequest.redirectUri());

if (!authorizationCodeRequest.scope().isEmpty()) {
String scopes = String.join(GlobalConstant.COMMA, authorizationCodeRequest.scope());
authorizationCodeUri.queryParam(SCOPE, scopes);
}

return authorizationCodeUri.toUriString();
}

public void redirectToLoginPage(HttpServletResponse httpServletResponse) {
String authorizationCodeUri = getAuthorizaionCodeUri();

try {
httpServletResponse.setContentType(MediaType.APPLICATION_FORM_URLENCODED + GlobalConstant.CHARSET_UTF_8);
httpServletResponse.sendRedirect(authorizationCodeUri);
} catch (IOException e) {
throw new BadRequestException(ErrorMessage.REQUEST_FAILD);
}
}
}
96 changes: 96 additions & 0 deletions src/main/java/com/moabam/api/domain/Member.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package com.moabam.api.domain;

import static java.util.Objects.*;

import java.time.LocalDateTime;

import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;

import com.moabam.global.common.entity.BaseTimeEntity;
import com.moabam.global.common.util.BaseImageUrl;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
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;

@Getter
@Entity
@Table(name = "member")
@SQLDelete(sql = "UPDATE member SET deleted_at = CURRENT_TIMESTAMP where participant_id = ?")
@Where(clause = "deleted_at IS NOT NULL")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member extends BaseTimeEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;

@Column(name = "social_id", nullable = false, unique = true)
private String socialId;

@Column(name = "nickname", nullable = false, unique = true)
private String nickname;

@Column(name = "intro", length = 30)
private String intro;

@Column(name = "profile_image", nullable = false)
private String profileImage;

@Column(name = "total_certify_count", nullable = false)
@ColumnDefault("0")
private long totalCertifyCount;

@Column(name = "report_count", nullable = false)
@ColumnDefault("0")
private int reportCount;

@Column(name = "current_night_count", nullable = false)
@ColumnDefault("0")
private int currentNightCount;

@Column(name = "current_morning_count", nullable = false)
@ColumnDefault("0")
private int currentMorningCount;

@Column(name = "morning_bug", nullable = false)
@ColumnDefault("0")
private int morningBug;

@Column(name = "night_bug", nullable = false)
@ColumnDefault("0")
private int nightBug;

@Column(name = "golden_bug", nullable = false)
@ColumnDefault("0")
private int goldenBug;

@Enumerated(EnumType.STRING)
@Column(name = "role", nullable = false)
@ColumnDefault("USER")
private Role role;

@Column(name = "deleted_at")
private LocalDateTime deletedAt;

@Builder
private Member(Long id, String socialId, String nickname, String profileImage) {
this.id = id;
this.socialId = requireNonNull(socialId);
this.nickname = requireNonNull(nickname);
this.profileImage = requireNonNullElse(profileImage, BaseImageUrl.PROFILE_URL);
this.role = Role.USER;
}
}
8 changes: 8 additions & 0 deletions src/main/java/com/moabam/api/domain/Role.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.moabam.api.domain;

public enum Role {

USER,
BLACK,
ADMIN
}
26 changes: 26 additions & 0 deletions src/main/java/com/moabam/api/dto/AuthorizationCodeRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.moabam.api.dto;

import static java.util.Objects.*;

import java.util.List;

import lombok.Builder;

public record AuthorizationCodeRequest(
String clientId,
String redirectUri,
String responseType,
List<String> scope,
String state
) {

@Builder
public AuthorizationCodeRequest(String clientId, String redirectUri, String responseType, List<String> scope,
String state) {
this.clientId = requireNonNull(clientId);
this.redirectUri = requireNonNull(redirectUri);
this.responseType = responseType;
this.scope = scope;
this.state = state;
}
}
19 changes: 19 additions & 0 deletions src/main/java/com/moabam/api/mapper/OAuthMapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.moabam.api.mapper;

import com.moabam.api.dto.AuthorizationCodeRequest;
import com.moabam.global.config.OAuthConfig;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class OAuthMapper {

public static AuthorizationCodeRequest toAuthorizationCodeRequest(OAuthConfig oAuthConfig) {
return AuthorizationCodeRequest.builder()
.clientId(oAuthConfig.client().clientId())
.redirectUri(oAuthConfig.provider().redirectUri())
.scope(oAuthConfig.client().scope())
.build();
}
}
23 changes: 23 additions & 0 deletions src/main/java/com/moabam/api/presentation/MemberController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.moabam.api.presentation;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.moabam.api.application.AuthenticationService;

import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;

@RestController
@RequestMapping("/members")
@RequiredArgsConstructor
public class MemberController {

private final AuthenticationService authenticationService;

@GetMapping
public void socialLogin(HttpServletResponse httpServletResponse) {
authenticationService.redirectToLoginPage(httpServletResponse);
}
}
10 changes: 10 additions & 0 deletions src/main/java/com/moabam/global/common/util/BaseImageUrl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.moabam.global.common.util;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BaseImageUrl {

public static final String PROFILE_URL = "/profile/baseUrl";
}
11 changes: 11 additions & 0 deletions src/main/java/com/moabam/global/common/util/GlobalConstant.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.moabam.global.common.util;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class GlobalConstant {

public static final String COMMA = ",";
public static final String CHARSET_UTF_8 = ";charset=UTF-8";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.moabam.global.common.util;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class OAuthParameterNames {

public static final String RESPONSE_TYPE = "response_type";
public static final String CODE = "code";
public static final String CLIENT_ID = "client_id";
public static final String REDIRECT_URI = "redirect_uri";
public static final String SCOPE = "scope";
}
28 changes: 28 additions & 0 deletions src/main/java/com/moabam/global/config/OAuthConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.moabam.global.config;

import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "oauth2")
public record OAuthConfig(
Provider provider,
Client client
) {

public record Client(
String provider,
String clientId,
String authorizationGrantType,
List<String> scope
) {

}

public record Provider(
String authorizationUri,
String redirectUri
) {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
@RequiredArgsConstructor
public enum ErrorMessage {

INVALID_REQUEST_FIELD("올바른 요청 정보가 아닙니다.");
INVALID_REQUEST_FIELD("올바른 요청 정보가 아닙니다."),
LOGIN_FAILED("로그인에 실패했습니다."),
REQUEST_FAILD("네트우크 접근 실패입니다.");

private final String message;
}
2 changes: 1 addition & 1 deletion src/main/resources/config
Loading

0 comments on commit 136beea

Please sign in to comment.