Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ configurations {

repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
}

dependencies {
Expand Down Expand Up @@ -69,6 +70,9 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-batch'
testImplementation 'org.springframework.batch:spring-batch-test'

//portOne
implementation 'com.github.iamport:iamport-rest-client-java:0.1.6'

compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.tenten.studybadge.account.controller;

import com.tenten.studybadge.account.dto.AccountRequest;
import com.tenten.studybadge.account.service.AccountService;
import com.tenten.studybadge.common.security.LoginUser;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
public class AccountController {

private final AccountService accountService;

@Operation(summary = "계좌 인증", description = "회원정보 수정 시 계좌인증(예금주조회)")
@Parameter(name = "BankCode", description = "은행코드")
@Parameter(name = "BankNum", description = "계좌번호")
@PostMapping("/api/cert/account")
public ResponseEntity<Void> certAccount(@LoginUser Long memberId,
@RequestBody AccountRequest accountRequest) {

accountService.certAccount(memberId, accountRequest);

return ResponseEntity.status(HttpStatus.OK).build();
}

@Operation(summary = "계좌 인증", description = "회원가입 시 계좌인증(예금주조회)")
@Parameter(name = "bankCode", description = "은행코드")
@Parameter(name = "bankNum", description = "계좌번호")
@Parameter(name = "name", description = "회원가입 시 입력하는 이름")
@GetMapping("/api/cert/sign-up")
public ResponseEntity<Void> certSignUp(@RequestParam String bankCode,
@RequestParam String bankNum,
@RequestParam String name) {

accountService.certSignUp(bankCode, bankNum, name);

return ResponseEntity.status(HttpStatus.OK).build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.tenten.studybadge.account.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class AccountRequest {

private String bankCode;

private String bankNum;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.tenten.studybadge.account.dto;

import lombok.*;

@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class AccountResponse {

private String accountHolder;

public static AccountResponse getHolder(String response) {

return AccountResponse.builder()
.accountHolder(response)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package com.tenten.studybadge.account.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.siot.IamportRestClient.IamportClient;
import com.tenten.studybadge.account.dto.AccountRequest;
import com.tenten.studybadge.account.dto.AccountResponse;
import com.tenten.studybadge.common.exception.account.NotMatchAccountHolder;
import com.tenten.studybadge.common.exception.member.NotFoundMemberException;
import com.tenten.studybadge.member.domain.entity.Member;
import com.tenten.studybadge.member.domain.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;

import java.util.Map;

import static com.tenten.studybadge.common.constant.AccountConstant.*;


@Service
@RequiredArgsConstructor
public class AccountService {

@Value("${portone.api.key}")
private String impKey;

@Value("${portone.api.secret}")
private String impSecret;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yml파일에 어떤 값을 넣어야하는지 슬랙으로 공유해주시면 감사하겠습니다~

private IamportClient iamportClient;

private final MemberRepository memberRepository;
private final ObjectMapper objectMapper;

public AccountResponse getAccountHolder(String bankCode, String bankNum) {

iamportClient = new IamportClient(impKey, impSecret);

WebClient webClient = WebClient.builder()
.baseUrl(IamportClient.API_URL)
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.defaultHeader(HttpHeaders.AUTHORIZATION, issueToken())
.build();

String response = webClient.get()
.uri(uriBuilder -> uriBuilder
.path(PATH)
.queryParam(BANK_CODE,bankCode)
.queryParam(BANK_NUM, bankNum)
.build())
.retrieve()
.bodyToMono(String.class)
.block();

String decode = decodeUnicode(response);

return AccountResponse.getHolder(decode);
}

public void certAccount(Long memberId, AccountRequest accountRequest) {

Member member = memberRepository.findById(memberId)
.orElseThrow(NotFoundMemberException::new);

AccountResponse accountResponse = getAccountHolder
(accountRequest.getBankCode(),
accountRequest.getBankNum());

if (accountResponse.getAccountHolder().equals(member.getName())) {

Member updatedMember = member.toBuilder()
.isAccountCert(true)
.build();

memberRepository.save(updatedMember);

} else {

throw new NotMatchAccountHolder();
}
}

public void certSignUp(String bankCode, String bankNum, String name) {

AccountResponse accountResponse = getAccountHolder(bankCode, bankNum);

if ( !accountResponse.getAccountHolder().equals(name)) {

throw new NotMatchAccountHolder();
}
}

private String decodeUnicode(String response) {
try {
Map<String, Object> responseMap = objectMapper.readValue(response, Map.class);

Map<String, Object> responseDetails = (Map<String, Object>) responseMap.get(RESPONSE);

return (String) responseDetails.get(BANK_HOLDER);

} catch (Exception e) {
e.printStackTrace();
return null;
}
}

public String issueToken() {

return iamportClient.getAuth().getResponse().getToken();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests( requests -> requests
.requestMatchers("/api/members/sign-up", "/api/members/auth/**", "/h2-console/**", "/swagger-ui/**", "/v3/api-docs/**", "/api/members/login/**", "/error", "/health-check").permitAll()
.requestMatchers("/api/token/oauth2/**", "/favicon.ico", "/oauth2/**", "/api/payments/success/**", "/api/payments/cancel/**", "/api/members/password/**", "/api/members/resend/**").permitAll()
.requestMatchers("/api/token/oauth2/**", "/favicon.ico", "/oauth2/**", "/api/payments/success/**", "/api/payments/cancel/**", "/api/members/password/**", "/api/members/resend/**", "/api/cert/sign-up/**").permitAll()
.requestMatchers(HttpMethod.GET, "/api/study-channels", "/api/study-channels/{studyChannelId:\\d+}").permitAll()
.requestMatchers("/api/members/logout", "api/study-channels/*/places", "/api/study-channels/**", "/api/token/re-issue"
, "/api/members/my-info", "/api/members/my-info/update", "/api/payments/**", "/api/participation/**",
"/api/study-channels/*/single-schedules/**", "/api/study-channels/*/repeat-schedules/**",
"/api/study-channels/*/schedules/**", "/api/points/my-point/**", "/api/members/my-apply/**", "/api/notifications/**", "/api/members/my-study", "/api/members/withdrawal").hasRole("USER"))
"/api/study-channels/*/schedules/**", "/api/points/my-point/**", "/api/members/my-apply/**", "/api/notifications/**", "/api/members/my-study", "/api/members/withdrawal", "/api/cert/account/**").hasRole("USER"))
.exceptionHandling(exception -> exception.authenticationEntryPoint(authenticationEntryPoint))

.cors(cors -> new CorsConfig())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.tenten.studybadge.common.constant;

public class AccountConstant {

public static final String RESPONSE = "response";
public static final String BANK_HOLDER = "bank_holder";

public static final String PATH = "/vbanks/holder";

public static final String BANK_CODE = "bank_code";
public static final String BANK_NUM = "bank_num";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.tenten.studybadge.common.exception.account;

import com.tenten.studybadge.common.exception.basic.AbstractException;
import org.springframework.http.HttpStatus;

import static org.springframework.http.HttpStatus.BAD_REQUEST;

public class BeforeCertAccountException extends AbstractException {

private static final String ERROR_CODE = "BEFORE_CERT_ACCOUNT_EXCEPTION";
private static final String ERROR_MESSAGE = "계좌 인증이 완료되지 않았습니다.";

@Override
public HttpStatus getHttpStatus() {
return BAD_REQUEST;
}

@Override
public String getErrorCode() {
return ERROR_CODE;
}

@Override
public String getMessage() {
return ERROR_MESSAGE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.tenten.studybadge.common.exception.account;

import com.tenten.studybadge.common.exception.basic.AbstractException;
import org.springframework.http.HttpStatus;

import static org.springframework.http.HttpStatus.BAD_REQUEST;

public class NotMatchAccountHolder extends AbstractException {

private static final String ERROR_CODE = "NOT_MATCH_ACCOUNT_HOLDER";
private static final String ERROR_MESSAGE = "예금주와 회원의 이름이 일치하지 않습니다.";

@Override
public HttpStatus getHttpStatus() {
return BAD_REQUEST;
}

@Override
public String getErrorCode() {
return ERROR_CODE;
}

@Override
public String getMessage() {
return ERROR_MESSAGE;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public class Member extends BaseEntity {

private String accountBank;

private Boolean isAccountCert;

private String imgUrl;

private Boolean isAuth;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public class MemberResponse {

private String accountBank;

private Boolean isAccountCert;

private String introduction;

private String imgUrl;
Expand All @@ -43,6 +45,7 @@ public static MemberResponse toResponse(Member member) {
.nickname(member.getNickname())
.account(member.getAccount())
.accountBank(member.getAccountBank())
.isAccountCert(member.getIsAccountCert())
.badgeLevel(member.getBadgeLevel())
.introduction(member.getIntroduction())
.imgUrl(member.getImgUrl())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ public class MemberSignUpRequest {
@NotBlank(message = "확인 비밀번호를 입력해주세요.")
private String checkPassword;

private Boolean isAccountCert;


public static Member toEntity(Member member, MemberSignUpRequest signUpRequest) {

Expand All @@ -63,15 +65,9 @@ public static Member toEntity(Member member, MemberSignUpRequest signUpRequest)
.banCnt(0)
.account(signUpRequest.getAccount())
.accountBank(signUpRequest.getAccountBank())
.isAccountCert(signUpRequest.getIsAccountCert())
.status(MemberStatus.WAIT_FOR_APPROVAL)
.badgeLevel(BadgeLevel.NONE)
.build();



}




}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import com.tenten.studybadge.common.component.AwsS3Service;
import com.tenten.studybadge.common.email.MailService;
import com.tenten.studybadge.common.exception.InvalidTokenException;
import com.tenten.studybadge.common.exception.account.BeforeCertAccountException;
import com.tenten.studybadge.common.exception.member.*;
import com.tenten.studybadge.common.exception.participation.NotFoundParticipationException;
import com.tenten.studybadge.common.exception.studychannel.NotFoundStudyChannelException;
import com.tenten.studybadge.common.jwt.JwtTokenProvider;
import com.tenten.studybadge.common.redis.RedisService;
import com.tenten.studybadge.member.dto.*;
Expand Down Expand Up @@ -61,7 +61,9 @@ public void signUp(MemberSignUpRequest signUpRequest, Platform platform) {
throw new NotMatchPasswordException();
}


if (!signUpRequest.getIsAccountCert()) {
throw new BeforeCertAccountException();
}

Optional<Member> byEmail = memberRepository.findByEmailAndPlatform(signUpRequest.getEmail(), platform);
if (byEmail.isPresent()) {
Expand Down