Initial commit
This commit is contained in:
16
backend/user-service/Dockerfile
Normal file
16
backend/user-service/Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
||||
# openjdk8 base image
|
||||
FROM openjdk:8-jre-alpine
|
||||
|
||||
# config server uri: dockder run --e 로 변경 가능
|
||||
#ENV SPRING_CLOUD_CONFIG_URI https://egov-config.paas-ta.org
|
||||
RUN mkdir -p /usr/app/msa-attach-volume
|
||||
# jar 파일이 복사되는 위치
|
||||
ENV APP_HOME=/usr/app/
|
||||
# 작업 시작 위치
|
||||
WORKDIR $APP_HOME
|
||||
# jar 파일 복사
|
||||
COPY build/libs/*.jar app.jar
|
||||
# cf docker push, random port 사용할 수 없다
|
||||
#EXPOSE 80
|
||||
# 실행 (application-cf.yml 프로필이 기본값)
|
||||
CMD ["java", "-Dspring.profiles.active=${profile:cf}", "-jar", "app.jar"]
|
||||
39
backend/user-service/README.md
Normal file
39
backend/user-service/README.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Getting Started
|
||||
|
||||
### OAUTH2 설정
|
||||
> 각 사이트에서 애플리케이션 API 이용을 신청하여 Client ID를 발급 받아야 한다.<br/>
|
||||
> 현재 구글과 네이버를 지원한다.
|
||||
- [Google](https://console.cloud.google.com)
|
||||
- [Naver](https://developers.naver.com/apps/#/register?api=nvlogin)
|
||||
- Kakao - @todo
|
||||
|
||||
### application-oauth.yml
|
||||
- resources/application-oauth.yml 파일을 생성한다.
|
||||
- 아래 내용을 넣고 각 client-id, client-secret 를 입력한다.
|
||||
```yaml
|
||||
spring:
|
||||
security:
|
||||
oauth2:
|
||||
client:
|
||||
registration:
|
||||
google:
|
||||
client-id: @TODO https://console.cloud.google.com
|
||||
client-secret: @TODO
|
||||
scope: profile,email
|
||||
# 네이버는 Spring Security를 공식 지원하지 않기 때문에 CommonOAuth2Provider 에서 해주는 값들을 수동으로 입력한다.
|
||||
naver:
|
||||
client-id: @TODO https://developers.naver.com/apps/#/register?api=nvlogin
|
||||
client-secret: @TODO
|
||||
redirect_uri_template: "{baseUrl}/{action}/oauth2/code/{registrationId}"
|
||||
authorization_grant_type: authorization_code
|
||||
scope: name,email,profile_image
|
||||
client-name: Naver
|
||||
provider:
|
||||
naver:
|
||||
authorization_uri: https://nid.naver.com/oauth2.0/authorize
|
||||
token_uri: https://nid.naver.com/oauth2.0/token
|
||||
user-info-uri: https://openapi.naver.com/v1/nid/me
|
||||
# 기준이 되는 user_name 의 이름을 네이버에서는 response로 지정해야한다. (네이버 회원 조회시 반환되는 JSON 형태 때문이다)
|
||||
# response를 user_name으로 지정하고 이후 자바 코드로 response의 id를 user_name으로 지정한다. (스프링 시큐리티에서 하위 필드를 명시할 수 없기 때문)
|
||||
user_name_attribute: response
|
||||
```
|
||||
100
backend/user-service/build.gradle
Normal file
100
backend/user-service/build.gradle
Normal file
@@ -0,0 +1,100 @@
|
||||
plugins {
|
||||
id 'org.springframework.boot' version '2.4.5'
|
||||
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
|
||||
// querydsl
|
||||
id 'com.ewerk.gradle.plugins.querydsl' version '1.0.10'
|
||||
id 'java'
|
||||
}
|
||||
|
||||
group = 'org.egovframe.cloud'
|
||||
version = '0.1'
|
||||
sourceCompatibility = '1.8'
|
||||
|
||||
configurations {
|
||||
compileOnly {
|
||||
extendsFrom annotationProcessor
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url "https://maven.egovframe.go.kr/maven/" } // egovframe maven 원격 저장소
|
||||
}
|
||||
|
||||
ext {
|
||||
set('springCloudVersion', "2020.0.3")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// implementation files('../../module-common/build/libs/module-common-0.1.jar') // 공통 모듈, @ComponentScan(basePackages={"org.egovframe.cloud"}) 추가해야 적용된다
|
||||
implementation 'org.egovframe.cloud:module-common:0.1'
|
||||
implementation('org.egovframe.rte:org.egovframe.rte.fdl.cmmn:4.0.0') {
|
||||
exclude group: 'org.egovframe.rte', module: 'org.egovframe.rte.fdl.logging'
|
||||
}
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-security'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-validation'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-mail'
|
||||
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
|
||||
implementation 'org.springframework.cloud:spring-cloud-starter-config' // config
|
||||
implementation 'org.springframework.cloud:spring-cloud-starter-bootstrap' // config
|
||||
implementation 'org.springframework.cloud:spring-cloud-starter-bus-amqp' // bus
|
||||
implementation 'org.springframework.cloud:spring-cloud-starter-sleuth'
|
||||
implementation 'org.springframework.cloud:spring-cloud-sleuth-zipkin'
|
||||
implementation 'net.logstash.logback:logstash-logback-encoder:6.6' // logstash logback
|
||||
implementation 'mysql:mysql-connector-java'
|
||||
implementation 'io.jsonwebtoken:jjwt:0.9.1'
|
||||
// querydsl
|
||||
implementation 'com.querydsl:querydsl-jpa'
|
||||
// cache
|
||||
implementation 'org.springframework.boot:spring-boot-starter-cache'
|
||||
implementation 'org.ehcache:ehcache'
|
||||
implementation 'javax.cache:cache-api' // expiry를 위해 필요
|
||||
|
||||
implementation 'com.google.api-client:google-api-client:1.32.1'
|
||||
|
||||
// swagger
|
||||
implementation group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'
|
||||
implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'
|
||||
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
|
||||
|
||||
// lombok
|
||||
implementation 'org.projectlombok:lombok'
|
||||
annotationProcessor 'org.projectlombok:lombok'
|
||||
testImplementation 'org.projectlombok:lombok'
|
||||
testAnnotationProcessor 'org.projectlombok:lombok'
|
||||
testImplementation 'com.h2database:h2'
|
||||
testImplementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.7'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
testImplementation 'org.springframework.security:spring-security-test'
|
||||
}
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
// querydsl 추가 시작
|
||||
def querydslDir = "$buildDir/generated/querydsl"
|
||||
querydsl {
|
||||
jpa = true
|
||||
querydslSourcesDir = querydslDir
|
||||
}
|
||||
sourceSets {
|
||||
main.java.srcDir querydslDir
|
||||
}
|
||||
configurations {
|
||||
querydsl.extendsFrom compileClasspath
|
||||
}
|
||||
compileQuerydsl {
|
||||
options.annotationProcessorPath = configurations.querydsl
|
||||
}
|
||||
// querydsl 추가 끝
|
||||
185
backend/user-service/gradlew
vendored
Executable file
185
backend/user-service/gradlew
vendored
Executable file
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
89
backend/user-service/gradlew.bat
vendored
Normal file
89
backend/user-service/gradlew.bat
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
16
backend/user-service/manifest.yml
Normal file
16
backend/user-service/manifest.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
applications:
|
||||
- name: egov-user-service # CF push 시 생성되는 이름
|
||||
# memory: 512M # 메모리
|
||||
instances: 1 # 인스턴스 수
|
||||
host: egov-user-service # host 명으로 유일해야 함
|
||||
path: build/libs/user-service-0.1.jar # build 후 생성된 jar 위치
|
||||
buildpack: java_buildpack # cf buildpacks 명령어로 java buildpack 이름 확인
|
||||
services:
|
||||
- egov-discovery-provided-service # discovery service binding
|
||||
env:
|
||||
spring_profiles_active: cf
|
||||
spring_cloud_config_uri: https://egov-config.paas-ta.org
|
||||
app_name: egov-user-service # logstash custom app name
|
||||
TZ: Asia/Seoul
|
||||
JAVA_OPTS: -Xss349k
|
||||
1
backend/user-service/settings.gradle
Normal file
1
backend/user-service/settings.gradle
Normal file
@@ -0,0 +1 @@
|
||||
rootProject.name = 'user-service'
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.egovframe.cloud.userservice;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.UserApplication
|
||||
* <p>
|
||||
* 유저 서비스 어플리케이션 클래스
|
||||
* Eureka Client 로 설정했기 때문에 Eureka Server 가 먼저 기동되어야 한다.
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/06/30
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/06/30 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@ComponentScan({"org.egovframe.cloud.common", "org.egovframe.cloud.servlet", "org.egovframe.cloud.userservice"}) // org.egovframe.cloud.common package 포함하기 위해
|
||||
@EntityScan({"org.egovframe.cloud.servlet.domain", "org.egovframe.cloud.userservice.domain"})
|
||||
@EnableDiscoveryClient
|
||||
@SpringBootApplication
|
||||
public class UserServiceApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(UserServiceApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BCryptPasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.egovframe.cloud.userservice.api;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.MessageSourceApiController
|
||||
* <p>
|
||||
* MessageSource 정상 확인을 위한 컨트롤러
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/08/10
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/08/10 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
public class MessageSourceApiController {
|
||||
private final MessageSource messageSource;
|
||||
|
||||
@GetMapping("/api/v1/messages/{code}/{lang}")
|
||||
public String getMessage(@PathVariable String code, @PathVariable String lang) {
|
||||
Locale locale = "en".equals(lang)? Locale.ENGLISH : Locale.KOREAN;
|
||||
String message = messageSource.getMessage(code, null, locale);
|
||||
log.info("code={}, lang={}, message={}", code, lang, message);
|
||||
return message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
package org.egovframe.cloud.userservice.api.role;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.egovframe.cloud.common.dto.RequestDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.AuthorizationListResponseDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.AuthorizationResponseDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.AuthorizationSaveRequestDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.AuthorizationUpdateRequestDto;
|
||||
import org.egovframe.cloud.userservice.service.role.AuthorizationService;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.web.PageableDefault;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.role.AuthorizationApiController
|
||||
* <p>
|
||||
* API Gateway 의 RestApiAuthorization.check 메소드에 의해 호출된다.
|
||||
* 요청 url에 대한 사용자 인가 서비스를 수행하는 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/07/19
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/19 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
public class AuthorizationApiController {
|
||||
|
||||
/**
|
||||
* 인가 서비스
|
||||
*/
|
||||
private final AuthorizationService authorizationService;
|
||||
|
||||
/**
|
||||
* 인가 여부 확인
|
||||
*
|
||||
* @param httpMethod Http Method
|
||||
* @param requestPath 요청 경로
|
||||
* @return Boolean 인가 여부
|
||||
*/
|
||||
@GetMapping("/api/v1/authorizations/check")
|
||||
public Boolean isAuthorization(@RequestParam("httpMethod") String httpMethod, @RequestParam("requestPath") String requestPath) {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
String userId = authentication.getName();
|
||||
List<String> roles = authentication.getAuthorities().stream().map(GrantedAuthority::toString).collect(Collectors.toList());
|
||||
|
||||
// 사용자 아이디로 조회
|
||||
// return authorizationService.isAuthorization(userId, httpMethod, requestPath);
|
||||
|
||||
// 권한으로 조회
|
||||
Boolean isAuth = authorizationService.isAuthorization(roles, httpMethod, requestPath);
|
||||
|
||||
log.info("[isAuthorization={}] authentication.isAuthenticated()={}, userId={}, httpMethod={}, requestPath={}, roleList={}", isAuth, authentication.isAuthenticated(), userId, httpMethod, requestPath, roles);
|
||||
|
||||
return isAuth;
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 페이지 목록 조회
|
||||
*
|
||||
* @param requestDto 요청 DTO
|
||||
* @param pageable 페이지 정보
|
||||
* @return Page<AuthorizationListResponseDto> 페이지 인가 목록 응답 DTO
|
||||
*/
|
||||
@GetMapping("/api/v1/authorizations")
|
||||
public Page<AuthorizationListResponseDto> findPage(RequestDto requestDto,
|
||||
@PageableDefault(sort = "sort_seq", direction = Sort.Direction.ASC) Pageable pageable) {
|
||||
return authorizationService.findPage(requestDto, pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 단건 조회
|
||||
*
|
||||
* @param authorizationNo 인가 번호
|
||||
* @return AuthorizationResponseDto 인가 상세 응답 DTO
|
||||
*/
|
||||
@GetMapping("/api/v1/authorizations/{authorizationNo}")
|
||||
public AuthorizationResponseDto findById(@PathVariable Integer authorizationNo) {
|
||||
return authorizationService.findById(authorizationNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 다음 정렬 순서 조회
|
||||
*
|
||||
* @return Integer 다음 정렬 순서
|
||||
*/
|
||||
@GetMapping("/api/v1/authorizations/sort-seq/next")
|
||||
public Integer findNextSortSeq() {
|
||||
return authorizationService.findNextSortSeq();
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 등록
|
||||
*
|
||||
* @param requestDto 인가 등록 요청 DTO
|
||||
* @return AuthorizationResponseDto 인가 상세 응답 DTO
|
||||
*/
|
||||
@PostMapping("/api/v1/authorizations")
|
||||
public AuthorizationResponseDto save(@RequestBody @Valid AuthorizationSaveRequestDto requestDto) {
|
||||
return authorizationService.save(requestDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 수정
|
||||
*
|
||||
* @param authorizationNo 인가 번호
|
||||
* @param requestDto 인가 수정 요청 DTO
|
||||
* @return AuthorizationResponseDto 인가 상세 응답 DTO
|
||||
*/
|
||||
@PutMapping("/api/v1/authorizations/{authorizationNo}")
|
||||
public AuthorizationResponseDto update(@PathVariable Integer authorizationNo, @RequestBody @Valid AuthorizationUpdateRequestDto requestDto) {
|
||||
return authorizationService.update(authorizationNo, requestDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 삭제
|
||||
*
|
||||
* @param authorizationNo 인가 번호
|
||||
*/
|
||||
@DeleteMapping("/api/v1/authorizations/{authorizationNo}")
|
||||
public void delete(@PathVariable Integer authorizationNo) {
|
||||
authorizationService.delete(authorizationNo);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package org.egovframe.cloud.userservice.api.role;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.egovframe.cloud.common.dto.RequestDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.RoleListResponseDto;
|
||||
import org.egovframe.cloud.userservice.service.role.RoleService;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.web.PageableDefault;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.role.RoleApiController
|
||||
* <p>
|
||||
* 권한 Rest API 컨트롤러 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/07
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/07 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
public class RoleApiController {
|
||||
|
||||
/**
|
||||
* 권한 서비스
|
||||
*/
|
||||
private final RoleService roleService;
|
||||
|
||||
/**
|
||||
* 권한 페이지 목록 조회
|
||||
*
|
||||
* @param requestDto 요청 DTO
|
||||
* @param pageable 페이지 정보
|
||||
* @return Page<RoleListResponseDto> 페이지 권한 목록 응답 DTO
|
||||
*/
|
||||
@GetMapping("/api/v1/roles")
|
||||
public Page<RoleListResponseDto> findPage(RequestDto requestDto,
|
||||
@PageableDefault(sort = "sort_seq", direction = Sort.Direction.ASC) Pageable pageable) {
|
||||
return roleService.findPage(requestDto, pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한 정렬 순서 오름차순 전체 목록 조회
|
||||
*
|
||||
* @return List<RoleListResponseDto>
|
||||
*/
|
||||
@GetMapping("/api/v1/roles/all")
|
||||
public List<RoleListResponseDto> findAll() {
|
||||
return roleService.findAllBySort(Sort.by(Sort.Direction.ASC, "sortSeq"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package org.egovframe.cloud.userservice.api.role;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.RoleAuthorizationDeleteRequestDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.RoleAuthorizationListRequestDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.RoleAuthorizationListResponseDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.RoleAuthorizationSaveRequestDto;
|
||||
import org.egovframe.cloud.userservice.service.role.RoleAuthorizationService;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.role.RoleAuthorizationApiController
|
||||
* <p>
|
||||
* 권한 인가 Rest API 컨트롤러 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/12
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/12 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
public class RoleAuthorizationApiController {
|
||||
|
||||
/**
|
||||
* 권한 인가 서비스
|
||||
*/
|
||||
private final RoleAuthorizationService roleAuthorizationService;
|
||||
|
||||
/**
|
||||
* 권한 인가 페이지 목록 조회
|
||||
*
|
||||
* @param requestDto 요청 DTO
|
||||
* @param pageable 페이지 정보
|
||||
* @return Page<RoleAuthorizationListResponseDto> 페이지 권한 인가 목록 응답 DTO
|
||||
*/
|
||||
@GetMapping("/api/v1/role-authorizations")
|
||||
public Page<RoleAuthorizationListResponseDto> findPageAuthorizationList(@Valid RoleAuthorizationListRequestDto requestDto,
|
||||
Pageable pageable) {
|
||||
return roleAuthorizationService.findPageAuthorizationList(requestDto, pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한 인가 다건 등록
|
||||
*
|
||||
* @param requestDtoList 권한 인가 등록 요청 DTO List
|
||||
* @return List<RoleAuthorizationListResponseDto> 등록한 권한 인가 목록 응답 DTO
|
||||
*/
|
||||
@PostMapping("/api/v1/role-authorizations")
|
||||
public List<RoleAuthorizationListResponseDto> save(@RequestBody @Valid List<RoleAuthorizationSaveRequestDto> requestDtoList) {
|
||||
return roleAuthorizationService.save(requestDtoList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한 인가 다건 삭제
|
||||
*
|
||||
* @param requestDtoList 권한 인가 삭제 요청 DTO List
|
||||
*/
|
||||
@PutMapping("/api/v1/role-authorizations")
|
||||
public void delete(@RequestBody @Valid List<RoleAuthorizationDeleteRequestDto> requestDtoList) {
|
||||
roleAuthorizationService.delete(requestDtoList);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package org.egovframe.cloud.userservice.api.role.dto;
|
||||
|
||||
import com.querydsl.core.annotations.QueryProjection;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.role.dto.AuthorizationListResponseDto
|
||||
* <p>
|
||||
* 인가 목록 응답 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/08
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/08 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class AuthorizationListResponseDto implements Serializable {
|
||||
|
||||
/**
|
||||
* serialVersionUID
|
||||
*/
|
||||
private static final long serialVersionUID = 7400347728171964946L;
|
||||
|
||||
/**
|
||||
* 인가 번호
|
||||
*/
|
||||
private Integer authorizationNo;
|
||||
|
||||
/**
|
||||
* 인가 명
|
||||
*/
|
||||
private String authorizationName;
|
||||
|
||||
/**
|
||||
* URL 패턴 값
|
||||
*/
|
||||
private String urlPatternValue;
|
||||
|
||||
/**
|
||||
* Http Method 코드
|
||||
*/
|
||||
private String httpMethodCode;
|
||||
|
||||
/**
|
||||
* 정렬 순서
|
||||
*/
|
||||
private Integer sortSeq;
|
||||
|
||||
/**
|
||||
* 인가 목록 응답 DTO 생성자
|
||||
*
|
||||
* @param authorizationNo 인가 번호
|
||||
* @param authorizationName 인가 명
|
||||
* @param urlPatternValue URL 패턴 값
|
||||
* @param httpMethodCode Http Method 코드
|
||||
* @param sortSeq 정렬 순서
|
||||
*/
|
||||
@QueryProjection
|
||||
public AuthorizationListResponseDto(Integer authorizationNo, String authorizationName, String urlPatternValue, String httpMethodCode, Integer sortSeq) {
|
||||
this.authorizationNo = authorizationNo;
|
||||
this.authorizationName = authorizationName;
|
||||
this.urlPatternValue = urlPatternValue;
|
||||
this.httpMethodCode = httpMethodCode;
|
||||
this.sortSeq = sortSeq;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package org.egovframe.cloud.userservice.api.role.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.egovframe.cloud.userservice.domain.role.Authorization;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.role.dto.AuthorizationResponseDto
|
||||
* <p>
|
||||
* 인가 상세 응답 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/08
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/08 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class AuthorizationResponseDto {
|
||||
|
||||
/**
|
||||
* 인가 번호
|
||||
*/
|
||||
private Integer authorizationNo;
|
||||
|
||||
/**
|
||||
* 인가 명
|
||||
*/
|
||||
private String authorizationName;
|
||||
|
||||
/**
|
||||
* URL 패턴 값
|
||||
*/
|
||||
private String urlPatternValue;
|
||||
|
||||
/**
|
||||
* Http Method 코드
|
||||
*/
|
||||
private String httpMethodCode;
|
||||
|
||||
/**
|
||||
* 정렬 순서
|
||||
*/
|
||||
private Integer sortSeq;
|
||||
|
||||
/**
|
||||
* 권한 인가 목록 응답 DTO
|
||||
*/
|
||||
private List<RoleAuthorizationListResponseDto> roleAuthorizations;
|
||||
|
||||
/**
|
||||
* 인가 엔티티를 생성자로 주입 받아서 인가 상세 응답 DTO 속성 값 세팅
|
||||
*
|
||||
* @param entity 인가 엔티티
|
||||
*/
|
||||
public AuthorizationResponseDto(Authorization entity) {
|
||||
this.authorizationNo = entity.getAuthorizationNo();
|
||||
this.authorizationName = entity.getAuthorizationName();
|
||||
this.urlPatternValue = entity.getUrlPatternValue();
|
||||
this.httpMethodCode = entity.getHttpMethodCode();
|
||||
this.sortSeq = entity.getSortSeq();
|
||||
if (entity.getRoleAuthorizations() != null) {
|
||||
this.roleAuthorizations = entity.getRoleAuthorizations().stream()
|
||||
// .map(RoleAuthorizationListResponseDto::new)
|
||||
.map(e -> RoleAuthorizationListResponseDto.builder()
|
||||
.roleId(e.getRoleAuthorizationId().getRoleId())
|
||||
.authorizationNo(e.getRoleAuthorizationId().getAuthorizationNo())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 상세 응답 DTO 속성 값으로 인가 엔티티 빌더를 사용하여 객체 생성
|
||||
*
|
||||
* @return Authorization 인가 엔티티
|
||||
*/
|
||||
public Authorization toEntity() {
|
||||
return Authorization.builder()
|
||||
.authorizationNo(authorizationNo)
|
||||
.authorizationName(authorizationName)
|
||||
.urlPatternValue(urlPatternValue)
|
||||
.httpMethodCode(httpMethodCode)
|
||||
.sortSeq(sortSeq)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package org.egovframe.cloud.userservice.api.role.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.egovframe.cloud.userservice.domain.role.Authorization;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.role.dto.AuthorizationSaveRequestDto
|
||||
* <p>
|
||||
* 인가 등록 요청 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/08
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/08 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
public class AuthorizationSaveRequestDto {
|
||||
|
||||
/**
|
||||
* 인가 명
|
||||
*/
|
||||
@NotBlank(message = "{authorization.authorizationName} {err.required}")
|
||||
private String authorizationName;
|
||||
|
||||
/**
|
||||
* URL 패턴 값
|
||||
*/
|
||||
@NotBlank(message = "{authorization.urlPatternValue} {err.required}")
|
||||
private String urlPatternValue;
|
||||
|
||||
/**
|
||||
* Http Method 코드
|
||||
*/
|
||||
@NotBlank(message = "{authorization.httpMethodCode} {err.required}")
|
||||
private String httpMethodCode;
|
||||
|
||||
/**
|
||||
* 정렬 순서
|
||||
*/
|
||||
@NotNull(message = "{authorization.sortSeq} {err.required}")
|
||||
private Integer sortSeq;
|
||||
|
||||
/**
|
||||
* 인가 등록 요청 DTO 속성 값으로 인가 엔티티 빌더를 사용하여 객체 생성
|
||||
*
|
||||
* @return Authorization 인가 엔티티
|
||||
*/
|
||||
public Authorization toEntity() {
|
||||
return Authorization.builder()
|
||||
.authorizationName(authorizationName)
|
||||
.urlPatternValue(urlPatternValue)
|
||||
.httpMethodCode(httpMethodCode)
|
||||
.sortSeq(sortSeq)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package org.egovframe.cloud.userservice.api.role.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.role.dto.AuthorizationUpdateRequestDto
|
||||
* <p>
|
||||
* 인가 수정 요청 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/08
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/08 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
public class AuthorizationUpdateRequestDto {
|
||||
|
||||
/**
|
||||
* 인가 명
|
||||
*/
|
||||
@NotBlank(message = "{authorization.authorizationName} {err.required}")
|
||||
private String authorizationName;
|
||||
|
||||
/**
|
||||
* URL 패턴 값
|
||||
*/
|
||||
@NotBlank(message = "{authorization.urlPatternValue} {err.required}")
|
||||
private String urlPatternValue;
|
||||
|
||||
/**
|
||||
* Http Method 코드
|
||||
*/
|
||||
@NotBlank(message = "{authorization.httpMethodCode} {err.required}")
|
||||
private String httpMethodCode;
|
||||
|
||||
/**
|
||||
* 정렬 순서
|
||||
*/
|
||||
@NotNull(message = "{authorization.sortSeq} {err.required}")
|
||||
private Integer sortSeq;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package org.egovframe.cloud.userservice.api.role.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.egovframe.cloud.userservice.domain.role.RoleAuthorization;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.role.dto.RoleAuthorizationDeleteRequestDto
|
||||
* <p>
|
||||
* 권한 인가 삭제 요청 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/13
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/13 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class RoleAuthorizationDeleteRequestDto {
|
||||
|
||||
/**
|
||||
* 권한 id
|
||||
*/
|
||||
@NotBlank(message = "{role.roleId} {err.required}")
|
||||
private String roleId;
|
||||
|
||||
/**
|
||||
* 인가 번호
|
||||
*/
|
||||
@NotNull(message = "{authorization.authorizationNo} {err.required}")
|
||||
private Integer authorizationNo;
|
||||
|
||||
/**
|
||||
* 권한 인가 삭제 요청 DTO 클래스 생성자
|
||||
* 빌더 패턴으로 객체 생성
|
||||
*
|
||||
* @param roleId 권한 id
|
||||
* @param authorizationNo 인가 번호
|
||||
*/
|
||||
@Builder
|
||||
public RoleAuthorizationDeleteRequestDto(String roleId, Integer authorizationNo) {
|
||||
this.roleId = roleId;
|
||||
this.authorizationNo = authorizationNo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한 인가 삭제 DTO 속성 값으로 권한 인가 엔티티 빌더를 사용하여 객체 생성
|
||||
*
|
||||
* @return RoleAuthorization 권한 인가 엔티티
|
||||
*/
|
||||
public RoleAuthorization toEntity() {
|
||||
return RoleAuthorization.builder()
|
||||
.roleId(roleId)
|
||||
.authorizationNo(authorizationNo)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.egovframe.cloud.userservice.api.role.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.egovframe.cloud.common.dto.RequestDto;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.role.dto.RoleAuthorizationListRequestDto
|
||||
* <p>
|
||||
* 권한 인가 목록 요청 DTO 클래스
|
||||
* 인가 목록 요청 DTO 클래스(org.egovframe.cloud.portalservice.api.authorization.dto.AuthorizationListRequestDto) 상속?
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/09
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/09 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
public class RoleAuthorizationListRequestDto extends RequestDto {
|
||||
|
||||
/**
|
||||
* 권한 id
|
||||
*/
|
||||
@NotBlank(message = "{role.roleId} {err.required}")
|
||||
private String roleId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package org.egovframe.cloud.userservice.api.role.dto;
|
||||
|
||||
import com.querydsl.core.annotations.QueryProjection;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.role.dto.RoleAuthorizationListResponseDto
|
||||
* <p>
|
||||
* 권한 인가 목록 응답 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/12
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/12 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class RoleAuthorizationListResponseDto {
|
||||
|
||||
/**
|
||||
* 권한 id
|
||||
*/
|
||||
private String roleId;
|
||||
|
||||
/**
|
||||
* 인가 번호
|
||||
*/
|
||||
private Integer authorizationNo;
|
||||
|
||||
/**
|
||||
* 인가 명
|
||||
*/
|
||||
private String authorizationName;
|
||||
|
||||
/**
|
||||
* URL 패턴 값
|
||||
*/
|
||||
private String urlPatternValue;
|
||||
|
||||
/**
|
||||
* Http Method 코드
|
||||
*/
|
||||
private String httpMethodCode;
|
||||
|
||||
/**
|
||||
* 정렬 순서
|
||||
*/
|
||||
private Integer sortSeq;
|
||||
|
||||
/**
|
||||
* 생성 여부
|
||||
*/
|
||||
private Boolean createdAt;
|
||||
|
||||
/**
|
||||
* 권한 인가 목록 응답 DTO 클래스 생성자
|
||||
*
|
||||
* @param roleId 권한 id
|
||||
* @param authorizationNo 인가 번호
|
||||
* @param authorizationName 인가 명
|
||||
* @param urlPatternValue URL 패턴 값
|
||||
* @param httpMethodCode Http Method 코드
|
||||
* @param sortSeq 정렬 순서
|
||||
* @param createdAt 생성 여부
|
||||
*/
|
||||
@QueryProjection
|
||||
@Builder
|
||||
public RoleAuthorizationListResponseDto(String roleId, Integer authorizationNo, String authorizationName,
|
||||
String urlPatternValue, String httpMethodCode, Integer sortSeq, Boolean createdAt) {
|
||||
this.roleId = roleId;
|
||||
this.authorizationNo = authorizationNo;
|
||||
this.authorizationName = authorizationName;
|
||||
this.urlPatternValue = urlPatternValue;
|
||||
this.httpMethodCode = httpMethodCode;
|
||||
this.sortSeq = sortSeq;
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package org.egovframe.cloud.userservice.api.role.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.egovframe.cloud.userservice.domain.role.RoleAuthorization;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.role.dto.RoleAuthorizationResponseDto
|
||||
* <p>
|
||||
* 권한 인가 상세 응답 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/12
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/12 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class RoleAuthorizationResponseDto {
|
||||
|
||||
/**
|
||||
* 권한 id
|
||||
*/
|
||||
private String roleId;
|
||||
|
||||
/**
|
||||
* 인가 번호
|
||||
*/
|
||||
private Integer authorizationNo;
|
||||
|
||||
/**
|
||||
* 인가 명
|
||||
*/
|
||||
private String authorizationName;
|
||||
|
||||
/**
|
||||
* URL 패턴 값
|
||||
*/
|
||||
private String urlPatternValue;
|
||||
|
||||
/**
|
||||
* Http Method 코드
|
||||
*/
|
||||
private String httpMethodCode;
|
||||
|
||||
/**
|
||||
* 정렬 순서
|
||||
*/
|
||||
private Integer sortSeq;
|
||||
|
||||
/**
|
||||
* 생성 여부
|
||||
*/
|
||||
private Integer createdAt;
|
||||
|
||||
/**
|
||||
* 권한 인가 엔티티를 생성자로 주입 받아서 권한 인가 상세 응답 DTO 속성 값 세팅
|
||||
*
|
||||
* @param entity 권한 인가 엔티티
|
||||
*/
|
||||
public RoleAuthorizationResponseDto(RoleAuthorization entity) {
|
||||
this.roleId = entity.getRoleAuthorizationId().getRoleId();
|
||||
this.authorizationNo = entity.getAuthorization().getAuthorizationNo();
|
||||
this.authorizationName = entity.getAuthorization().getAuthorizationName();
|
||||
this.urlPatternValue = entity.getAuthorization().getUrlPatternValue();
|
||||
this.httpMethodCode = entity.getAuthorization().getHttpMethodCode();
|
||||
this.sortSeq = entity.getAuthorization().getSortSeq();
|
||||
this.createdAt = 1;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.egovframe.cloud.userservice.api.role.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.egovframe.cloud.userservice.domain.role.RoleAuthorization;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.role.dto.RoleAuthorizationSaveRequestDto
|
||||
* <p>
|
||||
* 권한 인가 등록 요청 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/12
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/12 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
public class RoleAuthorizationSaveRequestDto {
|
||||
|
||||
/**
|
||||
* 권한 id
|
||||
*/
|
||||
@NotBlank(message = "{role.roleId} {err.required}")
|
||||
private String roleId;
|
||||
|
||||
/**
|
||||
* 인가 번호
|
||||
*/
|
||||
@NotNull(message = "{authorization.authorizationNo} {err.required}")
|
||||
private Integer authorizationNo;
|
||||
|
||||
/**
|
||||
* 권한 인가 등록 요청 DTO 속성 값으로 권한 인가 엔티티 빌더를 사용하여 객체 생성
|
||||
*
|
||||
* @return RoleAuthorization 권한 인가 엔티티
|
||||
*/
|
||||
public RoleAuthorization toEntity() {
|
||||
return RoleAuthorization.builder()
|
||||
.roleId(roleId)
|
||||
.authorizationNo(authorizationNo)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package org.egovframe.cloud.userservice.api.role.dto;
|
||||
|
||||
import com.querydsl.core.annotations.QueryProjection;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.role.dto.RoleListResponseDto
|
||||
* <p>
|
||||
* 권한 목록 응답 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/07
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/07 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class RoleListResponseDto {
|
||||
|
||||
/**
|
||||
* 권한 id
|
||||
*/
|
||||
private String roleId;
|
||||
|
||||
/**
|
||||
* 권한 명
|
||||
*/
|
||||
private String roleName;
|
||||
|
||||
/**
|
||||
* 권한 내용
|
||||
*/
|
||||
private String roleContent;
|
||||
|
||||
/**
|
||||
* 생성 일시
|
||||
*/
|
||||
private LocalDateTime createdDate;
|
||||
|
||||
/**
|
||||
* 권한 목록 응답 DTO 클래스 생성자
|
||||
*
|
||||
* @param roleId 권한 id
|
||||
* @param roleName 권한 명
|
||||
* @param roleContent 권한 내용
|
||||
* @param createdDate 생성 일시
|
||||
*/
|
||||
@QueryProjection
|
||||
@Builder
|
||||
public RoleListResponseDto(String roleId, String roleName, String roleContent, LocalDateTime createdDate) {
|
||||
this.roleId = roleId;
|
||||
this.roleName = roleName;
|
||||
this.roleContent = roleContent;
|
||||
this.createdDate = createdDate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
package org.egovframe.cloud.userservice.api.user;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.egovframe.cloud.common.dto.RequestDto;
|
||||
import org.egovframe.cloud.common.exception.BusinessMessageException;
|
||||
import org.egovframe.cloud.common.util.MessageUtil;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserEmailRequestDto;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserFindPasswordSaveRequestDto;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserFindPasswordUpdateRequestDto;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserJoinRequestDto;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserListResponseDto;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserPasswordMatchRequestDto;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserPasswordUpdateRequestDto;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserResponseDto;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserSaveRequestDto;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserUpdateInfoRequestDto;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserUpdateRequestDto;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserVerifyRequestDto;
|
||||
import org.egovframe.cloud.userservice.config.TokenProvider;
|
||||
import org.egovframe.cloud.userservice.service.user.UserService;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.user.UserApiController
|
||||
* <p>
|
||||
* 사용자 CRUD 요청을 처리하는 REST API Controller
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/06/30
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/06/30 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@RequiredArgsConstructor // final이 선언된 모든 필드를 인자값으로 하는 생성자를 대신 생성하여, 빈을 생성자로 주입받게 한다.
|
||||
@RestController
|
||||
public class UserApiController {
|
||||
private final UserService userService;
|
||||
private final Environment env;
|
||||
private final TokenProvider tokenProvider;
|
||||
|
||||
private final MessageUtil messageUtil;
|
||||
|
||||
/**
|
||||
* 유저 서비스 상태 확인
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/actuator/health-user")
|
||||
public String status() {
|
||||
return String.format("GET User Service on" +
|
||||
"\n local.server.port :" + env.getProperty("local.server.port")
|
||||
+ "\n token expiration time :" + env.getProperty("token.expiration_time")
|
||||
+ "\n spring.datasource.username :" + env.getProperty("spring.datasource.username")
|
||||
+ "\n egov.message :" + env.getProperty("egov.message")
|
||||
);
|
||||
}
|
||||
|
||||
@PostMapping("/actuator/health-user")
|
||||
public String poststatus() {
|
||||
return String.format("POST User Service on" +
|
||||
"\n local.server.port :" + env.getProperty("local.server.port")
|
||||
+ "\n token expiration time :" + env.getProperty("token.expiration_time")
|
||||
+ "\n spring.datasource.username :" + env.getProperty("spring.datasource.username")
|
||||
+ "\n egov.message :" + env.getProperty("egov.message")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 정보 입력
|
||||
*
|
||||
* @param requestDto
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/api/v1/users")
|
||||
public Long save(@RequestBody @Valid UserSaveRequestDto requestDto) {
|
||||
return userService.save(requestDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 정보 업데이트
|
||||
*
|
||||
* @param userId
|
||||
* @param requestDto
|
||||
* @return
|
||||
*/
|
||||
@PutMapping("/api/v1/users/{userId}")
|
||||
public String update(@PathVariable String userId, @RequestBody @Valid UserUpdateRequestDto requestDto) {
|
||||
return userService.update(userId, requestDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 페이지 목록 조회
|
||||
*
|
||||
* @param requestDto 요청 DTO
|
||||
* @param pageable 페이지 정보
|
||||
* @return Page<UserListResponseDto> 페이지 사용자 목록 응답 DTO
|
||||
*/
|
||||
@GetMapping("/api/v1/users")
|
||||
public Page<UserListResponseDto> findPage(RequestDto requestDto, Pageable pageable) {
|
||||
return userService.findPage(requestDto, pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 단 건 조회
|
||||
*
|
||||
* @param userId
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/api/v1/users/{userId}")
|
||||
public UserResponseDto findByUserId(@PathVariable String userId) {
|
||||
return userService.findByUserId(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* refresh token 과 일치하는 사용자가 있으면 access token 을 새로 발급하여 리턴한다.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@PutMapping("/api/v1/users/token/refresh")
|
||||
public void refreshToken(HttpServletRequest request, HttpServletResponse response) {
|
||||
String refreshToken = request.getHeader(HttpHeaders.AUTHORIZATION);
|
||||
tokenProvider.refreshToken(refreshToken, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 이메일 중복 확인
|
||||
*
|
||||
* @param requestDto 사용자 이메일 확인 요청 DTO
|
||||
* @return Boolean 중복 여부
|
||||
*/
|
||||
@PostMapping("/api/v1/users/exists")
|
||||
public Boolean existsEmail(@RequestBody UserEmailRequestDto requestDto) {
|
||||
return userService.existsEmail(requestDto.getEmail(), requestDto.getUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 회원 가입
|
||||
*
|
||||
* @param requestDto 사용자 가입 요청 DTO
|
||||
* @return Boolean 성공 여부
|
||||
*/
|
||||
@PostMapping("/api/v1/users/join")
|
||||
public Boolean join(@RequestBody @Valid UserJoinRequestDto requestDto) {
|
||||
return userService.join(requestDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 비밀번호 찾기
|
||||
*
|
||||
* @param requestDto 사용자 비밀번호 찾기 등록 요청 DTO
|
||||
* @return Boolean 메일 전송 여부
|
||||
*/
|
||||
@PostMapping("/api/v1/users/password/find")
|
||||
public Boolean findPassword(@RequestBody @Valid UserFindPasswordSaveRequestDto requestDto) {
|
||||
return userService.findPassword(requestDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 비밀번호 찾기 유효성 확인
|
||||
*
|
||||
* @param token 토큰
|
||||
* @return Boolean 유효 여부
|
||||
*/
|
||||
@GetMapping("/api/v1/users/password/valid/{token}")
|
||||
public Boolean validPassword(@PathVariable String token) {
|
||||
return userService.validPassword(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 비밀번호 찾기 변경
|
||||
*
|
||||
* @param requestDto 사용자 비밀번호 수정 요청 DTO
|
||||
* @return Boolean 수정 여부
|
||||
*/
|
||||
@PutMapping("/api/v1/users/password/change")
|
||||
public Boolean changePassword(@RequestBody @Valid UserFindPasswordUpdateRequestDto requestDto) {
|
||||
return userService.changePassword(requestDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 비밀번호 변경
|
||||
*
|
||||
* @param requestDto 사용자 비밀번호 수정 요청 DTO
|
||||
* @return Boolean 수정 여부
|
||||
*/
|
||||
@PutMapping("/api/v1/users/password/update")
|
||||
public Boolean updatePassword(@RequestBody @Valid UserPasswordUpdateRequestDto requestDto) {
|
||||
final String userId = SecurityContextHolder.getContext().getAuthentication().getName();
|
||||
|
||||
return userService.updatePassword(userId, requestDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 비밀번호 확인
|
||||
*
|
||||
* @param requestDto 사용자 비밀번호 확인 요청 DTO
|
||||
* @return Boolean 일치 여부
|
||||
*/
|
||||
@PostMapping("/api/v1/users/password/match")
|
||||
public Boolean matchPassword(@RequestBody @Valid UserPasswordMatchRequestDto requestDto) {
|
||||
final String userId = SecurityContextHolder.getContext().getAuthentication().getName();
|
||||
final String password = requestDto.getPassword();
|
||||
|
||||
return userService.matchPassword(userId, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 회원정보 변경
|
||||
*
|
||||
* @param userId 사용자 id
|
||||
* @param requestDto 사용자 수정 요청 DTO
|
||||
* @return String 사용자 id
|
||||
*/
|
||||
@PutMapping("/api/v1/users/info/{userId}")
|
||||
public String updateInfo(@PathVariable String userId, @RequestBody @Valid UserUpdateInfoRequestDto requestDto) {
|
||||
final String authUserId = SecurityContextHolder.getContext().getAuthentication().getName();
|
||||
if (!authUserId.equals(userId)) {
|
||||
throw new BusinessMessageException(messageUtil.getMessage("err.access.denied"));
|
||||
}
|
||||
|
||||
return userService.updateInfo(userId, requestDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 회원탈퇴
|
||||
*
|
||||
* @param requestDto 사용자 비밀번호 확인 요청 DTO
|
||||
* @return Boolean 일치 여부
|
||||
* @throws GeneralSecurityException 보안 예외
|
||||
* @throws IOException 입출력 예외
|
||||
*/
|
||||
@PostMapping("/api/v1/users/leave")
|
||||
public Boolean leave(@RequestBody @Valid UserVerifyRequestDto requestDto) throws GeneralSecurityException, IOException {
|
||||
final String userId = SecurityContextHolder.getContext().getAuthentication().getName();
|
||||
|
||||
return userService.leave(userId, requestDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 회원탈퇴
|
||||
*
|
||||
* @param userId 사용자 비밀번호 확인 요청 DTO
|
||||
* @return Boolean 일치 여부
|
||||
*/
|
||||
@DeleteMapping("/api/v1/users/delete/{userId}")
|
||||
public Boolean delete(@PathVariable String userId) {
|
||||
return userService.delete(userId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.egovframe.cloud.userservice.api.user.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.user.dto.UserEmailRequestDto
|
||||
*
|
||||
* 사용자 이메일 확인 요청 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/09/16
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/09/16 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class UserEmailRequestDto {
|
||||
|
||||
/**
|
||||
* 사용자 id
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 이메일
|
||||
*/
|
||||
@NotBlank(message = "{user.email}{valid.required}")
|
||||
@Email
|
||||
private String email;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package org.egovframe.cloud.userservice.api.user.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.egovframe.cloud.userservice.domain.user.UserFindPassword;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.user.dto.UserFindPasswordSaveRequestDto
|
||||
*
|
||||
* 사용자 비밀번호 찾기 등록 요청 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/09/15
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/09/15 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class UserFindPasswordSaveRequestDto {
|
||||
|
||||
/**
|
||||
* 사용자 명
|
||||
*/
|
||||
@NotBlank(message = "{user.user_name}{valid.required}")
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 이메일 주소
|
||||
*/
|
||||
@NotBlank(message = "{user.email}{valid.required}")
|
||||
@Email
|
||||
private String emailAddr;
|
||||
|
||||
/**
|
||||
* 메인 주소
|
||||
*/
|
||||
@NotBlank
|
||||
private String mainUrl;
|
||||
|
||||
/**
|
||||
* 비밀번호 변경 주소
|
||||
*/
|
||||
@NotBlank
|
||||
private String changePasswordUrl;
|
||||
|
||||
/**
|
||||
* 사용자 비밀번호 찾기 등록 요청 DTO 속성 값으로 개인정보처리방침 엔티티 빌더를 사용하여 객체 생성
|
||||
*
|
||||
* @return UserFindPassword 사용자 비밀번호 찾기 엔티티
|
||||
*/
|
||||
public UserFindPassword toEntity(Integer requestNo, String tokenValue) {
|
||||
return UserFindPassword.builder()
|
||||
.emailAddr(emailAddr)
|
||||
.requestNo(requestNo)
|
||||
.tokenValue(tokenValue)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.egovframe.cloud.userservice.api.user.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.user.dto.UserFindPasswordUpdateRequestDto
|
||||
*
|
||||
* 사용자 비밀번호 찾기 수정 요청 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/09/15
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/09/15 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class UserFindPasswordUpdateRequestDto {
|
||||
|
||||
/**
|
||||
* 토큰 값
|
||||
*/
|
||||
@NotBlank(message = "{common.token}{valid.required}")
|
||||
private String tokenValue;
|
||||
|
||||
/**
|
||||
* 비밀번호
|
||||
*/
|
||||
@NotBlank(message = "{user.password}{valid.required}")
|
||||
@Pattern(regexp = "(?=.*[0-9])(?=.*[a-zA-Z])(?=.*\\W)(?=\\S+$).{8,20}", message = "{valid.password}") // (숫자)(영문)(특수문자)(공백제거)(자리수)
|
||||
private String password;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.egovframe.cloud.userservice.api.user.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.user.dto.UserInfoUpdateRequestDto
|
||||
*
|
||||
* 사용자 정보 수정 요청 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/09/16
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/09/16 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class UserInfoUpdateRequestDto {
|
||||
|
||||
/**
|
||||
* 이메일
|
||||
*/
|
||||
@NotBlank(message = "{user.email}{valid.required}")
|
||||
@Email
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 사용자 명
|
||||
*/
|
||||
@NotBlank(message = "{user.user_name}{valid.required}")
|
||||
private String userName;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package org.egovframe.cloud.userservice.api.user.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.egovframe.cloud.common.domain.Role;
|
||||
import org.egovframe.cloud.userservice.domain.user.User;
|
||||
import org.egovframe.cloud.userservice.domain.user.UserStateCode;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.user.dto.UserJoinRequestDto
|
||||
*
|
||||
* 사용자 가입 요청 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/09/23
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/09/23 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class UserJoinRequestDto {
|
||||
|
||||
@NotBlank(message = "{user.user_name}{valid.required}")
|
||||
private String userName;
|
||||
|
||||
@NotBlank(message = "{user.email}{valid.required}")
|
||||
@Email
|
||||
private String email;
|
||||
|
||||
// (숫자)(영문)(특수문자)(공백제거)(자리수)
|
||||
@Pattern(regexp = "(?=.*[0-9])(?=.*[a-zA-Z])(?=.*\\W)(?=\\S+$).{8,20}",
|
||||
message = "{valid.password}")
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* UserSaveRequestDto 의 필드 값을 User Entity 빌더를 사용하여 주입 후 User를 리턴한다.
|
||||
* UserSaveRequestDto 가 가지고 있는 User 의 필드만 세팅할 수 있게 된다.
|
||||
*
|
||||
* @param passwordEncoder
|
||||
* @return
|
||||
*/
|
||||
public User toEntity(BCryptPasswordEncoder passwordEncoder) {
|
||||
return User.builder()
|
||||
.userName(userName)
|
||||
.email(email)
|
||||
.encryptedPassword(passwordEncoder.encode(password)) // 패스워드 인코딩
|
||||
.userId(UUID.randomUUID().toString()) // 사용자 아이디 랜덤하게 생성
|
||||
.role(Role.USER) // 가입 시 기본 권한
|
||||
.userStateCode(UserStateCode.NORMAL.getKey()) // 승인 절차 없이 정상 상태로 가입
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package org.egovframe.cloud.userservice.api.user.dto;
|
||||
|
||||
import com.querydsl.core.annotations.QueryProjection;
|
||||
import lombok.Getter;
|
||||
import org.egovframe.cloud.common.domain.Role;
|
||||
import org.egovframe.cloud.userservice.domain.user.User;
|
||||
import org.egovframe.cloud.userservice.domain.user.UserStateCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.user.dto.UserListResponseDto
|
||||
* <p>
|
||||
* 사용자 목록 요청시 사용되는 필요한 정보만 담긴 DTO
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/06/30
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/06/30 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
public class UserListResponseDto {
|
||||
private String userId;
|
||||
private String userName;
|
||||
private String email;
|
||||
private String roleId;
|
||||
private String roleName;
|
||||
private String userStateCode;
|
||||
private String userStateCodeName;
|
||||
private LocalDateTime lastLoginDate;
|
||||
private Integer loginFailCount;
|
||||
|
||||
/**
|
||||
* UserListResponseDto 는 Entity의 필드 중 일부만 사용하므로 생성자로 Entity를 받아 필드에 값을 넣는다.
|
||||
* 굳이 모든 필드를 가진 생성자가 필요하지 않다.
|
||||
*
|
||||
* @param entity
|
||||
*/
|
||||
public UserListResponseDto(User entity) {
|
||||
this.userId = entity.getUserId();
|
||||
this.userName = entity.getUserName();
|
||||
this.email = entity.getEmail();
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 목록 응답 DTO 생성자
|
||||
*
|
||||
* @param userId 사용자 id
|
||||
* @param userName 사용자 명
|
||||
* @param email 이메일 주소
|
||||
* @param role 권한
|
||||
* @param userStateCode 사용자 상태 코드
|
||||
* @param lastLoginDate 마지막 로그인 일시
|
||||
* @param loginFailCount 로그인 실패 수
|
||||
*/
|
||||
@QueryProjection
|
||||
public UserListResponseDto(String userId, String userName, String email, Role role, String userStateCode, LocalDateTime lastLoginDate, Integer loginFailCount) {
|
||||
this.userId = userId;
|
||||
this.userName = userName;
|
||||
this.email = email;
|
||||
this.roleId = role.getKey();
|
||||
this.roleName = role.getTitle();
|
||||
UserStateCode usc = UserStateCode.findByKey(userStateCode);
|
||||
this.userStateCode = usc.getKey();
|
||||
this.userStateCodeName = usc.getTitle();
|
||||
this.lastLoginDate = lastLoginDate;
|
||||
this.loginFailCount = loginFailCount;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package org.egovframe.cloud.userservice.api.user.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.user.dto.UserLoginRequestDto
|
||||
* <p>
|
||||
* 로그인 요청시 사용되는 필요한 정보만 담긴 DTO
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/06/30
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/06/30 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class UserLoginRequestDto {
|
||||
|
||||
/**
|
||||
* 이메일
|
||||
*/
|
||||
@Email
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 비밀번호
|
||||
*/
|
||||
// (숫자)(영문)(특수문자)(공백제거)(자리수)
|
||||
@Pattern(regexp = "(?=.*[0-9])(?=.*[a-zA-Z])(?=.*\\W)(?=\\S+$).{8,20}",
|
||||
message = "{valid.password}")
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 공급자
|
||||
*/
|
||||
@NotBlank(message = "{common.provider}{valid.required}")
|
||||
private String provider;
|
||||
|
||||
/**
|
||||
* 토큰
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 이름
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 사용자 로그인 요청 DTO 클래스 생성자
|
||||
* 빌더 패턴으로 객체 생성
|
||||
*
|
||||
* @param email 이메일
|
||||
* @param password 비밀번호
|
||||
* @param provider 공급자
|
||||
* @param token 토큰
|
||||
*/
|
||||
@Builder
|
||||
public UserLoginRequestDto(String email, String password, String provider, String token, String name) {
|
||||
this.email = email;
|
||||
this.password = password;
|
||||
this.provider = provider;
|
||||
this.token = token;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* OAuth 로그인 정보 세팅
|
||||
*
|
||||
* @param email
|
||||
* @param password
|
||||
*/
|
||||
public void setOAuthLoginInfo(String email, String password) {
|
||||
this.email = email;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.egovframe.cloud.userservice.api.user.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.user.dto.UserPasswordMatchRequestDto
|
||||
*
|
||||
* 사용자 비밀번호 확인 요청 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/09/16
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/09/16 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class UserPasswordMatchRequestDto {
|
||||
|
||||
/**
|
||||
* 비밀번호
|
||||
*/
|
||||
@NotBlank(message = "{label.title.current_password}{valid.required}")
|
||||
@Pattern(regexp = "(?=.*[0-9])(?=.*[a-zA-Z])(?=.*\\W)(?=\\S+$).{8,20}", message = "{valid.password}") // (숫자)(영문)(특수문자)(공백제거)(자리수)
|
||||
private String password;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.egovframe.cloud.userservice.api.user.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.user.dto.UserPasswordUpdateRequestDto
|
||||
* <p>
|
||||
* 사용자 비밀번호 변경 요청 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/09/16
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/09/16 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class UserPasswordUpdateRequestDto extends UserVerifyRequestDto {
|
||||
|
||||
/**
|
||||
* 신규 비밀번호
|
||||
*/
|
||||
@Pattern(regexp = "(?=.*[0-9])(?=.*[a-zA-Z])(?=.*\\W)(?=\\S+$).{8,20}", message = "{valid.password}")
|
||||
// (숫자)(영문)(특수문자)(공백제거)(자리수)
|
||||
private String newPassword;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.egovframe.cloud.userservice.api.user.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.egovframe.cloud.userservice.domain.user.User;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.user.dto.UserResponseDto
|
||||
* <p>
|
||||
* 사용자 정보 요청시 사용되는 필요한 정보만 담긴 DTO
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/06/30
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/06/30 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
public class UserResponseDto {
|
||||
|
||||
private String userId;
|
||||
private String userName;
|
||||
private String email;
|
||||
private String roleId;
|
||||
private String userStateCode;
|
||||
private String googleId;
|
||||
private String kakaoId;
|
||||
private String naverId;
|
||||
private Boolean isSocialUser;
|
||||
private Boolean hasPassword;
|
||||
|
||||
/**
|
||||
* UserResponseDto는 Entity의 필드 중 일부만 사용하므로 생성자로 Entity를 받아 필드에 값을 넣는다.
|
||||
* 굳이 모든 필드를 가진 생성자가 필요하지 않다.
|
||||
*
|
||||
* @param entity
|
||||
*/
|
||||
public UserResponseDto(User entity) {
|
||||
this.userId = entity.getUserId();
|
||||
this.userName = entity.getUserName();
|
||||
this.email = entity.getEmail();
|
||||
this.roleId = entity.getRoleKey();
|
||||
this.userStateCode = entity.getUserStateCode();
|
||||
this.googleId = entity.getGoogleId();
|
||||
this.kakaoId = entity.getKakaoId();
|
||||
this.naverId = entity.getNaverId();
|
||||
this.isSocialUser = entity.isSocialUser();
|
||||
this.hasPassword = entity.getEncryptedPassword() != null && !"".equals(entity.getEncryptedPassword());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package org.egovframe.cloud.userservice.api.user.dto;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
import org.egovframe.cloud.common.domain.Role;
|
||||
import org.egovframe.cloud.userservice.domain.user.User;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.user.dto.UserSaveRequestDto
|
||||
* <p>
|
||||
* 사용자 정보 생성 요청시 처리 가능한 정보만 담긴 DTO
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/06/30
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/06/30 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class UserSaveRequestDto {
|
||||
|
||||
@NotBlank(message = "{user.user_name}{valid.required}")
|
||||
private String userName;
|
||||
|
||||
@NotBlank(message = "{user.email}{valid.required}")
|
||||
@Email
|
||||
private String email;
|
||||
|
||||
// (숫자)(영문)(특수문자)(공백제거)(자리수)
|
||||
@Pattern(regexp = "(?=.*[0-9])(?=.*[a-zA-Z])(?=.*\\W)(?=\\S+$).{8,20}",
|
||||
message = "{valid.password}")
|
||||
private String password;
|
||||
|
||||
@NotBlank(message = "{role}{valid.required}")
|
||||
private String roleId;
|
||||
|
||||
@NotBlank(message = "{user.user_state_code}{valid.required}")
|
||||
private String userStateCode;
|
||||
|
||||
@Builder
|
||||
public UserSaveRequestDto(String userName, String email, String password, String roleId, String userStateCode) {
|
||||
this.userName = userName;
|
||||
this.email = email;
|
||||
this.password = password;
|
||||
this.roleId = roleId;
|
||||
this.userStateCode = userStateCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* UserSaveRequestDto 의 필드 값을 User Entity 빌더를 사용하여 주입 후 User를 리턴한다.
|
||||
* UserSaveRequestDto 가 가지고 있는 User 의 필드만 세팅할 수 있게 된다.
|
||||
*
|
||||
* @param passwordEncoder
|
||||
* @return
|
||||
*/
|
||||
public User toEntity(BCryptPasswordEncoder passwordEncoder) {
|
||||
return User.builder()
|
||||
.userName(userName)
|
||||
.email(email)
|
||||
.encryptedPassword(passwordEncoder.encode(password)) // 패스워드 인코딩
|
||||
.userId(UUID.randomUUID().toString()) // 사용자 아이디 랜덤하게 생성
|
||||
.role(Arrays.stream(Role.values()).filter(c -> c.getKey().equals(roleId)).findAny().orElse(null))
|
||||
.userStateCode(userStateCode)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.egovframe.cloud.userservice.api.user.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.user.dto.UserUpdateInfoRequestDto
|
||||
* <p>
|
||||
* 사용자 정보 수정 요청 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/09/23
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/09/23 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class UserUpdateInfoRequestDto extends UserVerifyRequestDto {
|
||||
|
||||
@NotBlank(message = "{user.user_name}{valid.required}")
|
||||
private String userName;
|
||||
|
||||
@NotBlank(message = "{user.email}{valid.required}")
|
||||
@Email
|
||||
private String email;
|
||||
|
||||
@Builder
|
||||
public UserUpdateInfoRequestDto(String userName, String email) {
|
||||
this.userName = userName;
|
||||
this.email = email;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.egovframe.cloud.userservice.api.user.dto;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.user.dto.UserUpdateRequestDto
|
||||
* <p>
|
||||
* 사용자 정보 수정 요청시 처리 가능한 정보만 담긴 DTO
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/06/30
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/06/30 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class UserUpdateRequestDto {
|
||||
|
||||
@NotBlank(message = "{user.user_name}{valid.required}")
|
||||
private String userName;
|
||||
|
||||
@NotBlank(message = "{user.email}{valid.required}")
|
||||
@Email
|
||||
private String email;
|
||||
|
||||
// (숫자)(영문)(특수문자)(공백제거)(자리수)
|
||||
@Pattern(regexp = "((?=.*[0-9])(?=.*[a-zA-Z])(?=.*\\W)(?=\\S+$).{8,20})|()",
|
||||
message = "{valid.password}")
|
||||
private String password;
|
||||
|
||||
@NotBlank(message = "{role}{valid.required}")
|
||||
private String roleId;
|
||||
|
||||
@NotBlank(message = "{user.user_state_code}{valid.required}")
|
||||
private String userStateCode;
|
||||
|
||||
@Builder
|
||||
public UserUpdateRequestDto(String userName, String email, String password, String roleId, String userStateCode) {
|
||||
this.userName = userName;
|
||||
this.email = email;
|
||||
this.password = password;
|
||||
this.roleId = roleId;
|
||||
this.userStateCode = userStateCode;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.egovframe.cloud.userservice.api.user.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.user.dto.UserVerifyRequestDto
|
||||
*
|
||||
* 사용자 탈퇴 요청 DTO 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/09/16
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/09/16 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class UserVerifyRequestDto {
|
||||
|
||||
/**
|
||||
* 비밀번호
|
||||
*/
|
||||
@Pattern(regexp = "((?=.*[0-9])(?=.*[a-zA-Z])(?=.*\\W)(?=\\S+$).{8,20})|()", message = "{valid.password}") // (숫자)(영문)(특수문자)(공백제거)(자리수)
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 공급자
|
||||
*/
|
||||
@NotBlank(message = "{common.provider}{valid.required}")
|
||||
private String provider;
|
||||
|
||||
/**
|
||||
* 토큰
|
||||
*/
|
||||
private String token;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
package org.egovframe.cloud.userservice.config;
|
||||
|
||||
import static org.egovframe.cloud.common.config.GlobalConstant.LOGIN_URI;
|
||||
import static org.springframework.util.StringUtils.hasLength;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.egovframe.cloud.common.util.LogUtil;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserLoginRequestDto;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserResponseDto;
|
||||
import org.egovframe.cloud.userservice.service.user.UserService;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.InternalAuthenticationServiceException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.config.AuthenticationFilter
|
||||
* <p>
|
||||
* Spring Security AuthenticationFilter 처리
|
||||
* 로그인 인증정보를 받아 토큰을 발급한다
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/06/30
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/06/30 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Slf4j
|
||||
public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
|
||||
|
||||
private final TokenProvider tokenProvider;
|
||||
private final UserService userService;
|
||||
|
||||
public AuthenticationFilter(AuthenticationManager authenticationManager, TokenProvider tokenProvider, UserService userService) {
|
||||
super.setAuthenticationManager(authenticationManager);
|
||||
this.tokenProvider = tokenProvider;
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 로그인 요청 시 호출되는 메소드이다.
|
||||
* 계정 정보를 받아 인증정보를 생성한다.
|
||||
*
|
||||
* @param request http 요청
|
||||
* @param response http 응답
|
||||
* @return Authentication 인증정보
|
||||
* @throws NullPointerException 널 포인터 예외
|
||||
* @throws Exception 예외
|
||||
*/
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
|
||||
try {
|
||||
// 사용자가 입력한 인증정보 받기, POST method 값이기 때문에 input stream으로 받았다.
|
||||
UserLoginRequestDto creds = new ObjectMapper().readValue(request.getInputStream(), UserLoginRequestDto.class);
|
||||
|
||||
UsernamePasswordAuthenticationToken upat = null;
|
||||
if (creds.getProvider() != null && !"email".equals(creds.getProvider())) {
|
||||
UserResponseDto userDto = userService.loadUserBySocial(creds);
|
||||
|
||||
upat = new UsernamePasswordAuthenticationToken(
|
||||
userDto.getEmail(),
|
||||
null,
|
||||
AuthorityUtils.createAuthorityList(userDto.getRoleId())
|
||||
);
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(upat);
|
||||
|
||||
return upat;
|
||||
} else {
|
||||
upat = new UsernamePasswordAuthenticationToken(
|
||||
creds.getEmail(),
|
||||
creds.getPassword(),
|
||||
new ArrayList<>()
|
||||
);
|
||||
|
||||
// 인증정보 만들기
|
||||
return getAuthenticationManager().authenticate(upat);
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
log.error(e.getLocalizedMessage());
|
||||
throw new RuntimeException(e);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getLocalizedMessage());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 로그인 인증 성공 후 호출된다.
|
||||
* 토큰을 생성하여 헤더에 토큰 정보를 담는다.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param chain
|
||||
* @param authResult
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
@Transactional
|
||||
@Override
|
||||
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
|
||||
// 토큰 생성 및 response header add
|
||||
tokenProvider.createTokenAndAddHeader(request, response, chain, authResult);
|
||||
// 로그인 성공 후처리
|
||||
userService.loginCallback(LogUtil.getSiteId(request), authResult.getName(), true, "");
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
|
||||
String failContent = failed.getMessage();
|
||||
if (failed instanceof InternalAuthenticationServiceException) {
|
||||
log.info("{} 해당 사용자가 없습니다", request.getAttribute("email"));
|
||||
} else if (failed instanceof BadCredentialsException) {
|
||||
failContent = "패스워드 인증에 실패하였습니다. " + failContent;
|
||||
}
|
||||
response.setStatus(HttpStatus.UNAUTHORIZED.value());
|
||||
|
||||
// 로그인 실패 후처리
|
||||
String email = (String) request.getAttribute("email");
|
||||
userService.loginCallback(LogUtil.getSiteId(request), email, false, failContent);
|
||||
super.unsuccessfulAuthentication(request, response, failed);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 로그인 요청 뿐만 아니라 모든 요청시마다 호출된다.
|
||||
* 토큰에 담긴 정보로 Authentication 정보를 설정한다.
|
||||
* 이 처리를 하지 않으면 AnonymousAuthenticationToken 으로 처리된다.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param chain
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||
String token = httpRequest.getHeader(HttpHeaders.AUTHORIZATION);
|
||||
if (!hasLength(token) || "undefined".equals(token)) {
|
||||
super.doFilter(request, response, chain);
|
||||
} else {
|
||||
try {
|
||||
final String requestURI = httpRequest.getRequestURI();
|
||||
log.info("httpRequest.getRequestURI() ={}", requestURI);
|
||||
|
||||
if (LOGIN_URI.equals(requestURI)) {
|
||||
// 로그인 등 토큰 정보를 꺼낼 필요가 없는 경우
|
||||
SecurityContextHolder.getContext().setAuthentication(null);
|
||||
} else {
|
||||
// 토큰 유효성 검사는 API Gateway ReactiveAuthorization 클래스에서 미리 처리된다.
|
||||
Claims claims = tokenProvider.getClaimsFromToken(token);
|
||||
|
||||
String username = claims.getSubject();
|
||||
if (username == null) {
|
||||
// refresh token 에는 subject, authorities 정보가 없다.
|
||||
SecurityContextHolder.getContext().setAuthentication(null);
|
||||
} else {
|
||||
List<SimpleGrantedAuthority> roleList = Arrays.stream(claims.get(tokenProvider.TOKEN_CLAIM_NAME, String.class).split(","))
|
||||
.map(SimpleGrantedAuthority::new)
|
||||
.collect(Collectors.toList());
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(username, null, roleList));
|
||||
}
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
|
||||
} catch (Exception e) {
|
||||
SecurityContextHolder.getContext().setAuthentication(null);
|
||||
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
|
||||
httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
|
||||
log.error("AuthenticationFilter doFilter", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.egovframe.cloud.userservice.config;
|
||||
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.config.CacheConfig
|
||||
*
|
||||
* 캐시 설정 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/21
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/21 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
@EnableAspectJAutoProxy(exposeProxy=true) // AopContext.currentProxy() 사용 옵션
|
||||
public class CacheConfig {
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.egovframe.cloud.userservice.config;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.ehcache.event.CacheEvent;
|
||||
import org.ehcache.event.CacheEventListener;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.config.CacheEventLogger
|
||||
*
|
||||
* 캐시 이밴트 로깅 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/22
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/22 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Slf4j
|
||||
public class CacheEventLogger implements CacheEventListener<Object, Object> {
|
||||
|
||||
/**
|
||||
* 캐시 이벤트 발생시 로깅
|
||||
*
|
||||
* @param cacheEvent 캐시 이벤트
|
||||
*/
|
||||
public void onEvent(CacheEvent<? extends Object, ? extends Object> cacheEvent) {
|
||||
log.info("cache event ::: key: {} / oldvalue: {} / newvalue:{}", cacheEvent.getKey(), cacheEvent.getOldValue(), cacheEvent.getNewValue());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.egovframe.cloud.userservice.config;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.config.CustomOAuth2SuccessHandler
|
||||
* <p>
|
||||
* OAuth2 인증 성공 시 호출된다.
|
||||
* 로그인 인증정보를 받아 토큰을 발급한다
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/07/01
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/01 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
public class CustomOAuth2SuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
|
||||
|
||||
private final TokenProvider tokenProvider;
|
||||
|
||||
/**
|
||||
* 인증 시 토큰 생성
|
||||
* @param request
|
||||
* @param response
|
||||
* @param chain
|
||||
* @param authentication
|
||||
* @throws IOException
|
||||
* @throws ServletException
|
||||
*/
|
||||
@Override
|
||||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException {
|
||||
tokenProvider.createTokenAndAddHeader(request, response, chain, authentication);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package org.egovframe.cloud.userservice.config;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.egovframe.cloud.userservice.config.dto.OAuthAttributes;
|
||||
import org.egovframe.cloud.userservice.domain.user.User;
|
||||
import org.egovframe.cloud.userservice.domain.user.UserRepository;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.config.CustomOAuth2UserService
|
||||
* <p>
|
||||
* OAuth2 로그인 이후 가져온 사용자의 정보들을 기반으로 가입 및 정보수정, 세션 저장 등의 기능을 지원
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/06/30
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/06/30 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
|
||||
private final UserRepository userRepository;
|
||||
// private final HttpSession httpSession;
|
||||
|
||||
/**
|
||||
* OAuth2 로그인 이후 호출되어 사용자 정보를 DB에 입력한다.
|
||||
*
|
||||
* @param userRequest
|
||||
* @return
|
||||
* @throws OAuth2AuthenticationException
|
||||
*/
|
||||
@Override
|
||||
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
|
||||
OAuth2UserService delegate = new DefaultOAuth2UserService();
|
||||
OAuth2User oAuth2User = delegate.loadUser(userRequest);
|
||||
|
||||
// 현재 로그인 진행 중인 서비스를 구분하는 코드(구글 or 네이버..)
|
||||
String registrationId = userRequest.getClientRegistration().getRegistrationId();
|
||||
// OAuth2 로그인 진행시 키가 되는 필드 값(PK). 구글만 기본적으로 기본 코드(sub)를 지원.
|
||||
String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName();
|
||||
|
||||
// OAuth2UserService를 통해 가져온 OAuth2User의 attributes를 담을 클래스
|
||||
OAuthAttributes attributes = OAuthAttributes.of(registrationId, userNameAttributeName, oAuth2User.getAttributes());
|
||||
|
||||
User user = saveOrUpdate(attributes);
|
||||
// 세션에 저장하는 경우 활성화한다
|
||||
// httpSession.setAttribute("user", new SessionUser(user));
|
||||
|
||||
return new DefaultOAuth2User(
|
||||
Collections.singleton(new SimpleGrantedAuthority(user.getRoleKey())),
|
||||
attributes.getAttributes(),
|
||||
attributes.getNameAttributeKey()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* OAuth2 사용자 정보가 변경는 경우 반영
|
||||
*
|
||||
* @param attributes
|
||||
* @return
|
||||
*/
|
||||
private User saveOrUpdate(OAuthAttributes attributes) {
|
||||
User user = userRepository.findByEmail(attributes.getEmail())
|
||||
.map(entity -> entity.updateInfo(attributes.getUserName(), attributes.getEmail()))
|
||||
.orElse(attributes.toEntity());
|
||||
|
||||
return userRepository.save(user);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.egovframe.cloud.userservice.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.config.RestTemplateConfig
|
||||
*
|
||||
* REST Template 설정 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/09/27
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/09/27 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Configuration
|
||||
public class RestTemplateConfig {
|
||||
|
||||
/**
|
||||
* REST Template 빈 등록
|
||||
*
|
||||
* @return RestTemplate REST Template
|
||||
*/
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
return new RestTemplate();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package org.egovframe.cloud.userservice.config;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.egovframe.cloud.userservice.service.user.UserService;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
import static org.egovframe.cloud.common.config.GlobalConstant.SECURITY_PERMITALL_ANTPATTERNS;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.SecurityConfig
|
||||
* <p>
|
||||
* Spring Security Config 클래스
|
||||
* AuthenticationFilter 를 추가하고 로그인 인증처리를 한다
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/06/30
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/06/30 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@EnableWebSecurity // Spring Security 설정들을 활성화시켜 준다
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private final TokenProvider tokenProvider;
|
||||
private final UserService userService;
|
||||
private final BCryptPasswordEncoder bCryptPasswordEncoder;
|
||||
|
||||
/**
|
||||
* 스프링 시큐리티 설정
|
||||
*
|
||||
* @param http
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.csrf().disable()
|
||||
.headers().frameOptions().disable()
|
||||
.and()
|
||||
.sessionManagement()
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 토큰 사용하기 때문에 세션은 비활성화
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.antMatchers(SECURITY_PERMITALL_ANTPATTERNS).permitAll()
|
||||
.anyRequest().access("@authorizationService.isAuthorization(request, authentication)") // 호출 시 권한 인가 데이터 확인
|
||||
.and()
|
||||
.addFilter(getAuthenticationFilter())
|
||||
.logout()
|
||||
.logoutSuccessUrl("/");
|
||||
}
|
||||
|
||||
/**
|
||||
* 로그인 인증정보를 받아 토큰을 발급할 수 있도록 필터를 등록해준다.
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private AuthenticationFilter getAuthenticationFilter() throws Exception {
|
||||
return new AuthenticationFilter(authenticationManager(), tokenProvider, userService);
|
||||
}
|
||||
|
||||
/**
|
||||
* 인증 관련 - 로그인 처리
|
||||
* DB 에서 조회하여 일치하는지 체크한다.
|
||||
*
|
||||
* @param auth
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
// userService.loadUserByUsername 메소드
|
||||
auth.userDetailsService(userService).passwordEncoder(bCryptPasswordEncoder);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
package org.egovframe.cloud.userservice.config;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserResponseDto;
|
||||
import org.egovframe.cloud.userservice.service.user.UserService;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Date;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.config.TokenProvider
|
||||
* <p>
|
||||
* 로그인 성공 인증정보로 토큰을 생성한다.
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/07/01
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/01 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Component
|
||||
public class TokenProvider {
|
||||
|
||||
private final UserService userService;
|
||||
|
||||
public TokenProvider(UserService userService) {
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@Value("${token.secret}")
|
||||
private String TOKEN_SECRET;
|
||||
|
||||
@Value("${token.expiration_time}")
|
||||
private String TOKEN_EXPIRATION_TIME;
|
||||
|
||||
@Value("${token.refresh_time}")
|
||||
private String TOKEN_REFRESH_TIME;
|
||||
|
||||
final String TOKEN_CLAIM_NAME = "authorities";
|
||||
final String TOKEN_ACCESS_KEY = "access-token";
|
||||
final String TOKEN_REFRESH_KEY = "refresh-token";
|
||||
final String TOKEN_USER_ID = "token-id";
|
||||
|
||||
/**
|
||||
* 로그인 후 토큰을 생성하고 헤더에 정보를 담는다.
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param chain
|
||||
* @param authResult
|
||||
*/
|
||||
public void createTokenAndAddHeader(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) {
|
||||
// 로그인 성공 후 토큰 처리
|
||||
String email = authResult.getName();
|
||||
String authorities = authResult.getAuthorities().stream()
|
||||
.map(GrantedAuthority::getAuthority)
|
||||
.collect(Collectors.joining(","));
|
||||
|
||||
// userid 가져오기
|
||||
UserResponseDto userResponseDto = userService.findByEmail(email);
|
||||
String userId = userResponseDto.getUserId();
|
||||
|
||||
// JWT Access 토큰 생성
|
||||
String accessToken = createAccessToken(authorities, userId);
|
||||
|
||||
// JWT Refresh 토큰 생성 후 사용자 도메인에 저장하여 토큰 재생성 요청시 활용한다.
|
||||
String refreshToken = createRefreshToken();
|
||||
userService.updateRefreshToken(userId, refreshToken);
|
||||
|
||||
// Header에 토큰 세팅
|
||||
response.addHeader(TOKEN_ACCESS_KEY, accessToken);
|
||||
response.addHeader(TOKEN_REFRESH_KEY, refreshToken);
|
||||
response.addHeader(TOKEN_USER_ID, userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* JWT Access Token 생성
|
||||
*
|
||||
* @param authorities
|
||||
* @param userId
|
||||
* @return
|
||||
*/
|
||||
private String createAccessToken(String authorities, String userId) {
|
||||
return Jwts.builder()
|
||||
.setSubject(userId)
|
||||
.claim(TOKEN_CLAIM_NAME, authorities)
|
||||
.setExpiration(new Date(System.currentTimeMillis() + Long.parseLong(TOKEN_EXPIRATION_TIME)))
|
||||
.signWith(SignatureAlgorithm.HS512, TOKEN_SECRET)
|
||||
.compact();
|
||||
}
|
||||
|
||||
/**
|
||||
* JWT Refresh Token 생성
|
||||
* 중복 로그인을 허용하려면 user domain 에 있는 refresh token 값을 반환하고 없는 경우에만 생성하도록 처리한다.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private String createRefreshToken() {
|
||||
return Jwts.builder()
|
||||
.setExpiration(new Date(System.currentTimeMillis() + Long.parseLong(TOKEN_REFRESH_TIME)))
|
||||
.signWith(SignatureAlgorithm.HS512, TOKEN_SECRET)
|
||||
.compact();
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자가 있으면 access token 을 새로 발급하여 리턴한다.
|
||||
*
|
||||
* @param refreshToken
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
public String refreshToken(String refreshToken, HttpServletResponse response) {
|
||||
// refresh token 으로 유효한 사용자가 있는지 찾는다.
|
||||
org.egovframe.cloud.userservice.domain.user.User user = userService.findByRefreshToken(refreshToken);
|
||||
// 사용자가 있으면 access token 을 새로 발급하여 리턴한다.
|
||||
String accessToken = createAccessToken(user.getRoleKey(), user.getUserId());
|
||||
|
||||
// Header에 토큰 세팅
|
||||
response.addHeader(TOKEN_ACCESS_KEY, accessToken);
|
||||
response.addHeader(TOKEN_REFRESH_KEY, refreshToken);
|
||||
response.addHeader(TOKEN_USER_ID, user.getUserId());
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* AuthenticationFilter.doFilter 메소드에서 UsernamePasswordAuthenticationToken 정보를 세팅할 때 호출된다.
|
||||
*
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
public Claims getClaimsFromToken(String token) {
|
||||
return Jwts.parser()
|
||||
.setSigningKey(TOKEN_SECRET)
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package org.egovframe.cloud.userservice.config;
|
||||
|
||||
public class UserPasswordChangeEmailTemplate {
|
||||
|
||||
/**
|
||||
* 객체 생성 금지
|
||||
*/
|
||||
private UserPasswordChangeEmailTemplate() {
|
||||
throw new IllegalStateException("user password change email template class");
|
||||
}
|
||||
|
||||
public static final String html = "<style type=\"text/css\">\n"
|
||||
+ " @import url(http://fonts.googleapis.com/earlyaccess/notosanskr.css);\n"
|
||||
+ " body {font-family:\"Noto Sans KR\", \"맑은 고딕\", sans-serif; font-weight:400; font-size:14px; color:#333; line-height:18px; -webkit-text-size-adjust:100%%; -moz-text-size-adjust:100%%; -ms-text-size-adjust:100%%;}\n"
|
||||
+ "</style>\n"
|
||||
+ "<div style=\"width:100%%; max-width:800px; margin:0 auto;\">\n"
|
||||
+ " <a href=\"%s\" target=\"_blank\" style=\"display:block; margin:35px;\"><div><img src=\"https://user-images.githubusercontent.com/80671095/130181337-16d978c6-71c4-4759-82b3-9a542f4c1aad.png\" alt=\"표준프레임워크 포털로고\" style=\"width:170px;\"></div></a>\n"
|
||||
+ " <table width=\"100%%\" align=\"center\" cellspacing=\"0\" border=\"0\" bgcolor=\"#fff\" style=\"margin:0 auto; border:35px solid #eee;\">\n"
|
||||
+ " <colgroup>\n"
|
||||
+ " <col width=\"165\">\n"
|
||||
+ " <col width=\"400\">\n"
|
||||
+ " <col width=\"165\">\n"
|
||||
+ " </colgroup>\n"
|
||||
+ " <thead>\n"
|
||||
+ " <tr>\n"
|
||||
+ " <th></th>\n"
|
||||
+ " <th height=\"100\"></th>\n"
|
||||
+ " <th></th>\n"
|
||||
+ " </tr>\n"
|
||||
+ " <tr>\n"
|
||||
+ " <th></th>\n"
|
||||
+ " <th align=\"center\" style=\"font-size:40px; font-weight:600;\">비밀번호 초기화 안내</th>\n"
|
||||
+ " <th></th>\n"
|
||||
+ " </tr>\n"
|
||||
+ " <tr>\n"
|
||||
+ " <th></th>\n"
|
||||
+ " <th height=\"40\" style=\"border-bottom:1px solid #e8e8e8\"></th>\n"
|
||||
+ " <th></th>\n"
|
||||
+ " </tr>\n"
|
||||
+ " </thead>\n"
|
||||
+ " <tbody>\n"
|
||||
+ " <tr>\n"
|
||||
+ " <td colspan=\"3\" height=\"60\"></td>\n"
|
||||
+ " </tr>\n"
|
||||
+ " <tr>\n"
|
||||
+ " <td colspan=\"3\" style=\"padding-left:45px; color:#666; font-size:24px; line-height:36px;\">\n"
|
||||
+ " 안녕하세요. <b style=\"color:#333;\">%s</b> 회원님.<br /><br />\n"
|
||||
+ " 비밀번호 초기화 관련하여 안내드립니다.<br />\n"
|
||||
+ " 회원님의 계정 비밀번호를 초기화할 수 있는 URL을 알려드립니다.<br /><br />\n"
|
||||
+ " <span style=\"color:#1e75d6; font-weight:600;\">[비밀번호 초기화] 버튼</span>으로 접속하여 비밀번호를 초기화 하신 후<br />서비스를 계속해서 이용해주시기 바랍니다.<br /><br />\n"
|
||||
+ " 해당 링크는 발송후 1시간 동안만 유효합니다.<br /><br />\n"
|
||||
+ " 감사합니다.\n"
|
||||
+ " </td>\n"
|
||||
+ " </tr>\n"
|
||||
+ " <tr>\n"
|
||||
+ " <td colspan=\"3\" height=\"60\"></td>\n"
|
||||
+ " </tr>\n"
|
||||
+ " <tr>\n"
|
||||
+ " <td colspan=\"3\" align=\"center\">\n"
|
||||
+ " <a href=\"%s\" target=\"_blank\" style=\"height:60px; padding:10px 50px; color:#fff; font-size:20px; font-weight:600; text-align:center; line-height:58px; border:0; background:#1e75d6; border-radius:5px; text-decoration: none;\">비밀번호 초기화</a>\n"
|
||||
+ " </td>\n"
|
||||
+ " </tr>\n"
|
||||
+ " <tr>\n"
|
||||
+ " <td colspan=\"3\" height=\"100\"></td>\n"
|
||||
+ " </tr>\n"
|
||||
+ " </tbody>\n"
|
||||
+ " </table>\n"
|
||||
+ " <div style=\"padding:25px 0; color:#999; font-size:15px; text-align:center; line-height:28px;\">\n"
|
||||
+ " (C) 표준프레임워크 포털 All Rights Reserved.\n"
|
||||
+ " </div>\n"
|
||||
+ "</div>\n";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package org.egovframe.cloud.userservice.config.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import org.egovframe.cloud.common.domain.Role;
|
||||
import org.egovframe.cloud.userservice.domain.user.User;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
public class OAuthAttributes {
|
||||
private Map<String, Object> attributes;
|
||||
private String nameAttributeKey;
|
||||
private String userName;
|
||||
private String email;
|
||||
|
||||
@Builder
|
||||
public OAuthAttributes(Map<String, Object> attributes,
|
||||
String nameAttributeKey, String userName, String email) {
|
||||
// public으로 선언된 데이터가 private 선언된 배열에 저장되지 않도록 한다.(reference가 아닌, “값”을 할당함으로써 private 멤버로서의 접근권한을 유지 시켜준다.)
|
||||
this.attributes = new HashMap<>();
|
||||
attributes.forEach((k, v) -> this.attributes.put(k, attributes.get(k)));
|
||||
this.nameAttributeKey = nameAttributeKey;
|
||||
this.userName = userName;
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
// OAuth2User에서 반환하는 사용자 정보는 Map이기 때문에 값 하나하나를 변환해야만 한다.
|
||||
public static OAuthAttributes of(String registrationId, String userNameAttributeName, Map<String, Object> attributes) {
|
||||
if ("naver".equals(registrationId)) {
|
||||
return ofNaver("id", attributes);
|
||||
}
|
||||
return ofGoogle(userNameAttributeName, attributes);
|
||||
}
|
||||
|
||||
private static OAuthAttributes ofGoogle(String userNameAttributeName, Map<String, Object> attributes) {
|
||||
return OAuthAttributes.builder()
|
||||
.userName((String) attributes.get("name"))
|
||||
.email((String) attributes.get("email"))
|
||||
.attributes(attributes)
|
||||
.nameAttributeKey(userNameAttributeName)
|
||||
.build();
|
||||
}
|
||||
|
||||
private static OAuthAttributes ofNaver(String userNameAttributeName, Map<String, Object> attributes) {
|
||||
Map<String, Object> response = (Map<String, Object>) attributes.get("response");
|
||||
return OAuthAttributes.builder()
|
||||
.userName((String) response.get("name"))
|
||||
.email((String) response.get("email"))
|
||||
.attributes(response)
|
||||
.nameAttributeKey(userNameAttributeName)
|
||||
.build();
|
||||
}
|
||||
|
||||
// User 엔티티 생성
|
||||
// OAuthAttributes에서 엔티티를 생성하는 시점은 처음 가입할 때이다.
|
||||
// 가입할 때의 기본 권한을 USER 변경함
|
||||
public User toEntity() {
|
||||
return User.builder()
|
||||
.userName(userName)
|
||||
.email(email)
|
||||
.role(Role.ANONYMOUS)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.egovframe.cloud.userservice.config.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.egovframe.cloud.userservice.domain.user.User;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.config.dto.SessionUser
|
||||
* <p>
|
||||
* session 에 담을 사용자 정보
|
||||
* session 에 저장하기 위해 직렬화를 구현하였다
|
||||
* 토큰 사용시에는 사용되지 않는다.
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/07/06
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/06 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
public class SessionUser implements Serializable {
|
||||
private String userName;
|
||||
private String email;
|
||||
|
||||
// 인증된 사용자 정보만 필요하여 두 컬럼만 정의
|
||||
public SessionUser(User user) {
|
||||
this.userName = user.getUserName();
|
||||
this.email = user.getEmail();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,382 @@
|
||||
package org.egovframe.cloud.userservice.config.dto;
|
||||
|
||||
import org.springframework.security.core.CredentialsContainer;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Models core user information retrieved by a {@link org.springframework.security.core.userdetails.UserDetailsService}.
|
||||
* <p>
|
||||
* Developers may use this class directly, subclass it, or write their own
|
||||
* {@link UserDetails} implementation from scratch.
|
||||
* <p>
|
||||
* {@code equals} and {@code hashcode} implementations are based on the {@code username}
|
||||
* property only, as the intention is that lookups of the same user principal object (in a
|
||||
* user registry, for example) will match where the objects represent the same user, not
|
||||
* just when all the properties (authorities, password for example) are the same.
|
||||
* <p>
|
||||
* Note that this implementation is not immutable. It implements the
|
||||
* {@code CredentialsContainer} interface, in order to allow the password to be erased
|
||||
* after authentication. This may cause side-effects if you are storing instances
|
||||
* in-memory and reusing them. If so, make sure you return a copy from your
|
||||
* {@code UserDetailsService} each time it is invoked.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class SocialUser implements UserDetails, CredentialsContainer {
|
||||
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
|
||||
|
||||
private String password;
|
||||
|
||||
private final String username;
|
||||
|
||||
private final Set<GrantedAuthority> authorities;
|
||||
|
||||
private final boolean accountNonExpired;
|
||||
|
||||
private final boolean accountNonLocked;
|
||||
|
||||
private final boolean credentialsNonExpired;
|
||||
|
||||
private final boolean enabled;
|
||||
|
||||
/**
|
||||
* Calls the more complex constructor with all boolean arguments set to {@code true}.
|
||||
*/
|
||||
public SocialUser(String username, Collection<? extends GrantedAuthority> authorities) {
|
||||
this(username, true, true, true, true, authorities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the <code>User</code> with the details required by
|
||||
* {@link org.springframework.security.authentication.dao.DaoAuthenticationProvider}.
|
||||
* @param username the username presented to the
|
||||
* <code>DaoAuthenticationProvider</code>
|
||||
* @param enabled set to <code>true</code> if the user is enabled
|
||||
* @param accountNonExpired set to <code>true</code> if the account has not expired
|
||||
* @param credentialsNonExpired set to <code>true</code> if the credentials have not
|
||||
* expired
|
||||
* @param accountNonLocked set to <code>true</code> if the account is not locked
|
||||
* @param authorities the authorities that should be granted to the caller if they
|
||||
* presented the correct username and password and the user is enabled. Not null.
|
||||
* @throws IllegalArgumentException if a <code>null</code> value was passed either as
|
||||
* a parameter or as an element in the <code>GrantedAuthority</code> collection
|
||||
*/
|
||||
public SocialUser(String username, boolean enabled, boolean accountNonExpired,
|
||||
boolean credentialsNonExpired, boolean accountNonLocked,
|
||||
Collection<? extends GrantedAuthority> authorities) {
|
||||
// Assert.isTrue(username != null && !"".equals(username) && password != null,
|
||||
// "Cannot pass null or empty values to constructor");
|
||||
this.username = username;
|
||||
this.enabled = enabled;
|
||||
this.accountNonExpired = accountNonExpired;
|
||||
this.credentialsNonExpired = credentialsNonExpired;
|
||||
this.accountNonLocked = accountNonLocked;
|
||||
this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<GrantedAuthority> getAuthorities() {
|
||||
return this.authorities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return this.accountNonExpired;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return this.accountNonLocked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return this.credentialsNonExpired;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eraseCredentials() {
|
||||
this.password = null;
|
||||
}
|
||||
|
||||
private static SortedSet<GrantedAuthority> sortAuthorities(Collection<? extends GrantedAuthority> authorities) {
|
||||
Assert.notNull(authorities, "Cannot pass a null GrantedAuthority collection");
|
||||
// Ensure array iteration order is predictable (as per
|
||||
// UserDetails.getAuthorities() contract and SEC-717)
|
||||
SortedSet<GrantedAuthority> sortedAuthorities = new TreeSet<>(new SocialUser.AuthorityComparator());
|
||||
for (GrantedAuthority grantedAuthority : authorities) {
|
||||
Assert.notNull(grantedAuthority, "GrantedAuthority list cannot contain any null elements");
|
||||
sortedAuthorities.add(grantedAuthority);
|
||||
}
|
||||
return sortedAuthorities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the supplied object is a {@code User} instance with the
|
||||
* same {@code username} value.
|
||||
* <p>
|
||||
* In other words, the objects are equal if they have the same username, representing
|
||||
* the same principal.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof SocialUser) {
|
||||
return this.username.equals(((SocialUser) obj).username);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hashcode of the {@code username}.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.username.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(getClass().getName()).append(" [");
|
||||
sb.append("Username=").append(this.username).append(", ");
|
||||
sb.append("Password=[PROTECTED], ");
|
||||
sb.append("Enabled=").append(this.enabled).append(", ");
|
||||
sb.append("AccountNonExpired=").append(this.accountNonExpired).append(", ");
|
||||
sb.append("credentialsNonExpired=").append(this.credentialsNonExpired).append(", ");
|
||||
sb.append("AccountNonLocked=").append(this.accountNonLocked).append(", ");
|
||||
sb.append("Granted Authorities=").append(this.authorities).append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a UserBuilder with a specified user name
|
||||
* @param username the username to use
|
||||
* @return the UserBuilder
|
||||
*/
|
||||
public static SocialUser.UserBuilder withUsername(String username) {
|
||||
return builder().username(username);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a UserBuilder
|
||||
* @return the UserBuilder
|
||||
*/
|
||||
public static SocialUser.UserBuilder builder() {
|
||||
return new SocialUser.UserBuilder();
|
||||
}
|
||||
|
||||
public static SocialUser.UserBuilder withUserDetails(UserDetails userDetails) {
|
||||
// @formatter:off
|
||||
return withUsername(userDetails.getUsername())
|
||||
.accountExpired(!userDetails.isAccountNonExpired())
|
||||
.accountLocked(!userDetails.isAccountNonLocked())
|
||||
.authorities(userDetails.getAuthorities())
|
||||
.credentialsExpired(!userDetails.isCredentialsNonExpired())
|
||||
.disabled(!userDetails.isEnabled());
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private static class AuthorityComparator implements Comparator<GrantedAuthority>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
|
||||
|
||||
@Override
|
||||
public int compare(GrantedAuthority g1, GrantedAuthority g2) {
|
||||
// Neither should ever be null as each entry is checked before adding it to
|
||||
// the set. If the authority is null, it is a custom authority and should
|
||||
// precede others.
|
||||
if (g2.getAuthority() == null) {
|
||||
return -1;
|
||||
}
|
||||
if (g1.getAuthority() == null) {
|
||||
return 1;
|
||||
}
|
||||
return g1.getAuthority().compareTo(g2.getAuthority());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the user to be added. At minimum the username, password, and authorities
|
||||
* should provided. The remaining attributes have reasonable defaults.
|
||||
*/
|
||||
public static final class UserBuilder {
|
||||
|
||||
private String username;
|
||||
|
||||
private List<GrantedAuthority> authorities;
|
||||
|
||||
private boolean accountExpired;
|
||||
|
||||
private boolean accountLocked;
|
||||
|
||||
private boolean credentialsExpired;
|
||||
|
||||
private boolean disabled;
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*/
|
||||
private UserBuilder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the username. This attribute is required.
|
||||
* @param username the username. Cannot be null.
|
||||
* @return the {@link SocialUser.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
*/
|
||||
public SocialUser.UserBuilder username(String username) {
|
||||
Assert.notNull(username, "username cannot be null");
|
||||
this.username = username;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the roles. This method is a shortcut for calling
|
||||
* {@link #authorities(String...)}, but automatically prefixes each entry with
|
||||
* "ROLE_". This means the following:
|
||||
*
|
||||
* <code>
|
||||
* builder.roles("USER","ADMIN");
|
||||
* </code>
|
||||
*
|
||||
* is equivalent to
|
||||
*
|
||||
* <code>
|
||||
* builder.authorities("ROLE_USER","ROLE_ADMIN");
|
||||
* </code>
|
||||
*
|
||||
* <p>
|
||||
* This attribute is required, but can also be populated with
|
||||
* {@link #authorities(String...)}.
|
||||
* </p>
|
||||
* @param roles the roles for this user (i.e. USER, ADMIN, etc). Cannot be null,
|
||||
* contain null values or start with "ROLE_"
|
||||
* @return the {@link SocialUser.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
*/
|
||||
public SocialUser.UserBuilder roles(String... roles) {
|
||||
List<GrantedAuthority> authorities = new ArrayList<>(roles.length);
|
||||
for (String role : roles) {
|
||||
Assert.isTrue(!role.startsWith("ROLE_"),
|
||||
() -> role + " cannot start with ROLE_ (it is automatically added)");
|
||||
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
|
||||
}
|
||||
return authorities(authorities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the authorities. This attribute is required.
|
||||
* @param authorities the authorities for this user. Cannot be null, or contain
|
||||
* null values
|
||||
* @return the {@link SocialUser.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
* @see #roles(String...)
|
||||
*/
|
||||
public SocialUser.UserBuilder authorities(GrantedAuthority... authorities) {
|
||||
return authorities(Arrays.asList(authorities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the authorities. This attribute is required.
|
||||
* @param authorities the authorities for this user. Cannot be null, or contain
|
||||
* null values
|
||||
* @return the {@link SocialUser.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
* @see #roles(String...)
|
||||
*/
|
||||
public SocialUser.UserBuilder authorities(Collection<? extends GrantedAuthority> authorities) {
|
||||
this.authorities = new ArrayList<>(authorities);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the authorities. This attribute is required.
|
||||
* @param authorities the authorities for this user (i.e. ROLE_USER, ROLE_ADMIN,
|
||||
* etc). Cannot be null, or contain null values
|
||||
* @return the {@link SocialUser.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
* @see #roles(String...)
|
||||
*/
|
||||
public SocialUser.UserBuilder authorities(String... authorities) {
|
||||
return authorities(AuthorityUtils.createAuthorityList(authorities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines if the account is expired or not. Default is false.
|
||||
* @param accountExpired true if the account is expired, false otherwise
|
||||
* @return the {@link SocialUser.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
*/
|
||||
public SocialUser.UserBuilder accountExpired(boolean accountExpired) {
|
||||
this.accountExpired = accountExpired;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines if the account is locked or not. Default is false.
|
||||
* @param accountLocked true if the account is locked, false otherwise
|
||||
* @return the {@link SocialUser.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
*/
|
||||
public SocialUser.UserBuilder accountLocked(boolean accountLocked) {
|
||||
this.accountLocked = accountLocked;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines if the credentials are expired or not. Default is false.
|
||||
* @param credentialsExpired true if the credentials are expired, false otherwise
|
||||
* @return the {@link SocialUser.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
*/
|
||||
public SocialUser.UserBuilder credentialsExpired(boolean credentialsExpired) {
|
||||
this.credentialsExpired = credentialsExpired;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines if the account is disabled or not. Default is false.
|
||||
* @param disabled true if the account is disabled, false otherwise
|
||||
* @return the {@link SocialUser.UserBuilder} for method chaining (i.e. to populate
|
||||
* additional attributes for this user)
|
||||
*/
|
||||
public SocialUser.UserBuilder disabled(boolean disabled) {
|
||||
this.disabled = disabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public UserDetails build() {
|
||||
return new SocialUser(this.username, !this.disabled, !this.accountExpired,
|
||||
!this.credentialsExpired, !this.accountLocked, this.authorities);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.egovframe.cloud.userservice.domain.log;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.egovframe.cloud.servlet.domain.BaseTimeEntity;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import static javax.persistence.GenerationType.IDENTITY;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.log.LoginLog
|
||||
* <p>
|
||||
* 로그인 로그 엔티티
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/09/01
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/09/01 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@Entity
|
||||
public class LoginLog extends BaseTimeEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = IDENTITY)
|
||||
@Column(name = "log_id")
|
||||
private Long id;
|
||||
|
||||
private Long siteId;
|
||||
|
||||
@Column(name = "email_addr", length = 100)
|
||||
private String email;
|
||||
|
||||
@Column(name = "ip_addr", length = 100)
|
||||
private String remoteIp;
|
||||
|
||||
private Boolean successAt;
|
||||
|
||||
@Column(name = "fail_content", length = 200)
|
||||
private String failContent;
|
||||
|
||||
@Builder
|
||||
public LoginLog(Long siteId, String email, Boolean successAt, String remoteIp, String failContent) {
|
||||
this.siteId = siteId;
|
||||
this.email = email;
|
||||
this.successAt = successAt;
|
||||
this.remoteIp = remoteIp;
|
||||
this.failContent = failContent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.egovframe.cloud.userservice.domain.log;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.log.LoginLogRepository
|
||||
* <p>
|
||||
* Spring Data JPA 에서 제공되는 JpaRepository 를 상속하는 인터페이스
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/09/01
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/09/01 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
public interface LoginLogRepository extends JpaRepository<LoginLog, Long> {
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package org.egovframe.cloud.userservice.domain.role;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
|
||||
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.egovframe.cloud.servlet.domain.BaseEntity;
|
||||
import org.hibernate.annotations.OnDelete;
|
||||
import org.hibernate.annotations.OnDeleteAction;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.role.Authorization
|
||||
* <p>
|
||||
* 인가 엔티티 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/08
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/08 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@Entity
|
||||
@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class)
|
||||
public class Authorization extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 인가 번호
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer authorizationNo;
|
||||
|
||||
/**
|
||||
* 인가 명
|
||||
*/
|
||||
@Column(nullable = false, length = 50)
|
||||
private String authorizationName;
|
||||
|
||||
/**
|
||||
* URL 패턴 값
|
||||
*/
|
||||
@Column(nullable = false, length = 200)
|
||||
private String urlPatternValue;
|
||||
|
||||
/**
|
||||
* Http Method 코드
|
||||
*/
|
||||
@Column(nullable = false, length = 20)
|
||||
private String httpMethodCode;
|
||||
|
||||
/**
|
||||
* 정렬 순서
|
||||
*/
|
||||
@Column()
|
||||
private Integer sortSeq;
|
||||
|
||||
/**
|
||||
* 권한 인가 엔티티
|
||||
*/
|
||||
@OneToMany(mappedBy = "authorization", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||
private List<RoleAuthorization> roleAuthorizations;
|
||||
|
||||
/**
|
||||
* 빌더 패턴 클래스 생성자
|
||||
*
|
||||
* @param authorizationNo 인가 번호
|
||||
* @param authorizationName 인가 명
|
||||
* @param urlPatternValue URL 패턴 값
|
||||
* @param httpMethodCode Http Method 코드
|
||||
* @param sortSeq 정렬 순서
|
||||
*/
|
||||
@Builder
|
||||
public Authorization(Integer authorizationNo, String authorizationName, String urlPatternValue, String httpMethodCode, Integer sortSeq, List<RoleAuthorization> roleAuthorizations) {
|
||||
this.authorizationNo = authorizationNo;
|
||||
this.authorizationName = authorizationName;
|
||||
this.urlPatternValue = urlPatternValue;
|
||||
this.httpMethodCode = httpMethodCode;
|
||||
this.sortSeq = sortSeq;
|
||||
this.roleAuthorizations = roleAuthorizations;
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 속성 값 수정
|
||||
*
|
||||
* @param authorizationName 인가 명
|
||||
* @param urlPatternValue URL 패턴 값
|
||||
* @param httpMethodCode Http Method 코드
|
||||
* @param sortSeq 정렬 순서
|
||||
* @return Authorization 인가 엔티티
|
||||
*/
|
||||
public Authorization update(String authorizationName, String urlPatternValue, String httpMethodCode, Integer sortSeq) {
|
||||
this.authorizationName = authorizationName;
|
||||
this.urlPatternValue = urlPatternValue;
|
||||
this.httpMethodCode = httpMethodCode;
|
||||
this.sortSeq = sortSeq;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.egovframe.cloud.userservice.domain.role;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.role.AuthorizationRepository
|
||||
* <p>
|
||||
* 인가 레파지토리 인터페이스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/08
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/08 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
public interface AuthorizationRepository extends JpaRepository<Authorization, Integer>, AuthorizationRepositoryCustom {
|
||||
|
||||
/**
|
||||
* 정렬 순서로 인가 단건 조회
|
||||
*
|
||||
* @param sortSeq 정렬 순서
|
||||
* @return Optional<Authorization> 인가 엔티티
|
||||
*/
|
||||
Optional<Authorization> findBySortSeq(Integer sortSeq);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package org.egovframe.cloud.userservice.domain.role;
|
||||
|
||||
import org.egovframe.cloud.common.dto.RequestDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.AuthorizationListResponseDto;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.role.AuthorizationRepositoryCustom
|
||||
* <p>
|
||||
* 인가 Querydsl 인터페이스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/15
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/15 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
public interface AuthorizationRepositoryCustom {
|
||||
|
||||
/**
|
||||
* 인가 페이지 목록 조회
|
||||
*
|
||||
* @param requestDto 인가 목록 요청 DTO
|
||||
* @param pageable 페이지 정보
|
||||
* @return Page<AuthorizationListResponseDto> 페이지 인가 목록 응답 DTO
|
||||
*/
|
||||
Page<AuthorizationListResponseDto> findPage(RequestDto requestDto, Pageable pageable);
|
||||
|
||||
/**
|
||||
* 권한 목록의 인가 전체 목록 조회
|
||||
*
|
||||
* @param roles 권한 목록
|
||||
* @return Page<AuthorizationListResponseDto> 페이지 인가 목록 응답 DTO
|
||||
*/
|
||||
List<AuthorizationListResponseDto> findByRoles(List<String> roles);
|
||||
|
||||
/**
|
||||
* 사용자의 인가 목록 조회
|
||||
*
|
||||
* @param userId 사용자 id
|
||||
* @return List<AuthorizationListResponseDto> 인가 목록 응답 DTO
|
||||
*/
|
||||
List<AuthorizationListResponseDto> findByUserId(String userId);
|
||||
|
||||
/**
|
||||
* 인가 다음 정렬 순서 조회
|
||||
*
|
||||
* @return Integer 다음 정렬 순서
|
||||
*/
|
||||
Integer findNextSortSeq();
|
||||
|
||||
/**
|
||||
* 인가 정렬 순서 수정
|
||||
*
|
||||
* @param startSortSeq 시작 정렬 순서
|
||||
* @param endSortSeq 종료 정렬 순서
|
||||
* @param increaseSortSeq 증가 정렬 순서
|
||||
* @return Long 처리 건수
|
||||
*/
|
||||
Long updateSortSeq(Integer startSortSeq, Integer endSortSeq, int increaseSortSeq);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
package org.egovframe.cloud.userservice.domain.role;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.egovframe.cloud.common.dto.RequestDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.AuthorizationListResponseDto;
|
||||
import org.egovframe.cloud.userservice.domain.user.QUser;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
import com.google.common.base.CaseFormat;
|
||||
import com.querydsl.core.QueryResults;
|
||||
import com.querydsl.core.types.Order;
|
||||
import com.querydsl.core.types.OrderSpecifier;
|
||||
import com.querydsl.core.types.Path;
|
||||
import com.querydsl.core.types.Projections;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import com.querydsl.core.types.dsl.Expressions;
|
||||
import com.querydsl.jpa.JPAExpressions;
|
||||
import com.querydsl.jpa.JPQLQuery;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.role.AuthorizationRepositoryImpl
|
||||
* <p>
|
||||
* 인가 Querydsl 구현 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/15
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/15 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class AuthorizationRepositoryImpl implements AuthorizationRepositoryCustom {
|
||||
|
||||
/**
|
||||
* DML 생성을위한 Querydsl 팩토리 클래스
|
||||
*/
|
||||
private final JPAQueryFactory jpaQueryFactory;
|
||||
|
||||
/**
|
||||
* 인가 페이지 목록 조회
|
||||
* 가급적 Entity 보다는 Dto를 리턴 - Entity 조회시 hibernate 캐시, 불필요 컬럼 조회, oneToOne N+1 문제 발생
|
||||
*
|
||||
* @param requestDto 요청 DTO
|
||||
* @param pageable 페이지 정보
|
||||
* @return Page<AuthorizationListResponseDto> 페이지 인가 목록 응답 DTO
|
||||
*/
|
||||
@Override
|
||||
public Page<AuthorizationListResponseDto> findPage(RequestDto requestDto, Pageable pageable) {
|
||||
JPQLQuery<AuthorizationListResponseDto> query = getAuthorizationListJPQLQuery()
|
||||
.where(getBooleanExpressionKeyword(requestDto));
|
||||
|
||||
//정렬
|
||||
pageable.getSort().stream().forEach(sort -> {
|
||||
Order order = sort.isAscending() ? Order.ASC : Order.DESC;
|
||||
String property = sort.getProperty();
|
||||
|
||||
Path<Object> target = Expressions.path(Object.class, QAuthorization.authorization, CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, property));
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
OrderSpecifier<?> orderSpecifier = new OrderSpecifier(order, target);
|
||||
query.orderBy(orderSpecifier);
|
||||
});
|
||||
|
||||
QueryResults<AuthorizationListResponseDto> result = query
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize()) //페이징
|
||||
.fetchResults();
|
||||
|
||||
return new PageImpl<>(result.getResults(), pageable, result.getTotal());
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한 목록의 인가 전체 목록 조회
|
||||
*
|
||||
* @param roles 권한 목록
|
||||
* @return Page<AuthorizationListResponseDto> 페이지 인가 목록 응답 DTO
|
||||
*/
|
||||
@Override
|
||||
public List<AuthorizationListResponseDto> findByRoles(List<String> roles) {
|
||||
JPQLQuery<AuthorizationListResponseDto> query = getAuthorizationListJPQLQuery()
|
||||
.where(JPAExpressions
|
||||
.selectFrom(QRoleAuthorization.roleAuthorization)
|
||||
.where(QRoleAuthorization.roleAuthorization.roleAuthorizationId.authorizationNo.eq(QAuthorization.authorization.authorizationNo)
|
||||
.and(QRoleAuthorization.roleAuthorization.roleAuthorizationId.roleId.in(roles)))
|
||||
.exists());
|
||||
|
||||
QueryResults<AuthorizationListResponseDto> result = query.fetchResults();
|
||||
|
||||
return result.getResults();
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자의 인가 목록 조회
|
||||
*
|
||||
* @param userId 사용자 id
|
||||
* @return List<AuthorizationListResponseDto> 인가 목록 응답 DTO
|
||||
*/
|
||||
@Override
|
||||
public List<AuthorizationListResponseDto> findByUserId(String userId) {
|
||||
JPQLQuery<AuthorizationListResponseDto> query = getAuthorizationListJPQLQuery()
|
||||
.where(JPAExpressions
|
||||
.selectFrom(QRoleAuthorization.roleAuthorization)
|
||||
.innerJoin(QUser.user)
|
||||
.on(QUser.user.role.stringValue().eq(QRoleAuthorization.roleAuthorization.roleAuthorizationId.roleId))
|
||||
.where(QRoleAuthorization.roleAuthorization.roleAuthorizationId.authorizationNo.eq(QAuthorization.authorization.authorizationNo)
|
||||
.and(QUser.user.userId.eq(userId)))
|
||||
.exists());
|
||||
|
||||
QueryResults<AuthorizationListResponseDto> result = query.fetchResults();
|
||||
|
||||
return result.getResults();
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 목록 JPQL Query 반환
|
||||
*
|
||||
* @return JPQLQuery<AuthorizationListResponseDto> 인가 목록 JPQL Query
|
||||
*/
|
||||
public JPQLQuery<AuthorizationListResponseDto> getAuthorizationListJPQLQuery() {
|
||||
return jpaQueryFactory
|
||||
.select(Projections.constructor(AuthorizationListResponseDto.class,
|
||||
QAuthorization.authorization.authorizationNo,
|
||||
QAuthorization.authorization.authorizationName,
|
||||
QAuthorization.authorization.urlPatternValue,
|
||||
QAuthorization.authorization.httpMethodCode,
|
||||
QAuthorization.authorization.sortSeq
|
||||
))
|
||||
.from(QAuthorization.authorization);
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 다음 정렬 순서 조회
|
||||
*
|
||||
* @return Integer 다음 정렬 순서
|
||||
*/
|
||||
@Override
|
||||
public Integer findNextSortSeq() {
|
||||
return jpaQueryFactory
|
||||
.select(QAuthorization.authorization.sortSeq.max().add(1).coalesce(1))
|
||||
.from(QAuthorization.authorization)
|
||||
.fetchOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 정렬 순서 수정
|
||||
*
|
||||
* @param startSortSeq 시작 정렬 순서
|
||||
* @param endSortSeq 종료 정렬 순서
|
||||
* @param increaseSortSeq 증가 정렬 순서
|
||||
* @return Long 수정 건수
|
||||
*/
|
||||
@Override
|
||||
public Long updateSortSeq(Integer startSortSeq, Integer endSortSeq, int increaseSortSeq) {
|
||||
return jpaQueryFactory.update(QAuthorization.authorization)
|
||||
.set(QAuthorization.authorization.sortSeq, QAuthorization.authorization.sortSeq.add(increaseSortSeq))
|
||||
.where(isGoeSortSeq(startSortSeq),
|
||||
isLoeSortSeq(endSortSeq))
|
||||
.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* 요청 DTO로 동적 검색 표현식 리턴
|
||||
*
|
||||
* @param requestDto 요청 DTO
|
||||
* @return BooleanExpression 검색 표현식
|
||||
*/
|
||||
private BooleanExpression getBooleanExpressionKeyword(RequestDto requestDto) {
|
||||
if (requestDto.getKeyword() == null || "".equals(requestDto.getKeyword())) return null;
|
||||
|
||||
switch (requestDto.getKeywordType()) {
|
||||
case "authorizationName": // 인가 명
|
||||
return QAuthorization.authorization.authorizationName.containsIgnoreCase(requestDto.getKeyword());
|
||||
case "urlPatternValue": // URL 패턴 값
|
||||
return QAuthorization.authorization.urlPatternValue.containsIgnoreCase(requestDto.getKeyword());
|
||||
case "httpMethodCode": // Http Method 코드
|
||||
return QAuthorization.authorization.httpMethodCode.containsIgnoreCase(requestDto.getKeyword());
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 정렬 순서 이하 검색 표현식
|
||||
*
|
||||
* @param sortSeq 정렬 순서
|
||||
* @return BooleanExpression 검색 표현식
|
||||
*/
|
||||
private BooleanExpression isLoeSortSeq(Integer sortSeq) {
|
||||
return sortSeq == null ? null : QAuthorization.authorization.sortSeq.loe(sortSeq);
|
||||
}
|
||||
|
||||
/**
|
||||
* 정렬 순서 이상 검색 표현식
|
||||
*
|
||||
* @param sortSeq 정렬 순서
|
||||
* @return BooleanExpression 검색 표현식
|
||||
*/
|
||||
private BooleanExpression isGoeSortSeq(Integer sortSeq) {
|
||||
return sortSeq == null ? null : QAuthorization.authorization.sortSeq.goe(sortSeq);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package org.egovframe.cloud.userservice.domain.role;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityListeners;
|
||||
import javax.persistence.Id;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.role.Role
|
||||
* <p>
|
||||
* 권한 엔티티 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/07
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/07 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@Entity
|
||||
@EntityListeners(AuditingEntityListener.class) // Auditing 기능 포함
|
||||
public class Role {
|
||||
|
||||
/**
|
||||
* 권한 id
|
||||
*/
|
||||
@Id
|
||||
@Column(nullable = false, length = 20, unique = true)
|
||||
private String roleId;
|
||||
|
||||
/**
|
||||
* 권한 명
|
||||
*/
|
||||
@Column(nullable = false, length = 50)
|
||||
private String roleName;
|
||||
|
||||
/**
|
||||
* 권한 내용
|
||||
*/
|
||||
@Column(length = 200)
|
||||
private String roleContent;
|
||||
|
||||
/**
|
||||
* 정렬 순서
|
||||
*/
|
||||
@Column
|
||||
private Integer sortSeq;
|
||||
|
||||
/**
|
||||
* 생성 일시
|
||||
*/
|
||||
@CreatedDate
|
||||
@Column
|
||||
private LocalDateTime createdDate;
|
||||
|
||||
/**
|
||||
* 빌드 패턴 클래스 생성자
|
||||
*
|
||||
* @param roleId 권한 id
|
||||
* @param roleName 권한 명
|
||||
* @param roleContent 권한 내용
|
||||
* @param sortSeq 정렬 순서
|
||||
*/
|
||||
@Builder
|
||||
public Role(String roleId, String roleName, String roleContent, Integer sortSeq) {
|
||||
this.roleId = roleId;
|
||||
this.roleName = roleName;
|
||||
this.roleContent = roleContent;
|
||||
this.sortSeq = sortSeq;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package org.egovframe.cloud.userservice.domain.role;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.CreatedBy;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.role.RoleAuthorization
|
||||
* <p>
|
||||
* 권한 인가 엔티티 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/09
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/09 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@Entity
|
||||
@EntityListeners(AuditingEntityListener.class) // Auditing 기능 포함
|
||||
public class RoleAuthorization {
|
||||
|
||||
/**
|
||||
* 권한 인가 복합키
|
||||
*/
|
||||
@EmbeddedId
|
||||
private RoleAuthorizationId roleAuthorizationId;
|
||||
|
||||
/**
|
||||
* 인가 엔티티
|
||||
*/
|
||||
@MapsId("authorizationNo") // RoleAuthorizationId.authorizationNo 매핑
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "authorization_no")
|
||||
private Authorization authorization;
|
||||
|
||||
/**
|
||||
* 생성자 id
|
||||
*/
|
||||
@CreatedBy
|
||||
@Column(updatable = false)
|
||||
private String createdBy;
|
||||
|
||||
/**
|
||||
* 생성 일시
|
||||
*/
|
||||
@CreatedDate
|
||||
@Column(updatable = false)
|
||||
private LocalDateTime createdDate;
|
||||
|
||||
/**
|
||||
* 빌드 패턴 클래스 생성자
|
||||
*
|
||||
* @param roleId 권한 id
|
||||
* @param authorizationNo 인가 번호
|
||||
*/
|
||||
@Builder
|
||||
public RoleAuthorization(String roleId, Integer authorizationNo) {
|
||||
this.roleAuthorizationId = RoleAuthorizationId.builder()
|
||||
.roleId(roleId)
|
||||
.authorizationNo(authorizationNo)
|
||||
.build();
|
||||
this.authorization = Authorization.builder()
|
||||
.authorizationNo(authorizationNo).build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package org.egovframe.cloud.userservice.domain.role;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.role.RoleAuthorizationId
|
||||
* <p>
|
||||
* 권한 인가 엔티티 복합키 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/09
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/09 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@Embeddable
|
||||
public class RoleAuthorizationId implements Serializable {
|
||||
|
||||
/**
|
||||
* SerialVersionUID
|
||||
*/
|
||||
private static final long serialVersionUID = 7191831905023135716L;
|
||||
|
||||
/**
|
||||
* 권한 id
|
||||
*/
|
||||
@Column(length = 20)
|
||||
private String roleId;
|
||||
|
||||
/**
|
||||
* 인가 번호
|
||||
*/
|
||||
private Integer authorizationNo; // @MapsId("authorizationNo")로 매핑
|
||||
|
||||
/**
|
||||
* 빌드 패턴 클래스 생성자
|
||||
*
|
||||
* @param roleId 권한 id
|
||||
* @param authorizationNo 인가 번호
|
||||
*/
|
||||
@Builder
|
||||
public RoleAuthorizationId(String roleId, Integer authorizationNo) {
|
||||
this.roleId = roleId;
|
||||
this.authorizationNo = authorizationNo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code value for the object. This method is supported for the benefit of hash tables such as those provided by java.util.HashMap.
|
||||
*
|
||||
* @return int a hash code value for this object.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(roleId, authorizationNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether some other object is "equal to" this one.
|
||||
*
|
||||
* @param object the reference object with which to compare.
|
||||
* @return {@code true} if this object is the same as the obj
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object) return true;
|
||||
if (!(object instanceof RoleAuthorizationId)) return false;
|
||||
RoleAuthorizationId that = (RoleAuthorizationId) object;
|
||||
return Objects.equals(roleId, that.getRoleId()) &&
|
||||
Objects.equals(authorizationNo, that.getAuthorizationNo());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.egovframe.cloud.userservice.domain.role;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.role.RoleAuthorizationRepository
|
||||
* <p>
|
||||
* 권한 인가 레파지토리 인터페이스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/09
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/09 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
public interface RoleAuthorizationRepository extends JpaRepository<RoleAuthorization, RoleAuthorizationId>, RoleAuthorizationRepositoryCustom {
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.egovframe.cloud.userservice.domain.role;
|
||||
|
||||
import org.egovframe.cloud.userservice.api.role.dto.RoleAuthorizationListRequestDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.RoleAuthorizationListResponseDto;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.role.RoleAuthorizationRepositoryCustom
|
||||
* <p>
|
||||
* 권한 인가 Querydsl 인터페이스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/15
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/15 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
public interface RoleAuthorizationRepositoryCustom {
|
||||
|
||||
/**
|
||||
* 권한 인가 페이지 목록 조회
|
||||
* 인가 기준으로 권한 인가 아우터 조인
|
||||
* 가급적 Entity 보다는 Dto를 리턴 - Entity 조회시 hibernate 캐시, 불필요 컬럼 조회, oneToOne N+1 문제 발생
|
||||
*
|
||||
* @param requestDto 권한 인가 목록 요청 DTO
|
||||
* @param pageable 페이지 정보
|
||||
* @return Page<RoleAuthorizationListResponseDto> 페이지 권한 인가 목록 응답 DTO
|
||||
*/
|
||||
Page<RoleAuthorizationListResponseDto> findPageAuthorizationList(RoleAuthorizationListRequestDto requestDto, Pageable pageable);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package org.egovframe.cloud.userservice.domain.role;
|
||||
|
||||
import com.querydsl.core.QueryResults;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import com.querydsl.core.types.dsl.CaseBuilder;
|
||||
import com.querydsl.core.types.dsl.Expressions;
|
||||
import com.querydsl.jpa.JPQLQuery;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.egovframe.cloud.common.dto.RequestDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.QRoleAuthorizationListResponseDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.RoleAuthorizationListRequestDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.RoleAuthorizationListResponseDto;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.role.RoleAuthorizationRepositoryImpl
|
||||
* <p>
|
||||
* 권한 인가 Querydsl 구현 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/15
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/15 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class RoleAuthorizationRepositoryImpl implements RoleAuthorizationRepositoryCustom {
|
||||
|
||||
/**
|
||||
* DML 생성을위한 Querydsl 팩토리 클래스
|
||||
*/
|
||||
private final JPAQueryFactory jpaQueryFactory;
|
||||
|
||||
/**
|
||||
* 권한 인가 페이지 목록 조회
|
||||
* 인가 기준으로 권한 인가 아우터 조인
|
||||
* 가급적 Entity 보다는 Dto를 리턴 - Entity 조회시 hibernate 캐시, 불필요 컬럼 조회, oneToOne N+1 문제 발생
|
||||
*
|
||||
* @param requestDto 권한 인가 목록 요청 DTO
|
||||
* @param pageable 페이지 정보
|
||||
* @return Page<RoleAuthorizationListResponseDto> 페이지 권한 인가 목록 응답 DTO
|
||||
*/
|
||||
public Page<RoleAuthorizationListResponseDto> findPageAuthorizationList(RoleAuthorizationListRequestDto requestDto, Pageable pageable) {
|
||||
JPQLQuery<RoleAuthorizationListResponseDto> query = jpaQueryFactory
|
||||
.select(new QRoleAuthorizationListResponseDto(
|
||||
Expressions.as(Expressions.constant(requestDto.getRoleId()), "roleId"),
|
||||
QAuthorization.authorization.authorizationNo,
|
||||
QAuthorization.authorization.authorizationName,
|
||||
QAuthorization.authorization.urlPatternValue,
|
||||
QAuthorization.authorization.httpMethodCode,
|
||||
QAuthorization.authorization.sortSeq,
|
||||
Expressions.as(new CaseBuilder()
|
||||
.when(QRoleAuthorization.roleAuthorization.roleAuthorizationId.roleId.isNotNull()
|
||||
.and(QRoleAuthorization.roleAuthorization.roleAuthorizationId.authorizationNo.isNotNull()))
|
||||
.then(true)
|
||||
.otherwise(false)
|
||||
, "createdAt") // 생성 여부
|
||||
))
|
||||
.from(QAuthorization.authorization)
|
||||
.leftJoin(QRoleAuthorization.roleAuthorization).on(QAuthorization.authorization.authorizationNo.eq(QRoleAuthorization.roleAuthorization.roleAuthorizationId.authorizationNo)
|
||||
.and(getBooleanExpressionRoleId(requestDto.getRoleId()))) // 권한 id
|
||||
.fetchJoin()
|
||||
.where(getBooleanExpressionKeyword(requestDto))
|
||||
.orderBy(QAuthorization.authorization.sortSeq.asc()); // 인가 정렬 순서 오름차순
|
||||
|
||||
QueryResults<RoleAuthorizationListResponseDto> result = query
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize()) //페이징
|
||||
.fetchResults();
|
||||
|
||||
return new PageImpl<>(result.getResults(), pageable, result.getTotal());
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한 id 검색 표현식 리턴
|
||||
*
|
||||
* @param roleId 권한 id
|
||||
* @return BooleanExpression
|
||||
*/
|
||||
private BooleanExpression getBooleanExpressionRoleId(String roleId) {
|
||||
return roleId != null && !"".equals(roleId) ? QRoleAuthorization.roleAuthorization.roleAuthorizationId.roleId.eq(roleId) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 요청 DTO로 동적 검색 표현식 리턴
|
||||
*
|
||||
* @param requestDto 요청 DTO
|
||||
* @return BooleanExpression 검색 표현식
|
||||
*/
|
||||
private BooleanExpression getBooleanExpressionKeyword(RequestDto requestDto) {
|
||||
if (requestDto.getKeyword() == null || "".equals(requestDto.getKeyword())) return null;
|
||||
|
||||
switch (requestDto.getKeywordType()) {
|
||||
case "authorizationName": // 인가 명
|
||||
return QAuthorization.authorization.authorizationName.containsIgnoreCase(requestDto.getKeyword());
|
||||
case "urlPatternValue": // URL 패턴 값
|
||||
return QAuthorization.authorization.urlPatternValue.containsIgnoreCase(requestDto.getKeyword());
|
||||
case "httpMethodCode": // Http Method 코드
|
||||
return QAuthorization.authorization.httpMethodCode.containsIgnoreCase(requestDto.getKeyword());
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.egovframe.cloud.userservice.domain.role;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.role.RoleRepository
|
||||
* <p>
|
||||
* 권한 레파지토리 인터페이스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/07
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/07 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
public interface RoleRepository extends JpaRepository<Role, Long>, RoleRepositoryCustom {
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.egovframe.cloud.userservice.domain.role;
|
||||
|
||||
import org.egovframe.cloud.common.dto.RequestDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.RoleListResponseDto;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.role.RoleRepositoryCustom
|
||||
* <p>
|
||||
* 권한 Querydsl 인터페이스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/15
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/15 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
public interface RoleRepositoryCustom {
|
||||
|
||||
/**
|
||||
* 권한 페이지 목록 조회
|
||||
* 가급적 Entity 보다는 Dto를 리턴 - Entity 조회시 hibernate 캐시, 불필요 컬럼 조회, oneToOne N+1 문제 발생
|
||||
*
|
||||
* @param requestDto 요청 DTO
|
||||
* @param pageable 페이지 정보
|
||||
* @return Page<RoleListResponseDto> 페이지 권한 목록 응답 DTO
|
||||
*/
|
||||
Page<RoleListResponseDto> findPage(RequestDto requestDto, Pageable pageable);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package org.egovframe.cloud.userservice.domain.role;
|
||||
|
||||
import org.egovframe.cloud.common.dto.RequestDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.QRoleListResponseDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.RoleListResponseDto;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
import com.google.common.base.CaseFormat;
|
||||
import com.querydsl.core.QueryResults;
|
||||
import com.querydsl.core.types.Order;
|
||||
import com.querydsl.core.types.OrderSpecifier;
|
||||
import com.querydsl.core.types.Path;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import com.querydsl.core.types.dsl.Expressions;
|
||||
import com.querydsl.jpa.JPQLQuery;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.role.RoleRepositoryImpl
|
||||
* <p>
|
||||
* 권한 Querydsl 구현 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/15
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/15 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class RoleRepositoryImpl implements RoleRepositoryCustom {
|
||||
|
||||
/**
|
||||
* DML 생성을위한 Querydsl 팩토리 클래스
|
||||
*/
|
||||
private final JPAQueryFactory jpaQueryFactory;
|
||||
|
||||
/**
|
||||
* 권한 페이지 목록 조회
|
||||
*
|
||||
* @param requestDto 요청 DTO
|
||||
* @param pageable 페이지 정보
|
||||
* @return Page<RoleListResponseDto> 페이지 권한 목록 응답 DTO
|
||||
*/
|
||||
@Override
|
||||
public Page<RoleListResponseDto> findPage(RequestDto requestDto, Pageable pageable) {
|
||||
JPQLQuery<RoleListResponseDto> query = jpaQueryFactory
|
||||
.select(new QRoleListResponseDto(
|
||||
QRole.role.roleId,
|
||||
QRole.role.roleName,
|
||||
QRole.role.roleContent,
|
||||
QRole.role.createdDate
|
||||
))
|
||||
.from(QRole.role)
|
||||
.where(getBooleanExpressionKeyword(requestDto));
|
||||
|
||||
//정렬
|
||||
pageable.getSort().stream().forEach(sort -> {
|
||||
Order order = sort.isAscending() ? Order.ASC : Order.DESC;
|
||||
String property = sort.getProperty();
|
||||
|
||||
Path<Object> target = Expressions.path(Object.class, QRole.role, CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, property));
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
OrderSpecifier<?> orderSpecifier = new OrderSpecifier(order, target);
|
||||
query.orderBy(orderSpecifier);
|
||||
});
|
||||
|
||||
QueryResults<RoleListResponseDto> result = query
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize()) //페이징
|
||||
.fetchResults();
|
||||
|
||||
return new PageImpl<>(result.getResults(), pageable, result.getTotal());
|
||||
}
|
||||
|
||||
/**
|
||||
* 요청 DTO로 동적 검색 표현식 리턴
|
||||
*
|
||||
* @param requestDto 요청 DTO
|
||||
* @return BooleanExpression 검색 표현식
|
||||
*/
|
||||
private BooleanExpression getBooleanExpressionKeyword(RequestDto requestDto) {
|
||||
if (requestDto.getKeyword() == null || "".equals(requestDto.getKeyword())) return null;
|
||||
|
||||
switch (requestDto.getKeywordType()) {
|
||||
case "roleId": // 권한 id
|
||||
return QRole.role.roleId.containsIgnoreCase(requestDto.getKeyword());
|
||||
case "roleName": // 권한 명
|
||||
return QRole.role.roleName.containsIgnoreCase(requestDto.getKeyword());
|
||||
case "roleContent": // 권한 내용
|
||||
return QRole.role.roleContent.containsIgnoreCase(requestDto.getKeyword());
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
package org.egovframe.cloud.userservice.domain.user;
|
||||
|
||||
import static javax.persistence.GenerationType.IDENTITY;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.egovframe.cloud.common.domain.Role;
|
||||
import org.egovframe.cloud.servlet.domain.BaseEntity;
|
||||
import org.hibernate.annotations.DynamicInsert;
|
||||
import org.hibernate.annotations.DynamicUpdate;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.user.User
|
||||
* <p>
|
||||
* 사용자 정보 엔티티
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/06/30
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/06/30 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@DynamicInsert
|
||||
@DynamicUpdate
|
||||
@Entity
|
||||
public class User extends BaseEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = IDENTITY)
|
||||
@Column(name = "user_no")
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false, unique = true)
|
||||
private String userId;
|
||||
|
||||
@Column(nullable = false, length = 50)
|
||||
private String userName;
|
||||
|
||||
@Column(nullable = false, name = "email_addr", length = 100, unique = true)
|
||||
private String email;
|
||||
|
||||
@Column(length = 100)
|
||||
private String encryptedPassword;
|
||||
|
||||
@Enumerated(EnumType.STRING) // Enum 값을 String 문자열로 저장
|
||||
@Column(name = "role_id", nullable = false)
|
||||
private Role role;
|
||||
|
||||
private String refreshToken;
|
||||
|
||||
@Column(nullable = false, length = 20, columnDefinition = "varchar(20) default '00'")
|
||||
private String userStateCode;
|
||||
|
||||
@Column
|
||||
private LocalDateTime lastLoginDate;
|
||||
|
||||
@Column(nullable = false, columnDefinition = "tinyint default '0'")
|
||||
private Integer loginFailCount;
|
||||
|
||||
@Column(length = 100)
|
||||
private String googleId;
|
||||
|
||||
@Column(length = 100)
|
||||
private String kakaoId;
|
||||
|
||||
@Column(length = 100)
|
||||
private String naverId;
|
||||
|
||||
@Builder
|
||||
public User(String userName, String email, String encryptedPassword, String userId,
|
||||
Role role, String userStateCode, String googleId, String kakaoId, String naverId) {
|
||||
this.userName = userName;
|
||||
this.email = email;
|
||||
this.encryptedPassword = encryptedPassword;
|
||||
this.userId = userId;
|
||||
this.role = role;
|
||||
this.userStateCode = userStateCode;
|
||||
this.googleId = googleId;
|
||||
this.kakaoId = kakaoId;
|
||||
this.naverId = naverId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 명과 이메일 정보를 수정한다.
|
||||
*
|
||||
* @param username 사용자 명
|
||||
* @param email 이메일
|
||||
* @param encryptedPassword 암호화 비밀번호
|
||||
* @param roleId 권한 id
|
||||
* @param userStateCode 회원 상태 코드
|
||||
* @return
|
||||
*/
|
||||
public User update(String username, String email, String encryptedPassword, String roleId, String userStateCode) {
|
||||
this.userName = username;
|
||||
this.email = email;
|
||||
this.encryptedPassword = encryptedPassword;
|
||||
this.role = Arrays.stream(Role.values()).filter(c -> c.getKey().equals(roleId)).findAny().orElse(null);
|
||||
this.userStateCode = userStateCode;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 refresh token 정보를 필드에 입력한다.
|
||||
*
|
||||
* @param refreshToken
|
||||
* @return
|
||||
*/
|
||||
public User updateRefreshToken(String refreshToken) {
|
||||
this.refreshToken = refreshToken;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 비밀번호 정보를 필드에 입력한다.
|
||||
*
|
||||
* @param encryptedPassword 암호화 비밀번호
|
||||
* @return User 사용자 엔티티
|
||||
*/
|
||||
public User updatePassword(String encryptedPassword) {
|
||||
this.encryptedPassword = encryptedPassword;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 명과 이메일 정보를 수정한다.
|
||||
*
|
||||
* @param username
|
||||
* @param email
|
||||
* @return
|
||||
*/
|
||||
public User updateInfo(String username, String email) {
|
||||
this.userName = username;
|
||||
this.email = email;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 상태 코드 정보를 필드에 입력한다.
|
||||
*
|
||||
* @param userStateCode 상태 코드
|
||||
* @return User 사용자 엔티티
|
||||
*/
|
||||
public User updateUserStateCode(String userStateCode) {
|
||||
this.userStateCode = userStateCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 로그인 실패 시 로그인실패수를 증가시키고 5회 이상 실패한 경우 회원상태를 정지로 변경
|
||||
*
|
||||
* @return User 사용자 엔티티
|
||||
*/
|
||||
public User failLogin() {
|
||||
this.loginFailCount = loginFailCount + 1;
|
||||
if (this.loginFailCount >= 5) {
|
||||
this.userStateCode = UserStateCode.HALT.getKey();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 로그인 성공 시 로그인실패수와 마지막로그인일시 정보를 갱신
|
||||
*
|
||||
* @return User 사용자 엔티티
|
||||
*/
|
||||
public User successLogin() {
|
||||
this.loginFailCount = 0;
|
||||
this.lastLoginDate = LocalDateTime.now();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 구글 id 등록
|
||||
*
|
||||
* @return User 사용자 엔티티
|
||||
*/
|
||||
public User updateGoogleId(String googleId) {
|
||||
this.googleId = googleId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 카카오 id 등록
|
||||
*
|
||||
* @return User 사용자 엔티티
|
||||
*/
|
||||
public User updateKakaoId(String kakaoId) {
|
||||
this.kakaoId = kakaoId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 네이버 id 등록
|
||||
*
|
||||
* @return User 사용자 엔티티
|
||||
*/
|
||||
public User updateNaverId(String naverId) {
|
||||
this.naverId = naverId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 소셜 사용자 여부 반환
|
||||
*
|
||||
* @return boolean 소셜 사용자 여부
|
||||
*/
|
||||
public boolean isSocialUser() {
|
||||
if (this.googleId != null && !"".equals(this.googleId)) return true;
|
||||
else if (this.kakaoId != null && !"".equals(this.kakaoId)) return true;
|
||||
else if (this.naverId != null && !"".equals(this.naverId)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getRoleKey() {
|
||||
return this.role.getKey();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package org.egovframe.cloud.userservice.domain.user;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.egovframe.cloud.servlet.domain.BaseTimeEntity;
|
||||
import org.hibernate.annotations.DynamicInsert;
|
||||
import org.hibernate.annotations.DynamicUpdate;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Entity;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.user.UserFindPassword
|
||||
* <p>
|
||||
* 사용자 비밀번호 찾기 엔티티 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/09/15
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/09/15 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@Entity
|
||||
@DynamicInsert
|
||||
@DynamicUpdate
|
||||
public class UserFindPassword extends BaseTimeEntity {
|
||||
|
||||
/**
|
||||
* 복합키
|
||||
*/
|
||||
@EmbeddedId
|
||||
private UserFindPasswordId userFindPasswordId;
|
||||
|
||||
/**
|
||||
* 토큰 값
|
||||
*/
|
||||
@Column(nullable = false, length = 50)
|
||||
private String tokenValue;
|
||||
|
||||
/**
|
||||
* 변경 여부
|
||||
*/
|
||||
@Column(nullable = false, columnDefinition = "tinyint(1) default '0'")
|
||||
private Boolean changeAt;
|
||||
|
||||
/**
|
||||
* 빌드 패턴 클래스 생성자
|
||||
*
|
||||
* @param emailAddr 이메일 주소
|
||||
* @param requestNo 요청 번호
|
||||
* @param tokenValue 토큰 값
|
||||
* @param changeAt 변경 여부
|
||||
*/
|
||||
@Builder
|
||||
public UserFindPassword(String emailAddr, Integer requestNo, String tokenValue, Boolean changeAt) {
|
||||
this.userFindPasswordId = UserFindPasswordId.builder()
|
||||
.emailAddr(emailAddr)
|
||||
.requestNo(requestNo)
|
||||
.build();
|
||||
this.tokenValue = tokenValue;
|
||||
this.changeAt = changeAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 변경 여부 수정
|
||||
*
|
||||
* @param changeAt 변경 여부
|
||||
* @return UserFindPassword 사용자 비밀번호 찾기 엔티티
|
||||
*/
|
||||
public UserFindPassword updateChangeAt(Boolean changeAt) {
|
||||
this.changeAt = changeAt;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.egovframe.cloud.userservice.domain.user;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@Embeddable
|
||||
public class UserFindPasswordId implements Serializable {
|
||||
|
||||
/**
|
||||
* SerialVersionUID
|
||||
*/
|
||||
private static final long serialVersionUID = -2267755880384011782L;
|
||||
|
||||
/**
|
||||
* 이메일 주소
|
||||
*/
|
||||
@Column(length = 50)
|
||||
private String emailAddr;
|
||||
|
||||
/**
|
||||
* 요청 번호
|
||||
*/
|
||||
private Integer requestNo;
|
||||
|
||||
/**
|
||||
* 빌드 패턴 클래스 생성자
|
||||
*
|
||||
* @param emailAddr 이메일 주소
|
||||
* @param requestNo 요청 번호
|
||||
*/
|
||||
@Builder
|
||||
public UserFindPasswordId(String emailAddr, Integer requestNo) {
|
||||
this.emailAddr = emailAddr;
|
||||
this.requestNo = requestNo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code value for the object. This method is supported for the benefit of hash tables such as those provided by java.util.HashMap.
|
||||
*
|
||||
* @return int a hash code value for this object.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(emailAddr, requestNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether some other object is "equal to" this one.
|
||||
*
|
||||
* @param object the reference object with which to compare.
|
||||
* @return {@code true} if this object is the same as the obj
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object) return true;
|
||||
if (!(object instanceof UserFindPasswordId)) return false;
|
||||
UserFindPasswordId that = (UserFindPasswordId) object;
|
||||
return Objects.equals(emailAddr, that.getEmailAddr()) &&
|
||||
Objects.equals(requestNo, that.getRequestNo());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.egovframe.cloud.userservice.domain.user;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.user.UserFindPasswordRepository
|
||||
*
|
||||
* 사용자 비밀번호 찾기 레파지토리 인터페이스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/09/15
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/09/15 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
public interface UserFindPasswordRepository extends JpaRepository<UserFindPassword, UserFindPasswordId>, UserFindPasswordRepositoryCustom {
|
||||
|
||||
/**
|
||||
* 토큰 값이 일치하는 사용자 비밀번호 찾기 조회
|
||||
*
|
||||
* @param tokenValue 토큰 값
|
||||
* @return Optional<UserFindPassword> 사용자 비밀번호 번경 요청 엔티티
|
||||
*/
|
||||
Optional<UserFindPassword> findByTokenValue(String tokenValue);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.egovframe.cloud.userservice.domain.user;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.user.UserFindPasswordRepositoryCustom
|
||||
* <p>
|
||||
* 사용자 비밀번호 찾기 Querydsl 인터페이스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/09/15
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/09/15 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
public interface UserFindPasswordRepositoryCustom {
|
||||
|
||||
/**
|
||||
* 다음 요청 번호 조회
|
||||
*
|
||||
* @param emailAddr 이메일 주소
|
||||
* @return Integer 다음 요청 번호
|
||||
*/
|
||||
Integer findNextRequestNo(String emailAddr);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.egovframe.cloud.userservice.domain.user;
|
||||
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.user.UserFindPasswordRepositoryImpl
|
||||
* <p>
|
||||
* 사용자 비밀번호 찾기 Querydsl 구현 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/09/15
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/09/15 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class UserFindPasswordRepositoryImpl implements UserFindPasswordRepositoryCustom {
|
||||
|
||||
/**
|
||||
* DML 생성을위한 Querydsl 팩토리 클래스
|
||||
*/
|
||||
private final JPAQueryFactory jpaQueryFactory;
|
||||
|
||||
/**
|
||||
* 다음 요청 번호 조회
|
||||
*
|
||||
* @param emailAddr 이메일 주소
|
||||
* @return Integer 다음 요청 번호
|
||||
*/
|
||||
@Override
|
||||
public Integer findNextRequestNo(String emailAddr) {
|
||||
return jpaQueryFactory
|
||||
.select(QUserFindPassword.userFindPassword.userFindPasswordId.requestNo.max().add(1).coalesce(1))
|
||||
.from(QUserFindPassword.userFindPassword)
|
||||
.where(QUserFindPassword.userFindPassword.userFindPasswordId.emailAddr.eq(emailAddr))
|
||||
.fetchOne();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.egovframe.cloud.userservice.domain.user;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.user.UserRepository
|
||||
* <p>
|
||||
* Spring Data JPA 에서 제공되는 JpaRepository 를 상속하는 인터페이스
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/07/01
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/01 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
public interface UserRepository extends JpaRepository<User, Long>, UserRepositoryCustom {
|
||||
// email을 통해 이미 생성된 사용자인지 판단하기 위한 메소드
|
||||
Optional<User> findByEmail(String email);
|
||||
Optional<User> findByUserId(String userId);
|
||||
Optional<User> findByRefreshToken(String refreshToken);
|
||||
List<User> findByEmailContains(String email);
|
||||
Optional<User> findByEmailAndUserName(String email, String userName);
|
||||
Optional<User> findByEmailAndUserIdNot(String email, String userId);
|
||||
Optional<User> findByGoogleId(String googleId);
|
||||
Optional<User> findByKakaoId(String kakaoId);
|
||||
Optional<User> findByNaverId(String naverId);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.egovframe.cloud.userservice.domain.user;
|
||||
|
||||
import org.egovframe.cloud.common.dto.RequestDto;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserListResponseDto;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.user.UserRepositoryCustom
|
||||
* <p>
|
||||
* 사용자 Querydsl 인터페이스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/09/23
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/09/23 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
public interface UserRepositoryCustom {
|
||||
|
||||
/**
|
||||
* 사용자 페이지 목록 조회
|
||||
*
|
||||
* @param requestDto 사용자 목록 요청 DTO
|
||||
* @param pageable 페이지 정보
|
||||
* @return Page<UserListResponseDto> 페이지 사용자 목록 응답 DTO
|
||||
*/
|
||||
Page<UserListResponseDto> findPage(RequestDto requestDto, Pageable pageable);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package org.egovframe.cloud.userservice.domain.user;
|
||||
|
||||
import com.querydsl.core.QueryResults;
|
||||
import com.querydsl.core.types.Projections;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.egovframe.cloud.common.dto.RequestDto;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserListResponseDto;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.user.UserRepositoryImpl
|
||||
* <p>
|
||||
* 사용자 Querydsl 구현 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/09/23
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/09/23 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class UserRepositoryImpl implements UserRepositoryCustom {
|
||||
|
||||
/**
|
||||
* DML 생성을위한 Querydsl 팩토리 클래스
|
||||
*/
|
||||
private final JPAQueryFactory jpaQueryFactory;
|
||||
|
||||
/**
|
||||
* 사용자 페이지 목록 조회
|
||||
*
|
||||
* @param requestDto 요청 DTO
|
||||
* @param pageable 페이지 정보
|
||||
* @return Page<UserListResponseDto> 페이지 사용자 목록 응답 DTO
|
||||
*/
|
||||
public Page<UserListResponseDto> findPage(RequestDto requestDto, Pageable pageable) {
|
||||
QueryResults<UserListResponseDto> result = jpaQueryFactory
|
||||
.select(Projections.constructor(UserListResponseDto.class,
|
||||
QUser.user.userId,
|
||||
QUser.user.userName,
|
||||
QUser.user.email,
|
||||
QUser.user.role,
|
||||
QUser.user.userStateCode,
|
||||
QUser.user.lastLoginDate,
|
||||
QUser.user.loginFailCount
|
||||
))
|
||||
.from(QUser.user)
|
||||
.where(getBooleanExpression(requestDto))
|
||||
.orderBy(QUser.user.userName.asc(), QUser.user.email.asc())
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize())
|
||||
.fetchResults();
|
||||
|
||||
return new PageImpl<>(result.getResults(), pageable, result.getTotal());
|
||||
}
|
||||
|
||||
/**
|
||||
* 요청 DTO로 동적 검색 표현식 리턴
|
||||
*
|
||||
* @param requestDto 요청 DTO
|
||||
* @return BooleanExpression 검색 표현식
|
||||
*/
|
||||
private BooleanExpression getBooleanExpression(RequestDto requestDto) {
|
||||
if (requestDto.getKeyword() == null || "".equals(requestDto.getKeyword())) return null;
|
||||
|
||||
switch (requestDto.getKeywordType()) {
|
||||
case "userName": // 사용자 명
|
||||
return QUser.user.userName.containsIgnoreCase(requestDto.getKeyword());
|
||||
case "email": // 이메일 주소
|
||||
return QUser.user.email.containsIgnoreCase(requestDto.getKeyword());
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package org.egovframe.cloud.userservice.domain.user;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.domain.user.UserStateCode
|
||||
*
|
||||
* 사용자 상태 코드 열거형 상수
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/09/17
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/09/17 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum UserStateCode {
|
||||
|
||||
WAIT("00", "대기"),
|
||||
NORMAL("01", "정상"),
|
||||
HALT("07", "정지"),
|
||||
LEAVE("08", "탈퇴"),
|
||||
DELETE("09", "삭제");
|
||||
|
||||
private final String key;
|
||||
private final String title;
|
||||
|
||||
/**
|
||||
* 사용자 상태 코드로 상수 검색
|
||||
*
|
||||
* @param key 사용자 상태 코드
|
||||
* @return UserStateCode 사용자 상태 코드 상수
|
||||
*/
|
||||
public static UserStateCode findByKey(String key) {
|
||||
return Arrays.stream(UserStateCode.values()).filter(c -> c.getKey().equals(key)).findAny().orElse(null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
package org.egovframe.cloud.userservice.service.role;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.egovframe.cloud.common.config.GlobalConstant;
|
||||
import org.egovframe.cloud.common.dto.RequestDto;
|
||||
import org.egovframe.cloud.common.exception.EntityNotFoundException;
|
||||
import org.egovframe.cloud.common.service.AbstractService;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.AuthorizationListResponseDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.AuthorizationResponseDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.AuthorizationSaveRequestDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.AuthorizationUpdateRequestDto;
|
||||
import org.egovframe.cloud.userservice.domain.role.Authorization;
|
||||
import org.egovframe.cloud.userservice.domain.role.AuthorizationRepository;
|
||||
import org.springframework.aop.framework.AopContext;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.service.role.AuthorizationService
|
||||
* <p>
|
||||
* 인가 서비스 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/08
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/08 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class AuthorizationService extends AbstractService {
|
||||
|
||||
/**
|
||||
* 인가 레파지토리 인터페이스
|
||||
*/
|
||||
private final AuthorizationRepository authorizationRepository;
|
||||
|
||||
/**
|
||||
* 캐시 관리자
|
||||
*/
|
||||
private final CacheManager cacheManager;
|
||||
|
||||
/**
|
||||
* 조회 조건에 일치하는 인가 페이지 목록 조회
|
||||
*
|
||||
* @param requestDto 요청 DTO
|
||||
* @param pageable 페이지 정보
|
||||
* @return Page<AuthorizationListResponseDto> 페이지 인가 목록 응답 DTO
|
||||
*/
|
||||
public Page<AuthorizationListResponseDto> findPage(RequestDto requestDto, Pageable pageable) {
|
||||
return authorizationRepository.findPage(requestDto, pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한의 인가 여부 확인
|
||||
* 사용자 서비스 시큐리티 필터에서 호출
|
||||
*
|
||||
* @param request http 요청
|
||||
* @param authentication 시큐리티 인증 토큰
|
||||
* @return Boolean 인가 여부
|
||||
*/
|
||||
public Boolean isAuthorization(HttpServletRequest request, Authentication authentication) {
|
||||
List<String> roles = authentication.getAuthorities().stream().map(GrantedAuthority::toString).collect(Collectors.toList());
|
||||
|
||||
List<AuthorizationListResponseDto> authorizationList = ((AuthorizationService) AopContext.currentProxy()).findByRoles(roles);
|
||||
|
||||
return isContainMatch(authorizationList, request.getMethod(), GlobalConstant.USER_SERVICE_URI + request.getRequestURI());
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한의 인가 전체 목록 조회
|
||||
*
|
||||
* @param roles 권한 목록
|
||||
* @return List<AuthorizationListResponseDto> 인가 목록
|
||||
*/
|
||||
@Cacheable(value = "cache-user-authorization-by-roles", key = "#roles")
|
||||
public List<AuthorizationListResponseDto> findByRoles(List<String> roles) {
|
||||
return authorizationRepository.findByRoles(roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한의 인가 여부 확인
|
||||
* gateway 에서 호출
|
||||
* <p>
|
||||
* Spring Cache는 Spring AOP를 이용해서 proxy로 동작하기 때문에 외부 method 호출만 인터셉트해서 작동하고 self-invocation의 경우 동작하지 않음
|
||||
* 스프링에서는 AspectJ를 권장하지만 Load-time Weaving 방식은 퍼포먼스 문제가 있고
|
||||
* Compile-time Weaving 방식은 컴파일 시 수행되는 라이브러리(lombok)와 충돌 문제가 있음
|
||||
* AopContext.currentProxy()를 이용해서 proxy로 호출하도록 함 - CacheConfig @EnableAspectJAutoProxy(exposeProxy=true)
|
||||
*
|
||||
* @param roles 권한 목록
|
||||
* @param httpMethod Http Method
|
||||
* @param requestPath 요청 경로
|
||||
* @return Boolean 인가 여부
|
||||
*/
|
||||
public Boolean isAuthorization(List<String> roles, String httpMethod, String requestPath) {
|
||||
List<AuthorizationListResponseDto> authorizationList = ((AuthorizationService) AopContext.currentProxy()).findByRoles(roles);
|
||||
|
||||
return isContainMatch(authorizationList, httpMethod, requestPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자의 인가 전체 목록 조회
|
||||
*
|
||||
* @param userId 사용자 id
|
||||
* @return List<AuthorizationListResponseDto> 인가 목록
|
||||
*/
|
||||
@Cacheable(value = "cache-user-authorization-by-userid", key = "#roles")
|
||||
public List<AuthorizationListResponseDto> findByUserId(String userId) {
|
||||
return authorizationRepository.findByUserId(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자의 인가 여부 확인
|
||||
* gateway 에서 호출
|
||||
*
|
||||
* @param userId 사용자 id
|
||||
* @param httpMethod Http Method
|
||||
* @param requestPath 요청 경로
|
||||
* @return Boolean 인가 여부
|
||||
*/
|
||||
public Boolean isAuthorization(String userId, String httpMethod, String requestPath) {
|
||||
List<AuthorizationListResponseDto> authorizationList = ((AuthorizationService) AopContext.currentProxy()).findByUserId(userId);
|
||||
|
||||
return isContainMatch(authorizationList, httpMethod, requestPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 여부 체크
|
||||
*
|
||||
* @param authorizationList 인가 목록
|
||||
* @param httpMethod Http Method
|
||||
* @param requestPath 요청 경로
|
||||
* @return Boolean 인가 여부
|
||||
*/
|
||||
private Boolean isContainMatch(List<AuthorizationListResponseDto> authorizationList, String httpMethod, String requestPath) {
|
||||
AntPathMatcher antPathMatcher = new AntPathMatcher();
|
||||
|
||||
for (AuthorizationListResponseDto dto : authorizationList) {
|
||||
if (antPathMatcher.match(dto.getUrlPatternValue(), requestPath) && dto.getHttpMethodCode().equals(httpMethod)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 단건 조회
|
||||
*
|
||||
* @param authorizationNo 인가 번호
|
||||
* @return AuthorizationResponseDto 인가 응답 DTO
|
||||
*/
|
||||
public AuthorizationResponseDto findById(Integer authorizationNo) {
|
||||
Authorization entity = findAuthorization(authorizationNo);
|
||||
|
||||
return new AuthorizationResponseDto(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 다음 정렬 순서 조회
|
||||
*
|
||||
* @return Integer 다음 정렬 순서
|
||||
*/
|
||||
public Integer findNextSortSeq() {
|
||||
return authorizationRepository.findNextSortSeq();
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 등록
|
||||
*
|
||||
* @param requestDto 인가 등록 요청 DTO
|
||||
* @return AuthorizationResponseDto 인가 응답 DTO
|
||||
*/
|
||||
@Transactional
|
||||
public AuthorizationResponseDto save(AuthorizationSaveRequestDto requestDto) {
|
||||
// 동일한 정렬 순서가 존재할 경우 +1
|
||||
Optional<Authorization> authorization = authorizationRepository.findBySortSeq(requestDto.getSortSeq());
|
||||
if (authorization.isPresent()) {
|
||||
authorizationRepository.updateSortSeq(requestDto.getSortSeq(), null, 1);
|
||||
}
|
||||
|
||||
// 등록
|
||||
Authorization entity = authorizationRepository.save(requestDto.toEntity());
|
||||
|
||||
clearAuthorizationCache();
|
||||
|
||||
return new AuthorizationResponseDto(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 수정
|
||||
*
|
||||
* @param authorizationNo 인가 번호
|
||||
* @param requestDto 인가 수정 요청 DTO
|
||||
* @return AuthorizationResponseDto 인가 응답 DTO
|
||||
*/
|
||||
@Transactional
|
||||
public AuthorizationResponseDto update(Integer authorizationNo, AuthorizationUpdateRequestDto requestDto) {
|
||||
Authorization entity = findAuthorization(authorizationNo);
|
||||
|
||||
// 정렬 순서가 변경된 경우 사이 구간 정렬 순서 조정
|
||||
Integer beforeSortSeq = entity.getSortSeq();
|
||||
Integer afterSortSeq = requestDto.getSortSeq();
|
||||
Integer startSortSeq = null;
|
||||
Integer endSortSeq = null;
|
||||
int increaseSortSeq = 0;
|
||||
if (beforeSortSeq == null && afterSortSeq != null) {
|
||||
startSortSeq = afterSortSeq;
|
||||
increaseSortSeq = 1;
|
||||
} else if (beforeSortSeq != null && afterSortSeq == null) {
|
||||
startSortSeq = beforeSortSeq + 1;
|
||||
increaseSortSeq = -1;
|
||||
} else if (beforeSortSeq != null && afterSortSeq != null && beforeSortSeq.compareTo(afterSortSeq) != 0) {
|
||||
if (beforeSortSeq.compareTo(afterSortSeq) > 0) {
|
||||
startSortSeq = afterSortSeq;
|
||||
endSortSeq = beforeSortSeq - 1;
|
||||
increaseSortSeq = 1;
|
||||
} else {
|
||||
startSortSeq = beforeSortSeq + 1;
|
||||
endSortSeq = afterSortSeq;
|
||||
increaseSortSeq = -1;
|
||||
}
|
||||
}
|
||||
if (startSortSeq != null || endSortSeq != null) {
|
||||
authorizationRepository.updateSortSeq(startSortSeq, endSortSeq, increaseSortSeq);
|
||||
}
|
||||
|
||||
// 수정
|
||||
entity.update(requestDto.getAuthorizationName(), requestDto.getUrlPatternValue(), requestDto.getHttpMethodCode(), requestDto.getSortSeq());
|
||||
|
||||
clearAuthorizationCache();
|
||||
|
||||
return new AuthorizationResponseDto(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 삭제
|
||||
* 권한 인가도 같이 삭제됨
|
||||
*
|
||||
* @param authorizationNo 인가 번호
|
||||
*/
|
||||
@Transactional
|
||||
public void delete(Integer authorizationNo) {
|
||||
Authorization entity = findAuthorization(authorizationNo);
|
||||
|
||||
// 삭제
|
||||
authorizationRepository.delete(entity);
|
||||
|
||||
// 삭제한 데이터보다 정렬 순서가 더 큰 데이터 -1
|
||||
authorizationRepository.updateSortSeq(entity.getSortSeq() + 1, null, -1);
|
||||
|
||||
clearAuthorizationCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 번호로 인가 엔티티 조회
|
||||
*
|
||||
* @param authorizationNo 인가 번호
|
||||
* @return Authorization 인가 엔티티
|
||||
*/
|
||||
private Authorization findAuthorization(Integer authorizationNo) {
|
||||
return authorizationRepository.findById(authorizationNo)
|
||||
.orElseThrow(() -> new EntityNotFoundException(getMessage("valid.notexists.format", new Object[]{getMessage("authorization")})));
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 조회 캐시 클리어
|
||||
*/
|
||||
private void clearAuthorizationCache() {
|
||||
Cache useridCache = cacheManager.getCache("cache-user-authorization-by-userid");
|
||||
if (useridCache != null) useridCache.clear();
|
||||
Cache rolesCache = cacheManager.getCache("cache-user-authorization-by-roles");
|
||||
if (rolesCache != null) rolesCache.clear();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package org.egovframe.cloud.userservice.service.role;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.egovframe.cloud.common.service.AbstractService;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.RoleAuthorizationDeleteRequestDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.RoleAuthorizationListRequestDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.RoleAuthorizationListResponseDto;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.RoleAuthorizationSaveRequestDto;
|
||||
import org.egovframe.cloud.userservice.domain.role.RoleAuthorization;
|
||||
import org.egovframe.cloud.userservice.domain.role.RoleAuthorizationRepository;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.service.role.RoleAuthorizationService
|
||||
* <p>
|
||||
* 권한 인가 서비스 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/12
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/12 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class RoleAuthorizationService extends AbstractService {
|
||||
|
||||
/**
|
||||
* 권한 인가 레파지토리 인터페이스
|
||||
*/
|
||||
private final RoleAuthorizationRepository roleAuthorizationRepository;
|
||||
|
||||
/**
|
||||
* 캐시 관리자
|
||||
*/
|
||||
private final CacheManager cacheManager;
|
||||
|
||||
/**
|
||||
* 조회 조건에 일치하는 권한 인가 페이지 목록 조회
|
||||
*
|
||||
* @param requestDto 권한 인가 목록 요청 DTO
|
||||
* @param pageable 페이지 정보
|
||||
* @return Page<RoleAuthorizationListResponseDto> 페이지 권한 인가 목록 응답 DTO
|
||||
*/
|
||||
public Page<RoleAuthorizationListResponseDto> findPageAuthorizationList(RoleAuthorizationListRequestDto requestDto, Pageable pageable) {
|
||||
if (requestDto.getRoleId() == null || "".equals(requestDto.getRoleId())) {
|
||||
return new PageImpl<>(Collections.emptyList(), pageable, 0);
|
||||
}
|
||||
|
||||
return roleAuthorizationRepository.findPageAuthorizationList(requestDto, pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한 인가 다건 등록
|
||||
*
|
||||
* @param requestDtoList 권한 인가 등록 요청 DTO List
|
||||
* @return List<RoleAuthorizationListResponseDto> 등록 권한 인가 목록
|
||||
*/
|
||||
@Transactional
|
||||
public List<RoleAuthorizationListResponseDto> save(List<RoleAuthorizationSaveRequestDto> requestDtoList) {
|
||||
List<RoleAuthorization> saveEntityList = requestDtoList.stream()
|
||||
.map(RoleAuthorizationSaveRequestDto::toEntity)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<RoleAuthorization> savedEntityList = roleAuthorizationRepository.saveAll(saveEntityList);
|
||||
|
||||
clearAuthorizationCache();
|
||||
|
||||
return savedEntityList.stream()
|
||||
.map(m -> RoleAuthorizationListResponseDto.builder()
|
||||
.roleId(m.getRoleAuthorizationId().getRoleId())
|
||||
.authorizationNo(m.getRoleAuthorizationId().getAuthorizationNo())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한 인가 다건 삭제
|
||||
*
|
||||
* @param requestDtoList 권한 인가 삭제 요청 DTO List
|
||||
*/
|
||||
@Transactional
|
||||
public void delete(List<RoleAuthorizationDeleteRequestDto> requestDtoList) {
|
||||
List<RoleAuthorization> deleteEntityList = requestDtoList.stream()
|
||||
.map(RoleAuthorizationDeleteRequestDto::toEntity)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
roleAuthorizationRepository.deleteAll(deleteEntityList);
|
||||
|
||||
clearAuthorizationCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 조회 캐시 클리어
|
||||
*/
|
||||
private void clearAuthorizationCache() {
|
||||
Cache useridCache = cacheManager.getCache("cache-user-authorization-by-userid");
|
||||
if (useridCache != null) useridCache.clear();
|
||||
Cache rolesCache = cacheManager.getCache("cache-user-authorization-by-roles");
|
||||
if (rolesCache != null) rolesCache.clear();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package org.egovframe.cloud.userservice.service.role;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.egovframe.cloud.common.dto.RequestDto;
|
||||
import org.egovframe.cloud.common.service.AbstractService;
|
||||
import org.egovframe.cloud.userservice.api.role.dto.RoleListResponseDto;
|
||||
import org.egovframe.cloud.userservice.domain.role.RoleRepository;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.service.role.RoleService
|
||||
* <p>
|
||||
* 권한 서비스 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/07
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/07 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class RoleService extends AbstractService {
|
||||
|
||||
/**
|
||||
* 권한 레파지토리 인터페이스
|
||||
*/
|
||||
private final RoleRepository roleRepository;
|
||||
|
||||
/**
|
||||
* 조회 조건에 일치하는 권한 페이지 목록 조회
|
||||
*
|
||||
* @param requestDto 요청 DTO
|
||||
* @param pageable 페이지 정보
|
||||
* @return Page<RoleListResponseDto> 페이지 권한 목록 응답 DTO
|
||||
*/
|
||||
public Page<RoleListResponseDto> findPage(RequestDto requestDto, Pageable pageable) {
|
||||
return roleRepository.findPage(requestDto, pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한 전체 조회
|
||||
*
|
||||
* @param sort 정렬
|
||||
* @return List<RoleListResponseDto> 권한 목록 응답 DTO
|
||||
*/
|
||||
public List<RoleListResponseDto> findAllBySort(Sort sort) {
|
||||
return roleRepository.findAll(sort).stream()
|
||||
.map(m -> RoleListResponseDto.builder()
|
||||
.roleId(m.getRoleId())
|
||||
.roleName(m.getRoleName())
|
||||
.roleContent(m.getRoleContent())
|
||||
.createdDate(m.getCreatedDate())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,861 @@
|
||||
package org.egovframe.cloud.userservice.service.user;
|
||||
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
import com.google.api.client.http.javanet.NetHttpTransport;
|
||||
import com.google.api.client.json.gson.GsonFactory;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.egovframe.cloud.common.domain.Role;
|
||||
import org.egovframe.cloud.common.dto.RequestDto;
|
||||
import org.egovframe.cloud.common.exception.BusinessMessageException;
|
||||
import org.egovframe.cloud.common.service.AbstractService;
|
||||
import org.egovframe.cloud.common.util.LogUtil;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.*;
|
||||
import org.egovframe.cloud.userservice.config.UserPasswordChangeEmailTemplate;
|
||||
import org.egovframe.cloud.userservice.config.dto.SocialUser;
|
||||
import org.egovframe.cloud.userservice.domain.log.LoginLog;
|
||||
import org.egovframe.cloud.userservice.domain.log.LoginLogRepository;
|
||||
import org.egovframe.cloud.userservice.domain.user.*;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.mail.javamail.JavaMailSender;
|
||||
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.service.user.UserService
|
||||
* <p>
|
||||
* 사용자 정보 서비스
|
||||
*
|
||||
* @author 표준프레임워크센터 jaeyeolkim
|
||||
* @version 1.0
|
||||
* @since 2021/07/08
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/08 jaeyeolkim 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@Slf4j
|
||||
@Transactional(readOnly = true)
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class UserService extends AbstractService implements UserDetailsService {
|
||||
|
||||
/**
|
||||
* 구글 클라이언트 ID
|
||||
*/
|
||||
@Value("${spring.security.oauth2.client.registration.google.client-id}")
|
||||
private String GOOGLE_CLIENT_ID;
|
||||
|
||||
/**
|
||||
* 카카오 사용자 정보 URL
|
||||
*/
|
||||
@Value("${spring.security.oauth2.client.provider.kakao.user-info-uri}")
|
||||
private String KAKAO_USER_INFO_URI;
|
||||
|
||||
/**
|
||||
* 네이버 사용자 정보 URL
|
||||
*/
|
||||
@Value("${spring.security.oauth2.client.provider.naver.user-info-uri}")
|
||||
private String NAVER_USER_INFO_URI;
|
||||
|
||||
/**
|
||||
* REST Template
|
||||
*/
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private final UserFindPasswordRepository userFindPasswordRepository;
|
||||
private final BCryptPasswordEncoder passwordEncoder;
|
||||
private final LoginLogRepository loginLogRepository;
|
||||
|
||||
/**
|
||||
* 자바 메일 전송 인터페이스
|
||||
*/
|
||||
private final JavaMailSender javaMailSender;
|
||||
|
||||
/**
|
||||
* 조회 조건에 일치하는 사용자 페이지 목록 조회
|
||||
*
|
||||
* @param requestDto 요청 DTO
|
||||
* @param pageable 페이지 정보
|
||||
* @return Page<UserListResponseDto> 페이지 사용자 목록 응답 DTO
|
||||
*/
|
||||
public Page<UserListResponseDto> findPage(RequestDto requestDto, Pageable pageable) {
|
||||
return userRepository.findPage(requestDto, pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 등록
|
||||
*
|
||||
* @param requestDto
|
||||
* @return
|
||||
*/
|
||||
@Transactional
|
||||
public Long save(UserSaveRequestDto requestDto) {
|
||||
return userRepository.save(requestDto.toEntity(passwordEncoder)).getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 수정
|
||||
*
|
||||
* @param userId 사용자 id
|
||||
* @param requestDto 사용자 수정 요청 DTO
|
||||
* @return String 사용자 id
|
||||
*/
|
||||
@Transactional
|
||||
public String update(String userId, UserUpdateRequestDto requestDto) {
|
||||
User user = getUserByUserId(userId);
|
||||
|
||||
final String password = requestDto.getPassword() != null && !"".equals(requestDto.getPassword())
|
||||
? passwordEncoder.encode(requestDto.getPassword())
|
||||
: user.getEncryptedPassword();
|
||||
|
||||
user.update(requestDto.getUserName(), requestDto.getEmail(), password,
|
||||
requestDto.getRoleId(), requestDto.getUserStateCode());
|
||||
|
||||
return userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 refresh token 정보를 필드에 입력한다
|
||||
*
|
||||
* @param userId
|
||||
* @param updateRefreshToken
|
||||
* @return
|
||||
*/
|
||||
@Transactional
|
||||
public String updateRefreshToken(String userId, String updateRefreshToken) {
|
||||
User user = userRepository.findByUserId(userId)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("해당 사용자가 없습니다."));
|
||||
|
||||
user.updateRefreshToken(updateRefreshToken);
|
||||
|
||||
return user.getRoleKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* 토큰으로 사용자를 찾아 반환한다.
|
||||
*
|
||||
* @param refreshToken
|
||||
* @return
|
||||
*/
|
||||
public User findByRefreshToken(String refreshToken) {
|
||||
return userRepository.findByRefreshToken(refreshToken)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("해당 사용자가 없습니다."));
|
||||
}
|
||||
|
||||
/**
|
||||
* 아이디로 사용자를 찾아 반환한다.
|
||||
*
|
||||
* @param userId
|
||||
* @return
|
||||
*/
|
||||
public UserResponseDto findByUserId(String userId) {
|
||||
User user = userRepository.findByUserId(userId)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("해당 사용자가 없습니다."));
|
||||
|
||||
return new UserResponseDto(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 이메일로 사용자를 찾아 반환한다.
|
||||
*
|
||||
* @param email
|
||||
* @return
|
||||
*/
|
||||
public UserResponseDto findByEmail(String email) {
|
||||
User user = userRepository.findByEmail(email)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("해당 사용자가 없습니다."));
|
||||
|
||||
return new UserResponseDto(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 모든 사용자를 생성일 역순으로 정렬하여 조회하여 List<UserListResponseDto> 형태로 반환한다.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<UserListResponseDto> findAllDesc() {
|
||||
return userRepository.findAll(Sort.by(Sort.Direction.DESC, "createdDate")).stream()
|
||||
.map(UserListResponseDto::new) // User의 Stream을 map을 통해 UserListResponseDto로 변환한다. 실제로 .map(user -> new UserListResponseDto(user)) 과 같다.
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* SecurityConfig > configure > UserDetailsService 메소드에서 호출된다.
|
||||
* 스프링 시큐리티에 의해 로그인 대상 사용자의 패스워드와 권한 정보를 DB에서 조회하여 UserDetails 를 리턴한다.
|
||||
*
|
||||
* @param email
|
||||
* @return
|
||||
* @throws UsernameNotFoundException
|
||||
*/
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
|
||||
log.info("loadUserByUsername! email={}", email);
|
||||
// 로그인 실패시 이메일 계정을 로그에 남기기 위해 세팅하고 unsuccessfulAuthentication 메소드에서 받아서 로그에 입력한다.
|
||||
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
|
||||
request.setAttribute("email", email);
|
||||
|
||||
// UsernameNotFoundException 을 던지면 AbstractUserDetailsAuthenticationProvider 에서 BadCredentialsException 으로 처리하기 때문에 IllegalArgumentException 을 발생시켰다.
|
||||
// 사용자가 없는 것인지 패스워드가 잘못된 것인지 구분하기 위함이다.
|
||||
User user = userRepository.findByEmail(email)
|
||||
.orElseThrow(() -> new IllegalArgumentException(getMessage("err.user.notexists")));
|
||||
log.info("{} 사용자 존재함", user);
|
||||
|
||||
if (!UserStateCode.NORMAL.getKey().equals(user.getUserStateCode())) {
|
||||
throw new IllegalArgumentException(getMessage("err.user.state.cantlogin"));
|
||||
}
|
||||
|
||||
// 로그인 유저의 권한 목록 주입
|
||||
ArrayList<GrantedAuthority> authorities = new ArrayList<>();
|
||||
authorities.add(new SimpleGrantedAuthority(user.getRoleKey()));
|
||||
|
||||
if (user.isSocialUser() && user.getEncryptedPassword() == null || "".equals(user.getEncryptedPassword())) { // 소셜 회원이고 비밀번호가 등록되지 않은 경우
|
||||
return new SocialUser(user.getEmail(), authorities);
|
||||
} else {
|
||||
return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getEncryptedPassword(), authorities);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 로그인 후처리
|
||||
*
|
||||
* @param siteId 사이트 id
|
||||
* @param email 이메일
|
||||
* @param successAt 성공 여부
|
||||
* @param failContent 실패 내용
|
||||
*/
|
||||
@Transactional
|
||||
public void loginCallback(Long siteId, String email, Boolean successAt, String failContent) {
|
||||
User user = userRepository.findByEmail(email)
|
||||
.orElseThrow(() -> new IllegalArgumentException(getMessage("err.user.notexists")));
|
||||
|
||||
if (Boolean.TRUE.equals(successAt)) {
|
||||
user.successLogin();
|
||||
} else {
|
||||
user.failLogin();
|
||||
}
|
||||
|
||||
// 로그인 로그 입력
|
||||
loginLogRepository.save(
|
||||
LoginLog.builder()
|
||||
.siteId(siteId)
|
||||
.email(email)
|
||||
.remoteIp(LogUtil.getUserIp())
|
||||
.successAt(successAt)
|
||||
.failContent(failContent)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 이메일 중복 확인
|
||||
*
|
||||
* @param email 이메일
|
||||
* @param userId 사용자 id
|
||||
* @return Boolean 중복 여부
|
||||
*/
|
||||
public Boolean existsEmail(String email, String userId) {
|
||||
if (email == null || "".equals(email)) {
|
||||
throw new BusinessMessageException(getMessage("valid.required.format", new Object[]{getMessage("user.email")}));
|
||||
}
|
||||
|
||||
|
||||
if (userId == null || "".equals(userId)) {
|
||||
return userRepository.findByEmail(email).isPresent();
|
||||
} else {
|
||||
return userRepository.findByEmailAndUserIdNot(email, userId).isPresent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 회원 가입
|
||||
*
|
||||
* @param requestDto 사용자 가입 요청 DTO
|
||||
* @return Boolean 성공 여부
|
||||
*/
|
||||
@Transactional
|
||||
public Boolean join(UserJoinRequestDto requestDto) {
|
||||
boolean exists = existsEmail(requestDto.getEmail(), null);
|
||||
if (exists) {
|
||||
throw new BusinessMessageException(getMessage("msg.join.email.exists"));
|
||||
}
|
||||
|
||||
userRepository.save(requestDto.toEntity(passwordEncoder));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 비밀번호 찾기
|
||||
*
|
||||
* @param requestDto 사용자 비밀번호 찾기 등록 요청 DTO
|
||||
* @return Boolean 메일 전송 여부
|
||||
*/
|
||||
@Transactional
|
||||
public Boolean findPassword(UserFindPasswordSaveRequestDto requestDto) {
|
||||
final String emailAddr = requestDto.getEmailAddr();
|
||||
|
||||
Optional<User> user = userRepository.findByEmailAndUserName(emailAddr, requestDto.getUserName());
|
||||
if (!user.isPresent()) {
|
||||
throw new BusinessMessageException(getMessage("err.user.notexists"));
|
||||
}
|
||||
User entity = user.get();
|
||||
|
||||
// 이메일 전송
|
||||
try {
|
||||
final String mainUrl = requestDto.getMainUrl();
|
||||
final String tokenValue = UUID.randomUUID().toString().replaceAll("-", "");
|
||||
|
||||
final String subject = getMessage("email.user.password.title");
|
||||
//final String text = getMessage("email.user.password.content"); // varchar(2000)
|
||||
final String text = UserPasswordChangeEmailTemplate.html;
|
||||
final String userName = entity.getUserName();
|
||||
final String changePasswordUrl = requestDto.getChangePasswordUrl() + "?token=" + tokenValue;
|
||||
|
||||
MimeMessage message = javaMailSender.createMimeMessage();
|
||||
MimeMessageHelper helper = new MimeMessageHelper(message);
|
||||
|
||||
helper.setTo(emailAddr);
|
||||
helper.setSubject(subject);
|
||||
helper.setText(String.format(text, mainUrl, userName, changePasswordUrl), true); // String.format에서 %를 쓰려면 %%로
|
||||
|
||||
log.info("start send change password email: " + emailAddr);
|
||||
javaMailSender.send(message);
|
||||
|
||||
Integer requestNo = userFindPasswordRepository.findNextRequestNo(emailAddr);
|
||||
UserFindPassword userFindPassword = requestDto.toEntity(requestNo, tokenValue);
|
||||
|
||||
userFindPasswordRepository.save(userFindPassword);
|
||||
|
||||
log.info("end send change password email - emailAddr: " + emailAddr + ", tokenValue: " + tokenValue);
|
||||
} catch (MessagingException e) {
|
||||
e.printStackTrace();
|
||||
String errorMessage = getMessage("err.user.find.password");
|
||||
log.error(errorMessage + ": " + e.getMessage());
|
||||
throw new BusinessMessageException(errorMessage);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
String errorMessage = getMessage("err.user.find.password");
|
||||
log.error(errorMessage + ": " + e.getMessage());
|
||||
throw new BusinessMessageException(errorMessage);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 비밀번호 찾기 유효성 확인
|
||||
*
|
||||
* @param tokenValue 토큰 값
|
||||
* @return Boolean 유효 여부
|
||||
*/
|
||||
@Transactional
|
||||
public Boolean validPassword(String tokenValue) {
|
||||
if (tokenValue == null || "".equals(tokenValue)) {
|
||||
throw new BusinessMessageException(getMessage("err.invalid.input.value"));
|
||||
}
|
||||
|
||||
Optional<UserFindPassword> userPassword = userFindPasswordRepository.findByTokenValue(tokenValue);
|
||||
if (userPassword.isPresent()) {
|
||||
UserFindPassword entity = userPassword.get();
|
||||
|
||||
boolean isExpired = LocalDateTime.now().isAfter(entity.getCreatedDate().plusHours(1)); // 1시간 후 만료
|
||||
if (Boolean.FALSE.equals(entity.getChangeAt()) && !isExpired) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 비밀번호 찾기 변경
|
||||
*
|
||||
* @param requestDto 사용자 비밀번호 수정 요청 DTO
|
||||
* @return Boolean 수정 여부
|
||||
*/
|
||||
@Transactional
|
||||
public Boolean changePassword(UserFindPasswordUpdateRequestDto requestDto) {
|
||||
final String tokenValue = requestDto.getTokenValue();
|
||||
|
||||
Optional<UserFindPassword> userPassword = userFindPasswordRepository.findByTokenValue(tokenValue);
|
||||
|
||||
if (!userPassword.isPresent()) {
|
||||
throw new BusinessMessageException(getMessage("err.user.change.password"));
|
||||
}
|
||||
|
||||
UserFindPassword entity = userPassword.get();
|
||||
if (Boolean.TRUE.equals(entity.getChangeAt()) || LocalDateTime.now().isAfter(entity.getCreatedDate().plusHours(1))) { // 1시간 후 만료
|
||||
throw new BusinessMessageException(getMessage("err.user.change.password"));
|
||||
}
|
||||
|
||||
User user = userRepository.findByEmail(entity.getUserFindPasswordId().getEmailAddr())
|
||||
.orElseThrow(() -> new UsernameNotFoundException("해당 사용자가 없습니다."));
|
||||
|
||||
user.updatePassword(passwordEncoder.encode(requestDto.getPassword())); // 비밀번호 수정
|
||||
|
||||
entity.updateChangeAt(Boolean.TRUE); // 변경 완료
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 비밀번호 변경
|
||||
*
|
||||
* @param userId 사용자 id
|
||||
* @param requestDto 사용자 비밀번호 변경 요청 DTO
|
||||
* @return Boolean 수정 여부
|
||||
*/
|
||||
@Transactional
|
||||
public Boolean updatePassword(String userId, UserPasswordUpdateRequestDto requestDto) {
|
||||
User entity = findUserVerify(userId, requestDto);
|
||||
|
||||
entity.updatePassword(passwordEncoder.encode(requestDto.getNewPassword())); // 비밀번호 수정
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 비밀번호 확인
|
||||
*
|
||||
* @param userId 사용자 id
|
||||
* @param password 비밀번호
|
||||
* @return Boolean 일치 여부
|
||||
*/
|
||||
public Boolean matchPassword(String userId, String password) {
|
||||
try {
|
||||
findUserVerifyPassword(userId, password);
|
||||
} catch (BusinessMessageException e) {
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 id로 조회
|
||||
*
|
||||
* @param userId 사용자 id
|
||||
* @return User 사용자 엔티티
|
||||
*/
|
||||
private User getUserByUserId(String userId) {
|
||||
Optional<User> user = userRepository.findByUserId(userId);
|
||||
if (!user.isPresent()) {
|
||||
throw new BusinessMessageException(getMessage("err.user.notexists"));
|
||||
}
|
||||
|
||||
return user.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 조회, 비밀번호 검증
|
||||
*
|
||||
* @param userId 사용자 id
|
||||
* @param password 비밀번호
|
||||
* @return User 사용자 엔티티
|
||||
*/
|
||||
private User findUserVerifyPassword(String userId, String password) {
|
||||
User entity = getUserByUserId(userId);
|
||||
|
||||
if (!passwordEncoder.matches(password, entity.getEncryptedPassword())) { // 소셜 사용자가 아닌 경우 비밀번호 확인
|
||||
throw new BusinessMessageException(getMessage("err.user.password.notmatch"));
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 정보 수정
|
||||
*
|
||||
* @param userId 사용자 id
|
||||
* @param requestDto 사용자 정보 수정 요청 DTO
|
||||
* @return String 사용자 id
|
||||
*/
|
||||
@Transactional
|
||||
public String updateInfo(String userId, UserUpdateInfoRequestDto requestDto) {
|
||||
User user = findUserVerify(userId, requestDto);
|
||||
|
||||
user.updateInfo(requestDto.getUserName(), requestDto.getEmail());
|
||||
|
||||
return userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 회원탈퇴
|
||||
*
|
||||
* @param userId 사용자 id
|
||||
* @param requestDto 회원 탈퇴 요청 DTO
|
||||
* @return User 사용자 엔티티
|
||||
*/
|
||||
@Transactional
|
||||
public Boolean leave(String userId, UserVerifyRequestDto requestDto) {
|
||||
User entity = findUserVerify(userId, requestDto);
|
||||
|
||||
entity.updateUserStateCode(UserStateCode.LEAVE.getKey());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 검증 및 조회
|
||||
*
|
||||
* @param userId 사용자 id
|
||||
* @param requestDto 회원 탈퇴 요청 DTO
|
||||
* @return User 사용자 엔티티
|
||||
*/
|
||||
private User findUserVerify(String userId, UserVerifyRequestDto requestDto) {
|
||||
User user = null;
|
||||
if ("password".equals(requestDto.getProvider())) {
|
||||
user = findUserVerifyPassword(userId, requestDto.getPassword());
|
||||
} else {
|
||||
user = findSocialUserByToken(requestDto.getProvider(), requestDto.getToken());
|
||||
|
||||
if (user == null) {
|
||||
throw new BusinessMessageException(getMessage("err.user.socail.find"));
|
||||
}
|
||||
if (!userId.equals(user.getUserId())) {
|
||||
throw new BusinessMessageException(getMessage("err.unauthorized"));
|
||||
}
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 삭제
|
||||
*
|
||||
* @param userId 사용자 id
|
||||
* @return User 사용자 엔티티
|
||||
*/
|
||||
@Transactional
|
||||
public Boolean delete(String userId) {
|
||||
User user = getUserByUserId(userId);
|
||||
|
||||
user.updateUserStateCode(UserStateCode.DELETE.getKey());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* OAuth 사용자 검색
|
||||
*
|
||||
* @param requestDto 사용자 로그인 요청 DTO
|
||||
* @return UserLoginRequestDto 사용자 로그인 요청 DTO
|
||||
*/
|
||||
@Transactional
|
||||
public UserResponseDto loadUserBySocial(UserLoginRequestDto requestDto) {
|
||||
String[] userInfo = getSocialUserInfo(requestDto.getProvider(), requestDto.getToken());
|
||||
|
||||
UserResponseDto userDto = getAndSaveSocialUser(requestDto.getProvider(), userInfo[0], userInfo[1], userInfo[2]);
|
||||
|
||||
if (userDto == null) {
|
||||
throw new BusinessMessageException(getMessage("err.user.join.social"));
|
||||
}
|
||||
if (!UserStateCode.NORMAL.getKey().equals(userDto.getUserStateCode())) {
|
||||
throw new BusinessMessageException(getMessage("err.user.state.cantlogin"));
|
||||
}
|
||||
|
||||
return userDto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 토큰으로 사용자 엔티티 조회
|
||||
*
|
||||
* @param provider 공급자
|
||||
* @param token 토큰
|
||||
* @return User 사용자 엔티티
|
||||
*/
|
||||
private User findSocialUserByToken(String provider, String token) {
|
||||
String[] userInfo = getSocialUserInfo(provider, token);
|
||||
|
||||
return findSocialUser(provider, userInfo[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 토큰으로 소셜 사용자 정보 조회
|
||||
*
|
||||
* @param provider 공급자
|
||||
* @param token 토큰
|
||||
* @return String[] 소셜 사용자 정보
|
||||
*/
|
||||
private String[] getSocialUserInfo(String provider, String token) {
|
||||
String[] userInfo = null;
|
||||
|
||||
switch (provider) {
|
||||
case "google":
|
||||
userInfo = getGoogleUserInfo(token);
|
||||
break;
|
||||
case "naver":
|
||||
userInfo = getNaverUserInfo(token);
|
||||
break;
|
||||
case "kakao":
|
||||
userInfo = getKakaoUserInfo(token);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (userInfo == null) throw new BusinessMessageException(getMessage("err.user.social.get"));
|
||||
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 구글 사용자 정보 조회
|
||||
*
|
||||
* @param token 토큰
|
||||
* @return String[] 구글 사용자 정보
|
||||
*/
|
||||
private String[] getGoogleUserInfo(String token) {
|
||||
try {
|
||||
HttpTransport transport = new NetHttpTransport();
|
||||
GsonFactory gsonFactory = new GsonFactory();
|
||||
|
||||
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, gsonFactory)
|
||||
.setAudience(Collections.singletonList(GOOGLE_CLIENT_ID))
|
||||
.build();
|
||||
|
||||
GoogleIdToken idToken = verifier.verify(token);
|
||||
|
||||
GoogleIdToken.Payload payload = idToken.getPayload();
|
||||
log.info("google oauth2: {}", payload.toString());
|
||||
|
||||
return new String[]{
|
||||
payload.getSubject(),
|
||||
payload.getEmail(),
|
||||
(String) payload.get("name")
|
||||
};
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new BusinessMessageException(getMessage("err.user.social.get"));
|
||||
} catch (IOException e) {
|
||||
throw new BusinessMessageException(getMessage("err.user.social.get"));
|
||||
} catch (Exception e) {
|
||||
throw new BusinessMessageException(getMessage("err.user.social.get"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 네이버 사용자 정보 조회
|
||||
*
|
||||
* @param token 토큰
|
||||
* @return String[] 네이버 사용자 정보
|
||||
*/
|
||||
private String[] getNaverUserInfo(String token) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.set("Authorization", "Bearer " + token);
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
|
||||
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
||||
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);
|
||||
|
||||
ResponseEntity<String> response = restTemplate.exchange(NAVER_USER_INFO_URI, HttpMethod.GET, request, String.class);
|
||||
|
||||
if (response.getBody() != null && !"".equals(response.getBody())) {
|
||||
JsonElement element = JsonParser.parseString(response.getBody());
|
||||
JsonObject object = element.getAsJsonObject();
|
||||
log.info("naver oauth2: {}", object.toString());
|
||||
|
||||
if (object.get("resultcode") != null && "00".equals(object.get("resultcode").getAsString())) {
|
||||
return new String[]{
|
||||
object.get("response").getAsJsonObject().get("id").getAsString(),
|
||||
object.get("response").getAsJsonObject().get("email").getAsString(),
|
||||
object.get("response").getAsJsonObject().get("name").getAsString()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 카카오 사용자 정보 조회
|
||||
*
|
||||
* @param token 토큰
|
||||
* @return String[] 카카오 사용자 정보
|
||||
*/
|
||||
private String[] getKakaoUserInfo(String token) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.set("Authorization", "Bearer " + token);
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
|
||||
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
||||
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);
|
||||
|
||||
ResponseEntity<String> response = restTemplate.exchange(KAKAO_USER_INFO_URI, HttpMethod.GET, request, String.class);
|
||||
|
||||
if (response.getBody() != null && !"".equals(response.getBody())) {
|
||||
JsonElement element = JsonParser.parseString(response.getBody());
|
||||
JsonObject object = element.getAsJsonObject();
|
||||
log.info("kakao oauth2: {}", object.toString());
|
||||
|
||||
if (object.get("id") != null && !"".equals(object.get("id").getAsString())) {
|
||||
return new String[]{
|
||||
object.get("id").getAsString(),
|
||||
object.get("kakao_account").getAsJsonObject().get("email").getAsString(),
|
||||
object.get("kakao_account").getAsJsonObject().get("profile").getAsJsonObject().get("nickname").getAsString()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 소셜 사용자 엔티티 조회
|
||||
*
|
||||
* @param providerCode 공급자 코드
|
||||
* @param providerId 공급자 id
|
||||
* @return User 사용자 엔티티
|
||||
*/
|
||||
private User findSocialUser(String providerCode, String providerId) {
|
||||
Optional<User> user;
|
||||
|
||||
// 공급자 id로 조회
|
||||
switch (providerCode) {
|
||||
case "google":
|
||||
user = userRepository.findByGoogleId(providerId);
|
||||
break;
|
||||
case "kakao":
|
||||
user = userRepository.findByKakaoId(providerId);
|
||||
break;
|
||||
case "naver":
|
||||
user = userRepository.findByNaverId(providerId);
|
||||
break;
|
||||
default:
|
||||
user = Optional.empty();
|
||||
break;
|
||||
}
|
||||
|
||||
return user.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 소셜 사용자 엔티티 조회
|
||||
* 등록되어 있지 않은 경우 사용자 등록
|
||||
*
|
||||
* @param providerCode 공급자 코드
|
||||
* @param providerId 공급자 id
|
||||
* @param email 이메일
|
||||
* @param userName 사용자 명
|
||||
* @return UserLoginRequestDto 사용자 로그인 요청 DTO
|
||||
*/
|
||||
private UserResponseDto getAndSaveSocialUser(String providerCode, String providerId, String email, String userName) {
|
||||
User user = findSocialUser(providerCode, providerId);
|
||||
|
||||
// 이메일로 조회
|
||||
// 공급자에서 동일한 이메일을 사용할 수 있고
|
||||
// 현재 시스템 구조 상 이메일을 사용자 식별키로 사용하고 있어서 이메일로 사용자를 한번 더 검색한다.
|
||||
if (user == null) {
|
||||
user = userRepository.findByEmail(email).orElse(null);
|
||||
|
||||
// 공급자 id로 조회되지 않지만 이메일로 조회되는 경우 공급자 id 등록
|
||||
if (user != null) {
|
||||
switch (providerCode) {
|
||||
case "google":
|
||||
user = user.updateGoogleId(providerId);
|
||||
break;
|
||||
case "kakao":
|
||||
user = user.updateKakaoId(providerId);
|
||||
break;
|
||||
case "naver":
|
||||
user = user.updateNaverId(providerId);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (user == null) {
|
||||
// 사용자 등록
|
||||
final String userId = UUID.randomUUID().toString();
|
||||
//final String password = makeRandomPassword(); // 임의 비밀번호 생성 시 복호화 불가능
|
||||
|
||||
User.UserBuilder userBuilder = User.builder()
|
||||
.email(email) // 100byte
|
||||
//.encryptedPassword(passwordEncoder.encode(password)) // 100 byte
|
||||
.userName(userName)
|
||||
.userId(userId)
|
||||
.role(Role.USER)
|
||||
.userStateCode(UserStateCode.NORMAL.getKey());
|
||||
|
||||
switch (providerCode) {
|
||||
case "google":
|
||||
user = userBuilder.googleId(providerId).build();
|
||||
break;
|
||||
case "kakao":
|
||||
user = userBuilder.kakaoId(providerId).build();
|
||||
break;
|
||||
case "naver":
|
||||
user = userBuilder.naverId(providerId).build();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (user != null) {
|
||||
userRepository.save(user);
|
||||
}
|
||||
}
|
||||
|
||||
return user == null ? null : new UserResponseDto(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* 임의 비밀번호 10자리 생성
|
||||
*
|
||||
* @return String 비밀번호
|
||||
*/
|
||||
private String makeRandomPassword() {
|
||||
char[] terms = new char[]{
|
||||
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'!', '@', '#', '$', '%', '^', '&', '*', '(', ')'};
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
int index = (int) (Math.random() * terms.length);
|
||||
sb.append(terms[index]);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
# oauth2 를 사용하기 위해서는 아래의 TODO 를 등록해야 함
|
||||
spring:
|
||||
security:
|
||||
oauth2:
|
||||
client:
|
||||
registration:
|
||||
# /oauth2/authorization/google
|
||||
google:
|
||||
client-id: google_client_id # TODO
|
||||
client-secret: google_client_secret # TODO
|
||||
scope: profile,email
|
||||
# 네이버는 Spring Security를 공식 지원하지 않기 때문에 CommonOAuth2Provider 에서 해주는 값들을 수동으로 입력한다.
|
||||
# /oauth2/authorization/naver
|
||||
naver:
|
||||
client-id: naver_client_id # TODO
|
||||
client-secret: naver_client_secret # TODO
|
||||
redirect_uri: "{baseUrl}/{action}/oauth2/code/{registrationId}"
|
||||
authorization_grant_type: authorization_code
|
||||
scope: name,email,profile_image
|
||||
client-name: Naver
|
||||
# /oauth2/authorization/kakao
|
||||
kakao:
|
||||
client-id: kakao_client_id # TODO
|
||||
client-secret: kakao_client_secret # TODO
|
||||
redirect-uri: "{baseUrl}/{action}/oauth2/code/{registrationId}"
|
||||
client-authentication-method: POST
|
||||
authorization-grant-type: authorization_code
|
||||
scope: profile_nickname, account_email
|
||||
client-name: Kakao
|
||||
provider:
|
||||
naver:
|
||||
authorization_uri: https://nid.naver.com/oauth2.0/authorize
|
||||
token_uri: https://nid.naver.com/oauth2.0/token
|
||||
user-info-uri: https://openapi.naver.com/v1/nid/me
|
||||
# 기준이 되는 user_name 의 이름을 네이버에서는 response로 지정해야한다. (네이버 회원 조회시 반환되는 JSON 형태 때문이다)
|
||||
# response를 user_name으로 지정하고 이후 자바 코드로 response의 id를 user_name으로 지정한다. (스프링 시큐리티에서 하위 필드를 명시할 수 없기 때문)
|
||||
user_name_attribute: response
|
||||
kakao:
|
||||
authorization_uri: https://kauth.kakao.com/oauth/authorize
|
||||
token_uri: https://kauth.kakao.com/oauth/token
|
||||
user-info-uri: https://kapi.kakao.com/v2/user/me
|
||||
user_name_attribute: id
|
||||
66
backend/user-service/src/main/resources/application.yml
Normal file
66
backend/user-service/src/main/resources/application.yml
Normal file
@@ -0,0 +1,66 @@
|
||||
server:
|
||||
port: 0 # random port
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: user-service
|
||||
profiles:
|
||||
group:
|
||||
default: oauth
|
||||
docker: oauth
|
||||
cf: oauth
|
||||
k8s: oauth
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: none
|
||||
properties:
|
||||
hibernate:
|
||||
dialect: org.hibernate.dialect.MySQL57Dialect
|
||||
storage_engine: innodb
|
||||
format_sql: true
|
||||
default_batch_fetch_size: 1000
|
||||
jdbc:
|
||||
batch_size: 1000
|
||||
order_inserts: true
|
||||
order_updates: true
|
||||
show-sql: true
|
||||
cache:
|
||||
jcache:
|
||||
config: classpath:ehcache.xml
|
||||
|
||||
# config server actuator
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: refresh, health, beans
|
||||
health:
|
||||
mail:
|
||||
enabled: false
|
||||
|
||||
# @TODO application-oauth.yml
|
||||
# spring:
|
||||
# security:
|
||||
# oauth2:
|
||||
# client:
|
||||
# registration:
|
||||
# google:
|
||||
# client-id: @TODO https://console.cloud.google.com
|
||||
# client-secret: @TODO
|
||||
# scope: profile,email
|
||||
# # 네이버는 Spring Security를 공식 지원하지 않기 때문에 CommonOAuth2Provider 에서 해주는 값들을 수동으로 입력한다.
|
||||
# naver:
|
||||
# client-id: @TODO https://developers.naver.com/apps/#/register?api=nvlogin
|
||||
# client-secret: @TODO
|
||||
# redirect_uri_template: "{baseUrl}/{action}/oauth2/code/{registrationId}"
|
||||
# authorization_grant_type: authorization_code
|
||||
# scope: name,email,profile_image
|
||||
# client-name: Naver
|
||||
# provider:
|
||||
# naver:
|
||||
# authorization_uri: https://nid.naver.com/oauth2.0/authorize
|
||||
# token_uri: https://nid.naver.com/oauth2.0/token
|
||||
# user-info-uri: https://openapi.naver.com/v1/nid/me
|
||||
# # 기준이 되는 user_name 의 이름을 네이버에서는 response로 지정해야한다. (네이버 회원 조회시 반환되는 JSON 형태 때문이다)
|
||||
# # response를 user_name으로 지정하고 이후 자바 코드로 response의 id를 user_name으로 지정한다. (스프링 시큐리티에서 하위 필드를 명시할 수 없기 때문)
|
||||
# user_name_attribute: response
|
||||
8
backend/user-service/src/main/resources/bootstrap.yml
Normal file
8
backend/user-service/src/main/resources/bootstrap.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
spring:
|
||||
cloud:
|
||||
config:
|
||||
uri: http://localhost:8888
|
||||
name: user-service # user-service.yml이 있으면 불러오게 된다
|
||||
# name: config-service # config-service의 application.yml 을 불러오게 된다
|
||||
# profiles:
|
||||
# active: prod # application-prod.yml
|
||||
51
backend/user-service/src/main/resources/ehcache.xml
Normal file
51
backend/user-service/src/main/resources/ehcache.xml
Normal file
@@ -0,0 +1,51 @@
|
||||
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
|
||||
xmlns='http://www.ehcache.org/v3'
|
||||
xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd">
|
||||
|
||||
<cache alias="cache-user-authorization-by-roles"> <!-- 캐시 이름 -->
|
||||
<key-type>java.util.List</key-type> <!-- 캐시 키 타입 -->
|
||||
<value-type>java.util.List</value-type> <!-- 캐시 저장 값 타입 -->
|
||||
<expiry>
|
||||
<ttl unit="minutes">3</ttl> <!-- 만료 시간 -->
|
||||
</expiry>
|
||||
|
||||
<listeners>
|
||||
<listener>
|
||||
<class>org.egovframe.cloud.userservice.config.CacheEventLogger</class> <!-- 캐시 이벤트 리스너 -->
|
||||
<event-firing-mode>ASYNCHRONOUS</event-firing-mode>
|
||||
<event-ordering-mode>UNORDERED</event-ordering-mode>
|
||||
<events-to-fire-on>CREATED</events-to-fire-on>
|
||||
<events-to-fire-on>EXPIRED</events-to-fire-on>
|
||||
</listener>
|
||||
</listeners>
|
||||
|
||||
<resources>
|
||||
<heap unit="entries">2000</heap> <!-- 힙 사이즈 -->
|
||||
<offheap unit="MB">1</offheap> <!-- 힙 사이즈가 부족할 경우 디스크 사용 용량 -->
|
||||
</resources>
|
||||
</cache>
|
||||
|
||||
<cache alias="cache-user-authorization-by-userid"> <!-- 캐시 이름 -->
|
||||
<key-type>java.lang.String</key-type> <!-- 캐시 키 타입 -->
|
||||
<value-type>java.util.List</value-type> <!-- 캐시 저장 값 타입 -->
|
||||
<expiry>
|
||||
<ttl unit="minutes">3</ttl> <!-- 만료 시간 -->
|
||||
</expiry>
|
||||
|
||||
<listeners>
|
||||
<listener>
|
||||
<class>org.egovframe.cloud.userservice.config.CacheEventLogger</class> <!-- 캐시 이벤트 리스너 -->
|
||||
<event-firing-mode>ASYNCHRONOUS</event-firing-mode>
|
||||
<event-ordering-mode>UNORDERED</event-ordering-mode>
|
||||
<events-to-fire-on>CREATED</events-to-fire-on>
|
||||
<events-to-fire-on>EXPIRED</events-to-fire-on>
|
||||
</listener>
|
||||
</listeners>
|
||||
|
||||
<resources>
|
||||
<heap unit="entries">2000</heap> <!-- 힙 사이즈 -->
|
||||
<offheap unit="MB">1</offheap> <!-- 힙 사이즈가 부족할 경우 디스크 사용 용량 -->
|
||||
</resources>
|
||||
</cache>
|
||||
|
||||
</config>
|
||||
34
backend/user-service/src/main/resources/logback-spring.xml
Normal file
34
backend/user-service/src/main/resources/logback-spring.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %thread %-5level %logger - %m%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 로컬에서는 로그를 전송하지 않도록 설정 -->
|
||||
<springProfile name="default">
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</springProfile>
|
||||
<springProfile name="!default">
|
||||
<!-- java -Ddestination="localhost:8088" 와 같이 변경할 수 있다. cf 환경에서는 manifest.yml 파일에 환경변수로 추가 -->
|
||||
<property name="destination" value="localhost:8088" />
|
||||
<property name="app_name" value="${app_name}" />
|
||||
|
||||
<!-- ELK - Logstash 로 로그를 전송하기 위한 appender -->
|
||||
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
|
||||
<destination>${destination}</destination><!-- native profile => localhost:8088 -->
|
||||
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
|
||||
<customFields>{"app.name":"${app_name}"}</customFields>
|
||||
</encoder>
|
||||
</appender>
|
||||
<root level="WARN">
|
||||
<appender-ref ref="LOGSTASH" />
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</springProfile>
|
||||
|
||||
</configuration>
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.egovframe.cloud.userservice;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class UserServiceApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package org.egovframe.cloud.userservice.api;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.egovframe.cloud.common.domain.Role;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserResponseDto;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserSaveRequestDto;
|
||||
import org.egovframe.cloud.userservice.api.user.dto.UserUpdateRequestDto;
|
||||
import org.egovframe.cloud.userservice.domain.user.User;
|
||||
import org.egovframe.cloud.userservice.domain.user.UserRepository;
|
||||
import org.egovframe.cloud.userservice.service.user.UserService;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@EnableConfigurationProperties
|
||||
@TestPropertySource(properties = {"spring.config.location=classpath:application-test.yml"})
|
||||
@ActiveProfiles(profiles = "test")
|
||||
class UserApiControllerTest {
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
// private static final String USER_SERVICE_URL = "http://localhost:8000/user-service";
|
||||
private static final String TEST_COM = "@test.com";
|
||||
private static final String TEST_EMAIL = System.currentTimeMillis() + TEST_COM;
|
||||
private static final String TEST_PASSWORD = "test1234!";
|
||||
|
||||
@Test
|
||||
@Order(Integer.MAX_VALUE)
|
||||
public void cleanup() throws Exception {
|
||||
// 테스트 후 데이터 삭제
|
||||
List<User> users = userRepository.findByEmailContains("test.com");
|
||||
users.forEach(user -> userRepository.deleteById(user.getId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(Integer.MIN_VALUE)
|
||||
public void 사용자_등록된다() throws Exception {
|
||||
// given
|
||||
UserSaveRequestDto userSaveRequestDto = UserSaveRequestDto.builder()
|
||||
.userName("사용자")
|
||||
.email(TEST_EMAIL)
|
||||
.password(TEST_PASSWORD)
|
||||
.roleId(Role.USER.getKey())
|
||||
.userStateCode("01")
|
||||
.build();
|
||||
userService.save(userSaveRequestDto);
|
||||
|
||||
// when
|
||||
UserResponseDto findUser = userService.findByEmail(TEST_EMAIL);
|
||||
|
||||
// then
|
||||
assertThat(findUser.getEmail()).isEqualTo(TEST_EMAIL);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void 사용자_수정된다() throws Exception {
|
||||
// given
|
||||
UserResponseDto findUser = userService.findByEmail(TEST_EMAIL);
|
||||
UserUpdateRequestDto userUpdateRequestDto = UserUpdateRequestDto.builder()
|
||||
.userName("사용자수정")
|
||||
.email(TEST_EMAIL)
|
||||
.roleId(Role.USER.getKey())
|
||||
.userStateCode("01")
|
||||
.build();
|
||||
|
||||
// when
|
||||
userService.update(findUser.getUserId(), userUpdateRequestDto);
|
||||
UserResponseDto updatedUser = userService.findByEmail(TEST_EMAIL);
|
||||
|
||||
// then
|
||||
assertThat(updatedUser.getUserName()).isEqualTo("사용자수정");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void 사용자_등록오류() throws Exception {
|
||||
// given
|
||||
UserSaveRequestDto userSaveRequestDto = UserSaveRequestDto.builder()
|
||||
.userName("사용자")
|
||||
.email("email")
|
||||
.password("test")
|
||||
.build();
|
||||
|
||||
String url = "/api/v1/users";
|
||||
|
||||
RestClientException restClientException = Assertions.assertThrows(RestClientException.class, () -> {
|
||||
restTemplate.postForEntity(url, userSaveRequestDto, Long.class);
|
||||
});
|
||||
System.out.println("restClientException.getMessage() = " + restClientException.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void 사용자_로그인된다() throws Exception {
|
||||
// given
|
||||
JSONObject loginJson = new JSONObject();
|
||||
loginJson.put("email", TEST_EMAIL);
|
||||
loginJson.put("password", TEST_PASSWORD);
|
||||
|
||||
String url = "/login";
|
||||
|
||||
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, loginJson.toString(), String.class);
|
||||
responseEntity.getHeaders().entrySet().forEach(System.out::println);
|
||||
assertThat(responseEntity.getHeaders().containsKey("access-token")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void 사용자_로그인_오류발생한다() throws Exception {
|
||||
// given
|
||||
JSONObject loginJson = new JSONObject();
|
||||
loginJson.put("email", TEST_EMAIL);
|
||||
loginJson.put("password", "test");
|
||||
|
||||
String url = "/login";
|
||||
|
||||
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, loginJson.toString(), String.class);
|
||||
System.out.println("responseEntity = " + responseEntity);
|
||||
assertThat(responseEntity.getHeaders().containsKey("access-token")).isFalse();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,403 @@
|
||||
package org.egovframe.cloud.userservice.api.role;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.egovframe.cloud.userservice.domain.role.Authorization;
|
||||
import org.egovframe.cloud.userservice.domain.role.AuthorizationRepository;
|
||||
import org.egovframe.cloud.userservice.domain.role.RoleAuthorization;
|
||||
import org.egovframe.cloud.userservice.domain.role.RoleAuthorizationRepository;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.filter.CharacterEncodingFilter;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.role.AuthorizationApiControllerTest
|
||||
* <p>
|
||||
* 인가 Rest API 컨트롤러 테스트 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/08
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/08 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@EnableConfigurationProperties
|
||||
@TestPropertySource(properties = {"spring.config.location=classpath:application-test.yml"})
|
||||
@ActiveProfiles(profiles = "test")
|
||||
class AuthorizationApiControllerTest {
|
||||
|
||||
/**
|
||||
* WebApplicationContext
|
||||
*/
|
||||
@Autowired
|
||||
private WebApplicationContext context;
|
||||
|
||||
/**
|
||||
* MockMvc
|
||||
*/
|
||||
private MockMvc mvc;
|
||||
|
||||
/**
|
||||
* ObjectMapper
|
||||
*/
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
* test rest template
|
||||
*/
|
||||
@Autowired
|
||||
TestRestTemplate restTemplate;
|
||||
|
||||
/**
|
||||
* 인가 레파지토리 인터페이스
|
||||
*/
|
||||
@Autowired
|
||||
AuthorizationRepository authorizationRepository;
|
||||
|
||||
/**
|
||||
* 권한 인가 레파지토리 인터페이스
|
||||
*/
|
||||
@Autowired
|
||||
RoleAuthorizationRepository roleAuthorizationRepository;
|
||||
|
||||
/**
|
||||
* 인가 API 경로
|
||||
*/
|
||||
private static final String URL = "/api/v1/authorizations";
|
||||
|
||||
/**
|
||||
* 테스트 데이터 등록 횟수
|
||||
*/
|
||||
private final Integer GIVEN_DATA_COUNT = 10;
|
||||
|
||||
/**
|
||||
* 테스트 데이터
|
||||
*/
|
||||
private final String AUTHORIZATION_NAME_PREFIX = "인가 명";
|
||||
//private final String URL_PATTERN_VALUE_PREFIX = "URL 패턴 값";
|
||||
private final String URL_PATTERN_VALUE_PREFIX = "/api/v1/authorizations";
|
||||
//private final String HTTP_METHOD_VALUE_PREFIX = "Http Method 코드";
|
||||
private final String HTTP_METHOD_VALUE_PREFIX = "GET";
|
||||
|
||||
private final String INSERT_AUTHORIZATION_NAME = AUTHORIZATION_NAME_PREFIX + "_1";
|
||||
private final String INSERT_URL_PATTERN_VALUE = URL_PATTERN_VALUE_PREFIX + "_1";
|
||||
private final String INSERT_HTTP_METHOD_VALUE = HTTP_METHOD_VALUE_PREFIX + "_1";
|
||||
private final Integer INSERT_SORT_SEQ = 2;
|
||||
|
||||
private final String UPDATE_AUTHORIZATION_NAME = AUTHORIZATION_NAME_PREFIX + "_2";
|
||||
private final String UPDATE_URL_PATTERN_VALUE = URL_PATTERN_VALUE_PREFIX + "_";
|
||||
private final String UPDATE_HTTP_METHOD_VALUE = HTTP_METHOD_VALUE_PREFIX + "_";
|
||||
private final Integer UPDATE_SORT_SEQ = 2;
|
||||
|
||||
/**
|
||||
* 테스트 데이터
|
||||
*/
|
||||
private List<Authorization> testDatas = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 테스트 시작 전 수행
|
||||
*/
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
mvc = MockMvcBuilders.webAppContextSetup(context)
|
||||
.addFilter(new CharacterEncodingFilter("UTF-8"))
|
||||
.apply(SecurityMockMvcConfigurers.springSecurity())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 테스트 종료 후 수행
|
||||
*/
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 페이지 목록 조회 테스트
|
||||
*/
|
||||
@Test
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
void 인가_페이지_목록_조회() throws Exception {
|
||||
// given
|
||||
insertTestDatas();
|
||||
|
||||
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
||||
params.add("keywordType", "authorizationName");
|
||||
params.add("keyword", AUTHORIZATION_NAME_PREFIX);
|
||||
params.add("page", "0");
|
||||
params.add("size", "10");
|
||||
|
||||
// when
|
||||
ResultActions resultActions = mvc.perform(MockMvcRequestBuilders.get(URL)
|
||||
.params(params));
|
||||
|
||||
// then
|
||||
resultActions
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
// .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.numberOfElements").value(GIVEN_DATA_COUNT))
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.content[0].authorizationName").value(AUTHORIZATION_NAME_PREFIX + "_1"));
|
||||
|
||||
deleteTestDatas();
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 상세 조회 테스트
|
||||
*/
|
||||
@Test
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
void 인가_상세_조회() throws Exception {
|
||||
// given
|
||||
Authorization entity = insertTestData();
|
||||
|
||||
final Integer authorizationNo = entity.getAuthorizationNo();
|
||||
|
||||
// when
|
||||
ResultActions resultActions = mvc.perform(MockMvcRequestBuilders.get(URL + "/" + authorizationNo));
|
||||
|
||||
// then
|
||||
resultActions
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.authorizationNo").value(authorizationNo))
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.authorizationName").value(INSERT_AUTHORIZATION_NAME))
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.urlPatternValue").value(INSERT_URL_PATTERN_VALUE))
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.httpMethodCode").value(INSERT_HTTP_METHOD_VALUE))
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.sortSeq").value(INSERT_SORT_SEQ));
|
||||
|
||||
deleteTestData(authorizationNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 다음 정렬 순서 조회
|
||||
*/
|
||||
@Test
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
void 인가_다음정렬순서_조회() throws Exception {
|
||||
// given
|
||||
insertTestDatas();
|
||||
|
||||
// when
|
||||
ResultActions resultActions = mvc.perform(MockMvcRequestBuilders.get(URL + "/sort-seq/next"));
|
||||
|
||||
// then
|
||||
resultActions
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
// .andExpect(MockMvcResultMatchers.content().string("11"));
|
||||
.andExpect(MockMvcResultMatchers.content().string("129")); // /src/test/resources/h2/data.sql 초기화 데이터의 마지막 순번 + 1
|
||||
|
||||
deleteTestDatas();
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 등록 테스트
|
||||
*/
|
||||
@Test
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
void 인가_등록() throws Exception {
|
||||
// given
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("authorizationName", INSERT_AUTHORIZATION_NAME);
|
||||
params.put("urlPatternValue", INSERT_URL_PATTERN_VALUE);
|
||||
params.put("httpMethodCode", INSERT_HTTP_METHOD_VALUE);
|
||||
params.put("sortSeq", INSERT_SORT_SEQ);
|
||||
|
||||
// when
|
||||
ResultActions resultActions = mvc.perform(MockMvcRequestBuilders.post(URL)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.contentType("application/json;charset=UTF-8")
|
||||
.content(objectMapper.writeValueAsString(params)));
|
||||
|
||||
// then
|
||||
resultActions
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(MockMvcResultMatchers.status().isOk());
|
||||
|
||||
String responseData = resultActions.andReturn().getResponse().getContentAsString();
|
||||
JSONObject jsonObject = new JSONObject(responseData);
|
||||
|
||||
final Integer authorizationNo = Integer.parseInt(jsonObject.get("authorizationNo").toString());
|
||||
|
||||
Optional<Authorization> authorization = selectData(authorizationNo);
|
||||
assertThat(authorization).isPresent();
|
||||
|
||||
Authorization entity = authorization.get();
|
||||
assertThat(entity.getAuthorizationNo()).isEqualTo(authorizationNo);
|
||||
assertThat(entity.getAuthorizationName()).isEqualTo(INSERT_AUTHORIZATION_NAME);
|
||||
assertThat(entity.getUrlPatternValue()).isEqualTo(INSERT_URL_PATTERN_VALUE);
|
||||
assertThat(entity.getHttpMethodCode()).isEqualTo(INSERT_HTTP_METHOD_VALUE);
|
||||
assertThat(entity.getSortSeq()).isEqualTo(INSERT_SORT_SEQ);
|
||||
|
||||
deleteTestData(authorizationNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 수정 테스트
|
||||
*/
|
||||
@Test
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
void 인가_수정() throws Exception {
|
||||
// given
|
||||
Authorization entity = insertTestData();
|
||||
|
||||
final Integer authorizationNo = entity.getAuthorizationNo();
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("authorizationName", UPDATE_AUTHORIZATION_NAME);
|
||||
params.put("urlPatternValue", UPDATE_URL_PATTERN_VALUE);
|
||||
params.put("httpMethodCode", UPDATE_HTTP_METHOD_VALUE);
|
||||
params.put("sortSeq", UPDATE_SORT_SEQ);
|
||||
|
||||
// when
|
||||
ResultActions resultActions = mvc.perform(MockMvcRequestBuilders.put(URL + "/" + authorizationNo)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.contentType("application/json;charset=UTF-8")
|
||||
.content(objectMapper.writeValueAsString(params)));
|
||||
|
||||
// then
|
||||
resultActions
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(MockMvcResultMatchers.status().isOk());
|
||||
|
||||
Optional<Authorization> authorization = selectData(authorizationNo);
|
||||
assertThat(authorization).isPresent();
|
||||
|
||||
Authorization updatedAuthorization = authorization.get();
|
||||
assertThat(updatedAuthorization.getAuthorizationNo()).isEqualTo(authorizationNo);
|
||||
assertThat(updatedAuthorization.getAuthorizationName()).isEqualTo(UPDATE_AUTHORIZATION_NAME);
|
||||
assertThat(updatedAuthorization.getUrlPatternValue()).isEqualTo(UPDATE_URL_PATTERN_VALUE);
|
||||
assertThat(updatedAuthorization.getHttpMethodCode()).isEqualTo(UPDATE_HTTP_METHOD_VALUE);
|
||||
assertThat(updatedAuthorization.getSortSeq()).isEqualTo(UPDATE_SORT_SEQ);
|
||||
|
||||
deleteTestData(authorizationNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 인가 삭제 테스트
|
||||
*/
|
||||
@Test
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
void 인가_삭제() throws Exception {
|
||||
// given
|
||||
Authorization entity = insertTestData();
|
||||
|
||||
final Integer authorizationNo = entity.getAuthorizationNo();
|
||||
|
||||
// 권한 인가 2건 등록 후 같이 삭제
|
||||
roleAuthorizationRepository.save(RoleAuthorization.builder()
|
||||
.roleId("ROLE_1")
|
||||
.authorizationNo(authorizationNo)
|
||||
.build());
|
||||
roleAuthorizationRepository.save(RoleAuthorization.builder()
|
||||
.roleId("ROLE_2")
|
||||
.authorizationNo(authorizationNo)
|
||||
.build());
|
||||
|
||||
// when
|
||||
ResultActions resultActions = mvc.perform(MockMvcRequestBuilders.delete(URL + "/" + authorizationNo));
|
||||
|
||||
// then
|
||||
resultActions
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(MockMvcResultMatchers.status().isOk());
|
||||
|
||||
Optional<Authorization> authorization = selectData(authorizationNo);
|
||||
assertThat(authorization).isNotPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
* 테스트 데이터 등록
|
||||
*/
|
||||
private void insertTestDatas() {
|
||||
for (int i = 1; i <= GIVEN_DATA_COUNT; i++) {
|
||||
testDatas.add(authorizationRepository.save(Authorization.builder()
|
||||
.authorizationName(AUTHORIZATION_NAME_PREFIX + "_" + i)
|
||||
.urlPatternValue(URL_PATTERN_VALUE_PREFIX + "_" + i)
|
||||
.httpMethodCode(HTTP_METHOD_VALUE_PREFIX + "_" + i)
|
||||
.sortSeq(i)
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 테스트 데이터 삭제
|
||||
*/
|
||||
private void deleteTestDatas() {
|
||||
if (testDatas != null) {
|
||||
if (!testDatas.isEmpty()) authorizationRepository.deleteAll(testDatas);
|
||||
|
||||
testDatas.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 테스트 데이터 단건 등록
|
||||
*
|
||||
* @return Authorization 인가 엔티티
|
||||
*/
|
||||
private Authorization insertTestData() {
|
||||
return authorizationRepository.save(Authorization.builder()
|
||||
.authorizationName(INSERT_AUTHORIZATION_NAME)
|
||||
.urlPatternValue(INSERT_URL_PATTERN_VALUE)
|
||||
.httpMethodCode(INSERT_HTTP_METHOD_VALUE)
|
||||
.sortSeq(INSERT_SORT_SEQ)
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* 테스트 데이터 단건 삭제
|
||||
*/
|
||||
private void deleteTestData(Integer authorizationNo) {
|
||||
authorizationRepository.deleteById(authorizationNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 테스트 데이터 단건 조회
|
||||
*
|
||||
* @param authorizationNo 인가 번호
|
||||
* @return Optional<Authorization> 인가 엔티티
|
||||
*/
|
||||
private Optional<Authorization> selectData(Integer authorizationNo) {
|
||||
return authorizationRepository.findById(authorizationNo);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
package org.egovframe.cloud.userservice.api.role;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.egovframe.cloud.userservice.domain.role.Role;
|
||||
import org.egovframe.cloud.userservice.domain.role.RoleRepository;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.filter.CharacterEncodingFilter;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.role.RoleApiControllerTest
|
||||
* <p>
|
||||
* 권한 Rest API 컨트롤러 테스트 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/07
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/07 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@EnableConfigurationProperties
|
||||
@TestPropertySource(properties = {"spring.config.location=classpath:application-test.yml"})
|
||||
@ActiveProfiles(profiles = "test")
|
||||
class RoleApiControllerTest {
|
||||
|
||||
/**
|
||||
* WebApplicationContext
|
||||
*/
|
||||
@Autowired
|
||||
private WebApplicationContext context;
|
||||
|
||||
/**
|
||||
* MockMvc
|
||||
*/
|
||||
private MockMvc mvc;
|
||||
|
||||
/**
|
||||
* 권한 레파지토리 인터페이스
|
||||
*/
|
||||
@Autowired
|
||||
private RoleRepository roleRepository;
|
||||
|
||||
/**
|
||||
* 권한 API 경로
|
||||
*/
|
||||
private static final String URL = "/api/v1/roles";
|
||||
|
||||
private static final Integer GIVEN_DATA_COUNT = 4;
|
||||
|
||||
private static final String ROLE_ID_PREFIX = "_ROLE_";
|
||||
private static final String ROLE_NAME_PREFIX = "권한 명 테스트";
|
||||
private static final String ROLE_CONTENT_PREFIX = "권한 내용";
|
||||
|
||||
/**
|
||||
* 테스트 데이터
|
||||
*/
|
||||
private List<Role> testDatas = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 테스트 시작 전
|
||||
*/
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
mvc = MockMvcBuilders.webAppContextSetup(context)
|
||||
.addFilter(new CharacterEncodingFilter("UTF-8"))
|
||||
.apply(SecurityMockMvcConfigurers.springSecurity())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 테스트 종료 후
|
||||
*/
|
||||
@BeforeEach
|
||||
void tearDown() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한 페이지 목록 조회 테스트
|
||||
*/
|
||||
@Test
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
void 권한_페이지_목록_조회() throws Exception {
|
||||
// given
|
||||
insertTestDatas();
|
||||
|
||||
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
||||
params.add("keywordType", "roleName");
|
||||
params.add("keyword", ROLE_NAME_PREFIX);
|
||||
params.add("page", "0");
|
||||
params.add("size", "10");
|
||||
|
||||
// when
|
||||
ResultActions resultActions = mvc.perform(MockMvcRequestBuilders.get(URL)
|
||||
.params(params));
|
||||
|
||||
// then
|
||||
resultActions
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.numberOfElements").value(GIVEN_DATA_COUNT))
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.content[0].roleId").value(ROLE_ID_PREFIX + "_1"));
|
||||
|
||||
deleteTestDatas();
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한 전체 목록 조회 테스트
|
||||
*/
|
||||
@Test
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
void 권한_전체_목록_조회() throws Exception {
|
||||
// given
|
||||
insertTestDatas();
|
||||
|
||||
// when
|
||||
ResultActions resultActions = mvc.perform(MockMvcRequestBuilders.get(URL + "/all"));
|
||||
|
||||
// then
|
||||
resultActions
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$[0].roleId").value(ROLE_ID_PREFIX + "_1"));
|
||||
|
||||
deleteTestDatas();
|
||||
}
|
||||
|
||||
/**
|
||||
* 테스트 데이터 등록
|
||||
*/
|
||||
private void insertTestDatas() {
|
||||
for (int i = 1; i <= GIVEN_DATA_COUNT; i++) {
|
||||
String roleId = ROLE_ID_PREFIX + "_" + i;
|
||||
String roleName = ROLE_NAME_PREFIX + "_" + i;
|
||||
String roleContent = ROLE_CONTENT_PREFIX + "_" + i;
|
||||
|
||||
testDatas.add(roleRepository.save(Role.builder()
|
||||
.roleId(roleId)
|
||||
.roleName(roleName)
|
||||
.roleContent(roleContent)
|
||||
.sortSeq(i)
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 테스트 데이터 삭제
|
||||
*/
|
||||
private void deleteTestDatas() {
|
||||
roleRepository.deleteAll(testDatas);
|
||||
|
||||
testDatas.clear();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,370 @@
|
||||
package org.egovframe.cloud.userservice.api.role;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.assertj.core.api.Condition;
|
||||
import org.egovframe.cloud.userservice.domain.role.Authorization;
|
||||
import org.egovframe.cloud.userservice.domain.role.AuthorizationRepository;
|
||||
import org.egovframe.cloud.userservice.domain.role.Role;
|
||||
import org.egovframe.cloud.userservice.domain.role.RoleAuthorization;
|
||||
import org.egovframe.cloud.userservice.domain.role.RoleAuthorizationId;
|
||||
import org.egovframe.cloud.userservice.domain.role.RoleAuthorizationRepository;
|
||||
import org.egovframe.cloud.userservice.domain.role.RoleRepository;
|
||||
import org.json.JSONArray;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.test.context.support.WithMockUser;
|
||||
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.filter.CharacterEncodingFilter;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.api.role.RoleAuthorizationApiControllerTest
|
||||
* <p>
|
||||
* 권한 인가 Rest API 컨트롤러 테스트 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/12
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/12 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@EnableConfigurationProperties
|
||||
@TestPropertySource(properties = {"spring.config.location=classpath:application-test.yml"})
|
||||
@ActiveProfiles(profiles = "test")
|
||||
class RoleAuthorizationApiControllerTest {
|
||||
|
||||
/**
|
||||
* WebApplicationContext
|
||||
*/
|
||||
@Autowired
|
||||
private WebApplicationContext context;
|
||||
|
||||
/**
|
||||
* MockMvc
|
||||
*/
|
||||
private MockMvc mvc;
|
||||
|
||||
/**
|
||||
* ObjectMapper
|
||||
*/
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
* 권한 레파지토리 인터페이스
|
||||
*/
|
||||
@Autowired
|
||||
RoleRepository roleRepository;
|
||||
|
||||
/**
|
||||
* 인가 레파지토리 인터페이스
|
||||
*/
|
||||
@Autowired
|
||||
AuthorizationRepository authorizationRepository;
|
||||
|
||||
/**
|
||||
* 권한 인가 레파지토리 인터페이스
|
||||
*/
|
||||
@Autowired
|
||||
RoleAuthorizationRepository roleAuthorizationRepository;
|
||||
|
||||
/**
|
||||
* 인가 API 경로
|
||||
*/
|
||||
private static final String URL = "/api/v1/role-authorizations";
|
||||
|
||||
/**
|
||||
* 테스트 데이터 등록 횟수
|
||||
*/
|
||||
private final Integer GIVEN_AUTHORIZATION_COUNT = 5;
|
||||
|
||||
private final String ROLE_ID = "_ROLE_1";
|
||||
private final String ROLE_NAME = "권한 명_1";
|
||||
private final String ROLE_CONTENT = "권한 내용_1";
|
||||
|
||||
private final String AUTHORIZATION_NAME_PREFIX = "인가 명";
|
||||
private final String URL_PATTERN_VALUE_PREFIX = "/api/v1/test";
|
||||
private final String HTTP_METHOD_VALUE_PREFIX = "GET";
|
||||
|
||||
/**
|
||||
* 테스트 데이터
|
||||
*/
|
||||
private Role role = null;
|
||||
private final List<Authorization> authorizations = new ArrayList<>();
|
||||
private final List<RoleAuthorization> testDatas = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 테스트 시작 전 수행
|
||||
*/
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
mvc = MockMvcBuilders.webAppContextSetup(context)
|
||||
.addFilter(new CharacterEncodingFilter("UTF-8"))
|
||||
.apply(SecurityMockMvcConfigurers.springSecurity())
|
||||
.build();
|
||||
|
||||
// 권한 등록
|
||||
role = roleRepository.save(Role.builder()
|
||||
.roleId(ROLE_ID)
|
||||
.roleName(ROLE_NAME)
|
||||
.roleContent(ROLE_CONTENT)
|
||||
.sortSeq(1)
|
||||
.build());
|
||||
|
||||
// 인가 등록
|
||||
for (int i = 1; i <= GIVEN_AUTHORIZATION_COUNT; i++) {
|
||||
authorizations.add(authorizationRepository.save(Authorization.builder()
|
||||
.authorizationName(AUTHORIZATION_NAME_PREFIX + "_" + i)
|
||||
.urlPatternValue(URL_PATTERN_VALUE_PREFIX + "_" + i)
|
||||
.httpMethodCode(HTTP_METHOD_VALUE_PREFIX + "_" + i)
|
||||
.sortSeq(i)
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 테스트 종료 후 수행
|
||||
*/
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
// 인가 삭제
|
||||
authorizationRepository.deleteAll(authorizations);
|
||||
authorizations.clear();
|
||||
|
||||
// 권한 삭제
|
||||
roleRepository.delete(role);
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한 인가 페이지 목록 조회
|
||||
*/
|
||||
@Test
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
void 권한_인가_페이지_목록_조회() throws Exception {
|
||||
// given
|
||||
insertTestDatas();
|
||||
|
||||
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
||||
params.add("roleId", role.getRoleId());
|
||||
params.add("keywordType", "urlPatternValue");
|
||||
params.add("keyword", URL_PATTERN_VALUE_PREFIX);
|
||||
params.add("page", "0");
|
||||
params.add("size", "10");
|
||||
|
||||
// when
|
||||
ResultActions resultActions = mvc.perform(MockMvcRequestBuilders.get(URL)
|
||||
.params(params));
|
||||
|
||||
// then
|
||||
resultActions
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.numberOfElements").value(authorizations.size()))
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.content[0].roleId").value(role.getRoleId()))
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.content[0].authorizationNo").value(authorizations.get(0).getAuthorizationNo()))
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$.content[0].createdAt").value(true));
|
||||
|
||||
deleteTestDatas();
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한 인가 다건 등록
|
||||
*/
|
||||
@Test
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
void 권한_인가_다건_등록() throws Exception {
|
||||
// given
|
||||
List<Map<String, Object>> requestDtoList = new ArrayList<>();
|
||||
for (int i = 1; i <= authorizations.size(); i++) {
|
||||
if (i % 2 == 0) continue; //홀수만 등록
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("roleId", role.getRoleId());
|
||||
params.put("authorizationNo", authorizations.get(i - 1).getAuthorizationNo());
|
||||
|
||||
requestDtoList.add(params);
|
||||
}
|
||||
|
||||
// when
|
||||
ResultActions resultActions = mvc.perform(MockMvcRequestBuilders.post(URL)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.contentType("application/json;charset=UTF-8")
|
||||
.content(objectMapper.writeValueAsString(requestDtoList)));
|
||||
|
||||
// then
|
||||
resultActions
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(MockMvcResultMatchers.status().isOk());
|
||||
|
||||
String responseData = resultActions.andReturn().getResponse().getContentAsString();
|
||||
JSONArray jsonArray = new JSONArray(responseData);
|
||||
|
||||
assertThat(jsonArray.length()).isEqualTo(requestDtoList.size());
|
||||
|
||||
List<RoleAuthorization> entityList = roleAuthorizationRepository.findAll(Sort.by(Sort.Direction.ASC, "roleAuthorizationId.authorizationNo"));
|
||||
for (int i = entityList.size() - 1; i >= 0; i--) {
|
||||
if (!entityList.get(i).getRoleAuthorizationId().getRoleId().equals(role.getRoleId())) {
|
||||
entityList.remove(i);
|
||||
}
|
||||
}
|
||||
assertThat(entityList).isNotNull();
|
||||
assertThat(entityList.size()).isEqualTo(requestDtoList.size());
|
||||
assertThat(entityList)
|
||||
.isNotEmpty()
|
||||
.has(new Condition<>(l -> l.get(0).getRoleAuthorizationId().getRoleId().equals(role.getRoleId()) && l.get(0).getRoleAuthorizationId().getAuthorizationNo().compareTo(authorizations.get(0).getAuthorizationNo()) == 0,
|
||||
"RoleAuthorizationApiControllerTest.saveList authorizationNo eq 1"))
|
||||
.has(new Condition<>(l -> l.get(1).getRoleAuthorizationId().getRoleId().equals(role.getRoleId()) && l.get(1).getRoleAuthorizationId().getAuthorizationNo().compareTo(authorizations.get(2).getAuthorizationNo()) == 0,
|
||||
"RoleAuthorizationApiControllerTest.saveList authorizationNo eq 3"));
|
||||
|
||||
for (int i = entityList.size() - 1; i >= 0; i--) {
|
||||
deleteTestData(entityList.get(i).getRoleAuthorizationId().getRoleId(), entityList.get(i).getRoleAuthorizationId().getAuthorizationNo());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한 인가 다건 삭제
|
||||
*/
|
||||
@Test
|
||||
@WithMockUser(roles = "ADMIN")
|
||||
void 권한_인가_다건_삭제() throws Exception {
|
||||
// given
|
||||
insertTestDatas();
|
||||
|
||||
List<Map<String, Object>> requestDtoList = new ArrayList<>();
|
||||
for (RoleAuthorization testData : testDatas) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("roleId", testData.getRoleAuthorizationId().getRoleId());
|
||||
params.put("authorizationNo", testData.getRoleAuthorizationId().getAuthorizationNo());
|
||||
|
||||
requestDtoList.add(params);
|
||||
}
|
||||
|
||||
// when
|
||||
ResultActions resultActions = mvc.perform(MockMvcRequestBuilders.put(URL)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.contentType("application/json;charset=UTF-8")
|
||||
.content(objectMapper.writeValueAsString(requestDtoList)));
|
||||
|
||||
// then
|
||||
resultActions
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(MockMvcResultMatchers.status().isOk());
|
||||
|
||||
List<RoleAuthorization> entityList = roleAuthorizationRepository.findAll(Sort.by(Sort.Direction.ASC, "roleAuthorizationId.authorizationNo"));
|
||||
for (int i = entityList.size() - 1; i >= 0; i--) {
|
||||
if (!entityList.get(i).getRoleAuthorizationId().getRoleId().equals(role.getRoleId())) {
|
||||
entityList.remove(i);
|
||||
}
|
||||
}
|
||||
assertThat(entityList).isNotNull();
|
||||
assertThat(entityList.size()).isZero();
|
||||
}
|
||||
|
||||
/**
|
||||
* 권한 인가 레파지토리 등록/조회 테스트
|
||||
*/
|
||||
@Test
|
||||
@Disabled
|
||||
void 권한_인가_등록_조회() {
|
||||
// given
|
||||
final Integer authorizationNo = authorizations.get(0).getAuthorizationNo();
|
||||
|
||||
roleAuthorizationRepository.save(RoleAuthorization.builder()
|
||||
.roleId(role.getRoleId())
|
||||
.authorizationNo(authorizationNo)
|
||||
.build());
|
||||
|
||||
// when
|
||||
Optional<RoleAuthorization> roleAuthorization = selectData(role.getRoleId(), authorizationNo);
|
||||
|
||||
// then
|
||||
assertThat(roleAuthorization).isPresent();
|
||||
|
||||
RoleAuthorization entity = roleAuthorization.get();
|
||||
assertThat(entity.getRoleAuthorizationId().getRoleId()).isEqualTo(role.getRoleId());
|
||||
assertThat(entity.getRoleAuthorizationId().getAuthorizationNo()).isEqualTo(authorizationNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 테스트 데이터 등록
|
||||
*/
|
||||
private void insertTestDatas() {
|
||||
// 권한 인가 등록
|
||||
for (int i = 1; i <= authorizations.size(); i++) {
|
||||
if (i % 2 == 0) continue; //인가 번호 홀수만 등록
|
||||
|
||||
testDatas.add(roleAuthorizationRepository.save(RoleAuthorization.builder()
|
||||
.roleId(role.getRoleId())
|
||||
.authorizationNo(authorizations.get(i - 1).getAuthorizationNo())
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 테스트 데이터 삭제
|
||||
*/
|
||||
private void deleteTestDatas() {
|
||||
// 권한 인가 삭제
|
||||
roleAuthorizationRepository.deleteAll(testDatas);
|
||||
testDatas.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 테스트 데이터 단건 삭제
|
||||
*/
|
||||
private void deleteTestData(String roleId, Integer authorizationNo) {
|
||||
roleAuthorizationRepository.deleteById(RoleAuthorizationId.builder()
|
||||
.roleId(roleId)
|
||||
.authorizationNo(authorizationNo)
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* 테스트 데이터 단건 조회
|
||||
*
|
||||
* @param roleId 권한 id
|
||||
* @param authorizationNo 인가 번호
|
||||
* @return Optional<RoleAuthorization> 권한 인가 엔티티
|
||||
*/
|
||||
private Optional<RoleAuthorization> selectData(String roleId, Integer authorizationNo) {
|
||||
return roleAuthorizationRepository.findById(RoleAuthorizationId.builder()
|
||||
.roleId(roleId)
|
||||
.authorizationNo(authorizationNo)
|
||||
.build());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.egovframe.cloud.userservice.config;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.context.MessageSource;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
|
||||
|
||||
@SpringBootTest(webEnvironment = RANDOM_PORT)
|
||||
class MessageSourceConfigTest {
|
||||
|
||||
@Autowired
|
||||
TestRestTemplate restTemplate;
|
||||
|
||||
@Test
|
||||
public void 메세지를_외부위치에서_읽어온다() throws Exception {
|
||||
// when
|
||||
String message = restTemplate.getForObject("http://localhost:8000/user-service/api/v1/messages/common.login/ko", String.class);
|
||||
|
||||
// then
|
||||
assertThat(message).isEqualTo("로그인");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package org.egovframe.cloud.userservice.util;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* org.egovframe.cloud.userservice.util.RestResponsePage
|
||||
* <p>
|
||||
* 페이지 API 조회 시 JSON 형식의 응답 데이터를 페이지 객체를 구현하여 마이그레이션 해주는 클래스
|
||||
*
|
||||
* @author 표준프레임워크센터 jooho
|
||||
* @version 1.0
|
||||
* @since 2021/07/08
|
||||
*
|
||||
* <pre>
|
||||
* << 개정이력(Modification Information) >>
|
||||
*
|
||||
* 수정일 수정자 수정내용
|
||||
* ---------- -------- ---------------------------
|
||||
* 2021/07/08 jooho 최초 생성
|
||||
* </pre>
|
||||
*/
|
||||
public class RestResponsePage<T> extends PageImpl<T> {
|
||||
|
||||
/**
|
||||
* Rest 응답 페이지 생성자
|
||||
*
|
||||
* @param content 목록
|
||||
* @param number 페이지 번호
|
||||
* @param size 조회할 데이터 수
|
||||
* @param totalElements 총 데이터 수
|
||||
* @param pageable 페이지 정보
|
||||
* @param last 마지막
|
||||
* @param totalPages 총 페이지
|
||||
* @param sort 정렬
|
||||
* @param first 처음
|
||||
* @param numberOfElements 조회된 데이터 수
|
||||
*/
|
||||
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
|
||||
public RestResponsePage(@JsonProperty("content") List<T> content,
|
||||
@JsonProperty("number") int number,
|
||||
@JsonProperty("size") int size,
|
||||
@JsonProperty("totalElements") Long totalElements,
|
||||
@JsonProperty("pageable") JsonNode pageable,
|
||||
@JsonProperty("last") boolean last,
|
||||
@JsonProperty("totalPages") int totalPages,
|
||||
@JsonProperty("sort") JsonNode sort,
|
||||
@JsonProperty("first") boolean first,
|
||||
@JsonProperty("numberOfElements") int numberOfElements) {
|
||||
super(content, PageRequest.of(number, size), totalElements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rest 응답 페이지 생성자
|
||||
*
|
||||
* @param content 목록
|
||||
* @param pageable 페이지 정보
|
||||
* @param total 총 데이터 수
|
||||
*/
|
||||
public RestResponsePage(List<T> content, Pageable pageable, long total) {
|
||||
super(content, pageable, total);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rest 응답 페이지 생성자
|
||||
*
|
||||
* @param content 목록
|
||||
*/
|
||||
public RestResponsePage(List<T> content) {
|
||||
super(content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rest 응답 페이지 생성자
|
||||
*/
|
||||
public RestResponsePage() {
|
||||
super(Collections.emptyList());
|
||||
}
|
||||
|
||||
}
|
||||
107
backend/user-service/src/test/resources/application-test.yml
Normal file
107
backend/user-service/src/test/resources/application-test.yml
Normal file
@@ -0,0 +1,107 @@
|
||||
spring:
|
||||
application:
|
||||
name: user-service
|
||||
|
||||
datasource:
|
||||
url: jdbc:h2:mem:testdb;MODE=MYSQL;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false
|
||||
username: sa
|
||||
password:
|
||||
driver-class-name: org.h2.Driver
|
||||
initialization-mode: always
|
||||
# schema: classpath:h2/schema.sql
|
||||
data: classpath:h2/data.sql
|
||||
jpa:
|
||||
hibernate:
|
||||
generate-ddl: true
|
||||
ddl-auto: create-drop
|
||||
dialect: org.hibernate.dialect.MySQL5Dialect
|
||||
properties:
|
||||
hibernate:
|
||||
format_sql: true
|
||||
default_batch_fetch_size: 1000
|
||||
show-sql: true
|
||||
h2:
|
||||
console:
|
||||
enabled: true
|
||||
path: /h2
|
||||
cache:
|
||||
jcache:
|
||||
config: classpath:ehcache.xml
|
||||
mail: # 비밀번호 변경 이메일 발송
|
||||
host: smtp.gmail.com # smtp host
|
||||
port: 587 # smtp port
|
||||
username: email_username # 계정
|
||||
password: 'email_password' # 비밀번호 - 구글 보안 2단계 인증 해제, 보안 수준이 낮은 앱의 액세스 허용(https://myaccount.google.com/lesssecureapps)
|
||||
properties:
|
||||
mail:
|
||||
smtp:
|
||||
auth: true
|
||||
starttls:
|
||||
enable: true
|
||||
required: true
|
||||
security:
|
||||
# oauth2 를 사용하려면 아래 google, naver, kakao 의 client-id, client-secret 을 발급받아야 한다.
|
||||
oauth2:
|
||||
client:
|
||||
registration:
|
||||
# /oauth2/authorization/google
|
||||
google:
|
||||
client-id: google_client_id # TODO
|
||||
client-secret: google_client_secret # TODO
|
||||
scope: profile,email
|
||||
# 네이버는 Spring Security를 공식 지원하지 않기 때문에 CommonOAuth2Provider 에서 해주는 값들을 수동으로 입력한다.
|
||||
# /oauth2/authorization/naver
|
||||
naver:
|
||||
client-id: naver_client_id # TODO
|
||||
client-secret: naver_client_secret # TODO
|
||||
redirect_uri: "{baseUrl}/{action}/oauth2/code/{registrationId}"
|
||||
authorization_grant_type: authorization_code
|
||||
scope: name,email,profile_image
|
||||
client-name: Naver
|
||||
# /oauth2/authorization/kakao
|
||||
kakao:
|
||||
client-id: kakao_client_id # TODO
|
||||
client-secret: kakao_client_secret # TODO
|
||||
redirect-uri: "{baseUrl}/{action}/oauth2/code/{registrationId}"
|
||||
client-authentication-method: POST
|
||||
authorization-grant-type: authorization_code
|
||||
scope: profile_nickname, account_email
|
||||
client-name: Kakao
|
||||
provider:
|
||||
naver:
|
||||
authorization_uri: https://nid.naver.com/oauth2.0/authorize
|
||||
token_uri: https://nid.naver.com/oauth2.0/token
|
||||
user-info-uri: https://openapi.naver.com/v1/nid/me
|
||||
# 기준이 되는 user_name 의 이름을 네이버에서는 response로 지정해야한다. (네이버 회원 조회시 반환되는 JSON 형태 때문이다)
|
||||
# response를 user_name으로 지정하고 이후 자바 코드로 response의 id를 user_name으로 지정한다. (스프링 시큐리티에서 하위 필드를 명시할 수 없기 때문)
|
||||
user_name_attribute: response
|
||||
kakao:
|
||||
authorization_uri: https://kauth.kakao.com/oauth/authorize
|
||||
token_uri: https://kauth.kakao.com/oauth/token
|
||||
user-info-uri: https://kapi.kakao.com/v2/user/me
|
||||
user_name_attribute: id
|
||||
|
||||
logging.level:
|
||||
org.hibernate.SQL: debug
|
||||
org.hibernate.type: trace
|
||||
|
||||
file:
|
||||
directory: ${user.home}/msa-attach-volume
|
||||
messages:
|
||||
directory: ${file.directory}/messages
|
||||
|
||||
# jwt token
|
||||
token:
|
||||
expiration_time: 7200000
|
||||
refresh_time: 86400000
|
||||
secret: egovframe_token_secret
|
||||
|
||||
# ftp server
|
||||
ftp:
|
||||
enabled: false # ftp 사용 여부, FTP 서버에 최상위 디렉토리 자동 생성 및 구현체를 결정하게 된다.
|
||||
|
||||
# eureka 가 포함되면 eureka server 도 등록되므로 해제한다.
|
||||
eureka:
|
||||
client:
|
||||
register-with-eureka: false
|
||||
fetch-registry: false
|
||||
38
backend/user-service/src/test/resources/h2/data.sql
Normal file
38
backend/user-service/src/test/resources/h2/data.sql
Normal file
@@ -0,0 +1,38 @@
|
||||
INSERT INTO `authorization` (authorization_name,url_pattern_value,http_method_code,sort_seq,created_by,created_date,last_modified_by,modified_date) VALUES
|
||||
('사용자 목록 조회','/user-service/api/v1/users','GET',101,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('사용자 단건 조회','/user-service/api/v1/users/?*','GET',102,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('사용자 등록','/user-service/api/v1/users','POST',103,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('사용자 수정','/user-service/api/v1/users/?*','PUT',104,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('사용자 토큰 갱신','/user-service/api/v1/users/token/refresh','GET',105,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('권한 페이지 목록 조회','/user-service/api/v1/roles','GET',106,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('권한 전체 목록 조회','/user-service/api/v1/roles/all','GET',107,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('인가 페이지 목록 조회','/user-service/api/v1/authorizations','GET',108,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('인가 단건 조회','/user-service/api/v1/authorizations/?*','GET',109,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('인가 다음 정렬 순서 조회','/user-service/api/v1/authorizations/sort-seq/next','GET',110,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('인가 등록','/user-service/api/v1/authorizations','POST',111,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('인가 수정','/user-service/api/v1/authorizations/?*','PUT',112,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('인가 삭제','/user-service/api/v1/authorizations/?*','DELETE',113,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('인가 여부 확인','/user-service/api/v1/authorizations/check','GET',114,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('권한 인가 페이지 목록 조회','/user-service/api/v1/role-authorizations','GET',115,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('권한 인가 다건 등록','/user-service/api/v1/role-authorizations','POST',116,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('권한 인가 다건 삭제','/user-service/api/v1/role-authorizations','PUT',117,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('사용자 이메일 중복 확인','/user-service/api/v1/users/exists','POST',118,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('사용자 회원 가입','/user-service/api/v1/users/join','POST',119,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('사용자 비밀번호 찾기','/user-service/api/v1/users/password/find','POST',120,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('사용자 비밀번호 찾기 유효성 확인','/user-service/api/v1/users/password/valid/?*','GET',121,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('사용자 비밀번호 찾기 변경','/user-service/api/v1/users/password/change','PUT',122,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('사용자 비밀번호 변경','/user-service/api/v1/users/password/update','PUT',123,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('사용자 비밀번호 확인','/user-service/api/v1/users/password/match','POST',124,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('예약지역 사용여부 토글','/reserve-item-service/api/v1/locations/?*/?*','PUT',125,'87638675-11fa-49e5-9bd1-d2524bf6fa45',now(),'87638675-11fa-49e5-9bd1-d2524bf6fa45',now()),
|
||||
('사용자 정보 수정','/user-service/api/v1/users/info/?*','PUT',126,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('사용자 회원탈퇴','/user-service/api/v1/users/leave','POST',127,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now()),
|
||||
('사용자 삭제','/user-service/api/v1/users/delete/?*','DELETE',128,'65a00f65-8460-49af-98ec-042977e56f4b',now(),'65a00f65-8460-49af-98ec-042977e56f4b',now());
|
||||
|
||||
INSERT INTO `role` (role_id,role_name,role_content,sort_seq,created_date) VALUES
|
||||
('ROLE_ADMIN','시스템 관리자','시스템 관리자 권한',101,'2021-10-20 13:39:15'),
|
||||
('ROLE_ANONYMOUS','손님','손님 권한',104,'2021-10-20 13:39:15'),
|
||||
('ROLE_EMPLOYEE','내부 사용자','내부 사용자 권한',102,'2021-10-20 13:39:15'),
|
||||
('ROLE_USER','일반 사용자','일반 사용자 권한',103,'2021-10-20 13:39:15');
|
||||
|
||||
INSERT INTO role_authorization (role_id,authorization_no,created_by,created_date)
|
||||
select 'ROLE_ADMIN', authorization_no, '65a00f65-8460-49af-98ec-042977e56f4b', now() from `authorization`;
|
||||
Reference in New Issue
Block a user