Skip to content

Commit

Permalink
Merge pull request #58 from JNU-econovation/be
Browse files Browse the repository at this point in the history
[BE] be -> develop
  • Loading branch information
kssumin authored Oct 6, 2023
2 parents b605de7 + 6ee7855 commit 29376d6
Show file tree
Hide file tree
Showing 28 changed files with 526 additions and 104 deletions.
25 changes: 0 additions & 25 deletions .github/workflows/main.yml

This file was deleted.

4 changes: 4 additions & 0 deletions be/overflow/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM openjdk:17-oracle
ARG JAR_FILE=/build/libs/overflow-0.0.1-SNAPSHOT.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
35 changes: 35 additions & 0 deletions be/overflow/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
version: '3.1'
services:
mysql:
container_name: overflow-mysql-dev
image: mysql/mysql-server:8.0.27
environment:
- MYSQL_DATABASE=overflow
- MYSQL_ROOT_HOST=%
- MYSQL_ROOT_PASSWORD=root
command: [ "--character-set-server=utf8mb4", "--collation-server=utf8mb4_unicode_ci", "--lower_case_table_names=1", "--max_connections=2048", "--wait_timeout=3600" ]
ports:
- "13307:3306"
volumes: #볼륨 지정
- ./resources/develop-environment/mysql-init.d:/docker-entrypoint-initdb.d
networks: #사용할 네트워크 지정
- overflow-network
backend:
build:
context: .
dockerfile: Dockerfile
container_name: overflow-app-dev
ports:
- "8080:8080"
depends_on:
- mysql
restart: always
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://overflow-mysql-dev:3306/overflow?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false&allowPublicKeyRetrieval=true
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: root
SPRING_PROFILES_ACTIVE: dev
networks: #사용할 네트워크 지정
- overflow-network
networks:
overflow-network:
13 changes: 13 additions & 0 deletions be/overflow/resources/develop-environment/mysql-init.d/00_init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
CREATE
USER 'overflow-local'@'localhost' IDENTIFIED BY 'root';
CREATE
USER 'overflow-local'@'%' IDENTIFIED BY 'root';

GRANT ALL PRIVILEGES ON *.* TO
'overflow-local'@'localhost';
GRANT ALL PRIVILEGES ON *.* TO
'overflow-local'@'%';

-- CREATE
-- DATABASE overflow DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
create table auth_info_tb
(
auth_info_id BIGINT not null auto_increment,
user_id BIGINT not null,
auth_info_type varchar(255) not null,
auth_info_token varchar(255) not null,
created_date datetime not null,
deleted bit not null,
updated_date datetime not null,
primary key (auth_info_id)
) ENGINE = InnoDB;

create table user_tb
(
user_id BIGINT not null auto_increment,
user_email varchar(255) not null,
user_nickname varchar(255) not null,
user_password varchar(255) not null,
created_date datetime not null,
deleted bit not null,
updated_date datetime not null,
primary key (user_id)
) ENGINE = InnoDB;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.econovation.overflow.auth.domain.exception;

import com.econovation.overflow.common.exception.BusinessException;
import org.springframework.http.HttpStatus;

