admin : 탭 생성시 CSRF토큰 동기화 문제 수정

This commit is contained in:
HyeonJongKim 2024-08-26 14:08:38 +09:00
parent 3c3cecf6ba
commit 4b0dedef7a
17 changed files with 188 additions and 23 deletions

10
poc/.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# GitHub Copilot persisted chat sessions
/copilot/chatSessions

31
poc/.idea/compiler.xml Normal file
View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Gradle Imported" enabled="true">
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="false">
<entry name="$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.querydsl/querydsl-apt/5.0.0/d48657412f2b96d787bbe5ae393e33815c94b4d0/querydsl-apt-5.0.0-jakarta.jar" />
<entry name="$USER_HOME$/.gradle/caches/modules-2/files-2.1/jakarta.persistence/jakarta.persistence-api/3.1.0/66901fa1c373c6aff65c13791cc11da72060a8d6/jakarta.persistence-api-3.1.0.jar" />
<entry name="$USER_HOME$/.gradle/caches/modules-2/files-2.1/jakarta.annotation/jakarta.annotation-api/2.1.1/48b9bda22b091b1f48b13af03fe36db3be6e1ae3/jakarta.annotation-api-2.1.1.jar" />
<entry name="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.projectlombok/lombok/1.18.32/17d46b3e205515e1e8efd3ee4d57ce8018914163/lombok-1.18.32.jar" />
<entry name="$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.querydsl/querydsl-codegen/5.0.0/d690e92300f528e4161307b286f76aeaf348e2fb/querydsl-codegen-5.0.0.jar" />
<entry name="$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.querydsl/querydsl-core/5.0.0/7a469f78b7a89bae429f17766fb92687d0ab9e5b/querydsl-core-5.0.0.jar" />
<entry name="$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.querydsl/codegen-utils/5.0.0/ff8a2ebbc3a317715de0ce2856c2024534d18a1a/codegen-utils-5.0.0.jar" />
<entry name="$USER_HOME$/.gradle/caches/modules-2/files-2.1/javax.inject/javax.inject/1/6975da39a7040257bd51d21a231b76c915872d38/javax.inject-1.jar" />
<entry name="$USER_HOME$/.gradle/caches/modules-2/files-2.1/io.github.classgraph/classgraph/4.8.108/1c175d4ce7a1fa67463bad731f37f1a284dab790/classgraph-4.8.108.jar" />
<entry name="$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.mysema.commons/mysema-commons-lang/0.2.4/d09c8489d54251a6c22fbce804bdd4a070557317/mysema-commons-lang-0.2.4.jar" />
<entry name="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.eclipse.jdt/ecj/3.26.0/4837be609a3368a0f7e7cf0dc1bdbc7fe94993de/ecj-3.26.0.jar" />
</processorPath>
<module name="admin.main" />
</profile>
<profile name="Gradle Imported" enabled="true">
<outputRelativeToContentRoot value="true" />
<processorPath useClasspath="false">
<entry name="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.projectlombok/lombok/1.18.32/17d46b3e205515e1e8efd3ee4d57ce8018914163/lombok-1.18.32.jar" />
</processorPath>
<module name="admin.test" />
</profile>
</annotationProcessing>
</component>
</project>

12
poc/.idea/dataSources.xml Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="admin-system@localhost" uuid="b50bc72b-d061-414d-9e85-7088ff3b1e99">
<driver-ref>mariadb</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.mariadb.jdbc.Driver</jdbc-driver>
<jdbc-url>jdbc:mariadb://localhost:3307/admin-system</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

16
poc/.idea/gradle.xml Normal file
View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$/admin" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$/admin" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

View File

@ -0,0 +1,15 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="HtmlUnknownAttribute" enabled="true" level="WARNING" enabled_by_default="true">
<option name="myValues">
<value>
<list size="1">
<item index="0" class="java.lang.String" itemvalue="sec:authorize" />
</list>
</value>
</option>
<option name="myCustomValuesEnabled" value="true" />
</inspection_tool>
</profile>
</component>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="MavenRepo" />
<option name="name" value="MavenRepo" />
<option name="url" value="https://repo.maven.apache.org/maven2/" />
</remote-repository>
</component>
</project>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<file url="file://$PROJECT_DIR$/admin/build/generated/sources/annotationProcessor/java/main" libraries="{jquery-latest, jquery-ui}" />
<file url="file://$PROJECT_DIR$/admin/src/main" libraries="{jquery-latest, jquery-ui}" />
</component>
</project>