public class AuthorizationException extends BusinessException {

public AuthorizationException(String message) {
super(message, HttpStatus.NOT_FOUND);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.econovation.overflow.auth.domain.service;

import com.econovation.overflow.auth.domain.dto.converter.TokenConverter;
import com.econovation.overflow.auth.domain.dto.response.TokenResponse;
import com.econovation.overflow.auth.persistence.converter.AuthInfoEntityConverter;
import com.econovation.overflow.auth.persistence.entity.AuthInfoEntity;
import com.econovation.overflow.auth.persistence.repository.AuthInfoRepository;
import com.econovation.overflow.security.authority.UserRole;
import com.econovation.overflow.security.token.TokenProvider;
import com.econovation.overflow.security.token.TokenResolver;
import java.util.Collections;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class CreateTokenService {
private final TokenProvider tokenProvider;
private final TokenConverter tokenConverter;
private final TokenResolver tokenResolver;
private final AuthInfoRepository authInfoRepository;
private final AuthInfoEntityConverter authInfoEntityConverter;

@Transactional
public TokenResponse execute(final Long userId) {
String accessToken =
tokenProvider.createAccessToken(userId, Collections.singletonList(UserRole.USER));
String refreshToken = tokenProvider.createRefreshToken(userId);

saveToken(userId, refreshToken);

return tokenConverter.from(
accessToken, tokenResolver.getExpiredDate(accessToken), refreshToken);
}

private void saveToken(Long userId, String token) {
AuthInfoEntity authInfoEntity = authInfoEntityConverter.from(userId, token);
authInfoRepository.save(authInfoEntity);
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
package com.econovation.overflow.auth.domain.usecase;

import com.econovation.overflow.auth.domain.dto.converter.TokenConverter;
import com.econovation.overflow.auth.domain.dto.request.LoginUserRequest;
import com.econovation.overflow.auth.domain.dto.response.TokenResponse;
import com.econovation.overflow.auth.domain.exception.NotFoundEmailException;
import com.econovation.overflow.auth.domain.exception.NotFoundPasswordException;
import com.econovation.overflow.auth.domain.service.SaveTokenService;
import com.econovation.overflow.auth.domain.service.CreateTokenService;
import com.econovation.overflow.auth.persistence.entity.UserEntity;
import com.econovation.overflow.auth.persistence.repository.UserRepository;
import com.econovation.overflow.security.authority.UserRole;
import com.econovation.overflow.security.token.TokenProvider;
import com.econovation.overflow.security.token.TokenResolver;
import java.util.Collections;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
Expand All @@ -22,12 +17,9 @@
@Transactional(readOnly = true)
public class LoginUserUseCase {

private final TokenProvider tokenProvider;
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final TokenConverter tokenConverter;
private final TokenResolver tokenResolver;
private final SaveTokenService saveTokenService;
private final CreateTokenService createTokenService;

@Transactional
public TokenResponse execute(final LoginUserRequest request) {
Expand All @@ -38,17 +30,7 @@ public TokenResponse execute(final LoginUserRequest request) {

validPassword(request.getPassword(), userEntity);

String accessToken =
tokenProvider.createAccessToken(
userEntity.getId(), Collections.singletonList(UserRole.USER));
String refreshToken =
tokenProvider.createRefreshToken(
userEntity.getId(), Collections.singletonList(UserRole.USER));

saveTokenService.execute(userEntity.getId(), refreshToken);

return tokenConverter.from(
accessToken, tokenResolver.getExpiredDate(accessToken), refreshToken);
return createTokenService.execute(userEntity.getId());
}

private void validPassword(final String requestPassword, final UserEntity userEntity) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.econovation.overflow.auth.domain.usecase;

import com.econovation.overflow.auth.domain.dto.response.TokenResponse;
import com.econovation.overflow.auth.domain.exception.AuthorizationException;
import com.econovation.overflow.auth.domain.service.CreateTokenService;
import com.econovation.overflow.auth.persistence.entity.AuthInfoEntity;
import com.econovation.overflow.auth.persistence.repository.AuthInfoRepository;
import com.econovation.overflow.security.token.TokenResolver;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
@Slf4j
public class ReissueUseCase {
private final CreateTokenService createTokenService;
private final TokenResolver tokenResolver;
private final AuthInfoRepository authInfoRepository;

@Transactional
public TokenResponse execute(final String token) {
Long userId = tokenResolver.getUserInfo(token);

AuthInfoEntity authInfoEntity = authInfoRepository
.findByUserIdAndToken(userId, token)
.orElseThrow(() -> new AuthorizationException("잘못된 토큰 입니다"));

authInfoRepository.delete(authInfoEntity);
return createTokenService.execute(userId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

import static com.econovation.overflow.auth.persistence.entity.AuthInfoEntity.ENTITY_PREFIX;

import com.econovation.overflow.common.BaseEntity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
Expand All @@ -24,7 +24,8 @@
@ToString
@SuperBuilder(toBuilder = true)
@Entity(name = ENTITY_PREFIX + "_entity")
public class AuthInfoEntity extends BaseEntity {
@Table(name = ENTITY_PREFIX + "_tb")
public class AuthInfoEntity {

public static final String ENTITY_PREFIX = "auth_info";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.Table;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
Expand All @@ -21,6 +23,12 @@
@ToString
@SuperBuilder(toBuilder = true)
@Entity(name = ENTITY_PREFIX + "_entity")
@Table(
name = ENTITY_PREFIX + "_tb",
indexes = {
@Index(name = "idx_nickname", columnList = ENTITY_PREFIX + "_nickname", unique = true),
@Index(name = "idx_email", columnList = ENTITY_PREFIX + "_email", unique = true)
})
public class UserEntity extends BaseEntity {

public static final String ENTITY_PREFIX = "user";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.econovation.overflow.auth.persistence.repository;

import com.econovation.overflow.auth.persistence.entity.AuthInfoEntity;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

public interface AuthInfoRepository extends JpaRepository<AuthInfoEntity, Long> {}
public interface AuthInfoRepository extends JpaRepository<AuthInfoEntity, Long> {
Optional<AuthInfoEntity> findByUserIdAndToken(Long userId, String token);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
import com.econovation.overflow.auth.domain.dto.request.LoginUserRequest;
import com.econovation.overflow.auth.domain.dto.response.TokenResponse;
import com.econovation.overflow.auth.domain.usecase.LoginUserUseCase;
import com.econovation.overflow.auth.domain.usecase.ReissueUseCase;
import com.econovation.overflow.auth.web.support.CookieExtractor;
import com.econovation.overflow.common.support.respnose.ApiResponse;
import com.econovation.overflow.common.support.respnose.ApiResponseBody.SuccessBody;
import com.econovation.overflow.common.support.respnose.ApiResponseGenerator;
import com.econovation.overflow.common.support.respnose.MessageCode;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
Expand All @@ -19,10 +22,12 @@
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/auth")
public class LoginController {
public class AuthController {
private static final String REFRESH_TOKEN = "refreshToken";
private static final int REFRESH_TOKEN_EXPIRATION = 7 * 24 * 60 * 60;
private final LoginUserUseCase loginUserUseCase;
private final ReissueUseCase reissueUseCase;
private final CookieExtractor cookieExtractor;

@PostMapping("/login")
public ApiResponse<SuccessBody<TokenResponse>> signIn(
Expand All @@ -33,6 +38,17 @@ public ApiResponse<SuccessBody<TokenResponse>> signIn(
tokenResponse, HttpStatus.OK, MessageCode.CREATE, cookie.toString());
}

@PostMapping("/reissue")
public ApiResponse<SuccessBody<TokenResponse>> reissue(HttpServletRequest request) {

final String token = cookieExtractor.extract(request);
final TokenResponse tokenResponse = reissueUseCase.execute(token);
final ResponseCookie cookie = putTokenInCookie(tokenResponse);

return ApiResponseGenerator.success(
tokenResponse, HttpStatus.OK, MessageCode.CREATE, cookie.toString());
}

private ResponseCookie putTokenInCookie(final TokenResponse tokenResponse) {
return ResponseCookie.from(REFRESH_TOKEN, tokenResponse.getRefreshToken())
.maxAge(REFRESH_TOKEN_EXPIRATION)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.econovation.overflow.auth.web.support;

import com.econovation.overflow.auth.domain.exception.AuthorizationException;
import java.util.Arrays;
import java.util.Optional;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;

@Component
public class CookieExtractor implements TokenExtractor {
private static final String REFRESH_KEY = "refreshToken";

@Override
public String extract(HttpServletRequest request) {
Cookie[] cookies = getCookies(request);
Optional<Cookie> tokenCookie =
Arrays.stream(cookies).filter(cookie -> cookie.getName().equals(REFRESH_KEY)).findAny();

Cookie refreshCookie =
tokenCookie.orElseThrow(() -> new AuthorizationException("토큰이 존재하지 않습니다."));

return getValue(refreshCookie);
}

private Cookie[] getCookies(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies == null) {
throw new AuthorizationException("토큰이 존재하지 않습니다");
}
return cookies;
}

private String getValue(Cookie cookie) {
String token = cookie.getValue();
validNullToken(token);
return token;
}

private void validNullToken(String token) {
if (token == null) {
throw new AuthorizationException("토큰이 존재하지 않습니다");
}
}
}
Loading

0 comments on commit 29376d6

Please sign in to comment.