9
poc/.idea/misc.xml Normal file
View File

@ -0,0 +1,9 @@
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$/admin" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" project-jdk-name="21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
poc/.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/poc.iml" filepath="$PROJECT_DIR$/.idea/poc.iml" />
</modules>
</component>
</project>

11
poc/.idea/poc.iml Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.idea/copilot/chatSessions" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
poc/.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

View File

@ -0,0 +1,4 @@
CREATE DATABASE IF NOT EXISTS `admin-system`;
CREATE USER IF NOT EXISTS 'admin'@'%' IDENTIFIED BY '1234';
GRANT ALL PRIVILEGES ON `admin-system`.* TO 'admin'@'%';
FLUSH PRIVILEGES;

View File

@ -18,8 +18,6 @@ import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
@ -75,6 +73,7 @@ public class SecurityConfig {
.anyRequest()
.access(new CustomAuthorizationManager(authorizationAppService))
);
}
private void configureFormLogin(HttpSecurity http) throws Exception {

View File

@ -11,6 +11,6 @@ public class JwtTokenConstants {
public static final String KEY = "8530b13adb4e420d9694b27570635b47";
public static final String ACCESS_TOKEN_NAME = "AT";
public static final String REFRESH_TOKEN_NAME = "RT";
public static final long AT_EXPIRATION_TIME = 30 * 1000;
public static final long RT_EXPIRATION_TIME = 60 * 1000;
public static final long AT_EXPIRATION_TIME = 30 * 30 * 1000;
public static final long RT_EXPIRATION_TIME = 30* 60 * 1000;
}

View File

@ -27,8 +27,7 @@ public class TabRestController {
@PostMapping("/tab/add")
public ResponseEntity<?> addTab(
@RequestBody @Valid TabCreate.Request request ,
BindingResult bindingResult
@RequestBody @Valid TabCreate.Request request
) {
TabCreate.Response response = tabAppService.addTab(request);
return ResponseEntity.ok(response);

View File

@ -34,6 +34,7 @@ const Reqhelper = {
}
})
.finally(() => {
refreshCsrf();
if (fFunc) {
fFunc();
}
@ -66,6 +67,7 @@ const Reqhelper = {
}
})
.catch((error) => {
refreshCsrf();
if (eFunc) {
eFunc(error);
}
@ -81,13 +83,13 @@ const Reqhelper = {
}
function refreshCsrf() {
fetch('/csrf', {
return fetch('/csrf', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}).then(response => {
response.json().then(data => {
return response.json().then(data => {
const csrfToken = data.token;
document.querySelector('meta[name="_csrf"]').setAttribute('content', csrfToken);
});

View File

@ -60,18 +60,34 @@
// 탭 생성 및 DB Insert 메서드
function addTab(tabName, url) {
Reqhelper.reqPostJson('/admin/tab/add', {
name: tabName,
url: url
}, function(response) {
console.log('Tab created successfully');
const tabId = response.id;
createTab(tabId, tabName, url);
openTab({currentTarget: $(`#${tabId}-tab`)}, tabId);
loadTabContent(tabId, url);
}, function() {
console.log('Failed to create tab');
});
if (url !== '/main'){
refreshCsrf().then(() => {
var csrfToken = $("meta[name='_csrf']").attr("content");
var csrfHeader = $("meta[name='_csrf_header']").attr("content");
$.ajax({
url: '/admin/tab/add',
type: 'POST',
data: JSON.stringify({
name: tabName,
url: url
}),
beforeSend: function(xhr) {
xhr.setRequestHeader(csrfHeader, csrfToken);
},
contentType: 'application/json',
success: function(response) {
const tabId = response.id;
createTab(tabId, tabName, url);
openTab({currentTarget: $(`#${tabId}-tab`)}, tabId);
loadTabContent(tabId, url);
console.log('Tab created successfully');
},
error: function() {
console.log('Failed to create tab');
}
});
});
}
}
function loadTabContent(tabId, url) {
@ -135,12 +151,12 @@
}
function deleteTab(event, tabId) {
$(`#${tabId}`).remove();
$(`#${tabId}-tab`).parent().remove();
event.stopPropagation();
Reqhelper.reqPostJson('/admin/tab/delete', {
id : tabId
}, function() {
$(`#${tabId}`).remove();
$(`#${tabId}-tab`).parent().remove();
event.stopPropagation();
console.log('Tab deleted successfully');
}, function() {
console.log('Failed to delete tab');