admin : 탭 생성시 CSRF토큰 동기화 문제 수정 #13
|
|
@ -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
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
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.SecurityFilterChain;
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||||
|
|
@ -75,6 +73,7 @@ public class SecurityConfig {
|
||||||
.anyRequest()
|
.anyRequest()
|
||||||
.access(new CustomAuthorizationManager(authorizationAppService))
|
.access(new CustomAuthorizationManager(authorizationAppService))
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void configureFormLogin(HttpSecurity http) throws Exception {
|
private void configureFormLogin(HttpSecurity http) throws Exception {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,6 @@ public class JwtTokenConstants {
|
||||||
public static final String KEY = "8530b13adb4e420d9694b27570635b47";
|
public static final String KEY = "8530b13adb4e420d9694b27570635b47";
|
||||||
public static final String ACCESS_TOKEN_NAME = "AT";
|
public static final String ACCESS_TOKEN_NAME = "AT";
|
||||||
public static final String REFRESH_TOKEN_NAME = "RT";
|
public static final String REFRESH_TOKEN_NAME = "RT";
|
||||||
public static final long AT_EXPIRATION_TIME = 30 * 1000;
|
public static final long AT_EXPIRATION_TIME = 30 * 30 * 1000;
|
||||||
public static final long RT_EXPIRATION_TIME = 60 * 1000;
|
public static final long RT_EXPIRATION_TIME = 30* 60 * 1000;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,7 @@ public class TabRestController {
|
||||||
|
|
||||||
@PostMapping("/tab/add")
|
@PostMapping("/tab/add")
|
||||||
public ResponseEntity<?> addTab(
|
public ResponseEntity<?> addTab(
|
||||||
@RequestBody @Valid TabCreate.Request request ,
|
@RequestBody @Valid TabCreate.Request request
|
||||||
BindingResult bindingResult
|
|
||||||
) {
|
) {
|
||||||
TabCreate.Response response = tabAppService.addTab(request);
|
TabCreate.Response response = tabAppService.addTab(request);
|
||||||
return ResponseEntity.ok(response);
|
return ResponseEntity.ok(response);
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ const Reqhelper = {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
|
refreshCsrf();
|
||||||
if (fFunc) {
|
if (fFunc) {
|
||||||
fFunc();
|
fFunc();
|
||||||
}
|
}
|
||||||
|
|
@ -66,6 +67,7 @@ const Reqhelper = {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
refreshCsrf();
|
||||||
if (eFunc) {
|
if (eFunc) {
|
||||||
eFunc(error);
|
eFunc(error);
|
||||||
}
|
}
|
||||||
|
|
@ -81,13 +83,13 @@ const Reqhelper = {
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshCsrf() {
|
function refreshCsrf() {
|
||||||
fetch('/csrf', {
|
return fetch('/csrf', {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
response.json().then(data => {
|
return response.json().then(data => {
|
||||||
const csrfToken = data.token;
|
const csrfToken = data.token;
|
||||||
document.querySelector('meta[name="_csrf"]').setAttribute('content', csrfToken);
|
document.querySelector('meta[name="_csrf"]').setAttribute('content', csrfToken);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -60,18 +60,34 @@
|
||||||
|
|
||||||
// 탭 생성 및 DB Insert 메서드
|
// 탭 생성 및 DB Insert 메서드
|
||||||
function addTab(tabName, url) {
|
function addTab(tabName, url) {
|
||||||
Reqhelper.reqPostJson('/admin/tab/add', {
|
if (url !== '/main'){
|
||||||
name: tabName,
|
refreshCsrf().then(() => {
|
||||||
url: url
|
var csrfToken = $("meta[name='_csrf']").attr("content");
|
||||||
}, function(response) {
|
var csrfHeader = $("meta[name='_csrf_header']").attr("content");
|
||||||
console.log('Tab created successfully');
|
$.ajax({
|
||||||
const tabId = response.id;
|
url: '/admin/tab/add',
|
||||||
createTab(tabId, tabName, url);
|
type: 'POST',
|
||||||
openTab({currentTarget: $(`#${tabId}-tab`)}, tabId);
|
data: JSON.stringify({
|
||||||
loadTabContent(tabId, url);
|
name: tabName,
|
||||||
}, function() {
|
url: url
|
||||||
console.log('Failed to create tab');
|
}),
|
||||||
});
|
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) {
|
function loadTabContent(tabId, url) {
|
||||||
|
|
@ -135,12 +151,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteTab(event, tabId) {
|
function deleteTab(event, tabId) {
|
||||||
$(`#${tabId}`).remove();
|
|
||||||
$(`#${tabId}-tab`).parent().remove();
|
|
||||||
event.stopPropagation();
|
|
||||||
Reqhelper.reqPostJson('/admin/tab/delete', {
|
Reqhelper.reqPostJson('/admin/tab/delete', {
|
||||||
id : tabId
|
id : tabId
|
||||||
}, function() {
|
}, function() {
|
||||||
|
$(`#${tabId}`).remove();
|
||||||
|
$(`#${tabId}-tab`).parent().remove();
|
||||||
|
event.stopPropagation();
|
||||||
console.log('Tab deleted successfully');
|
console.log('Tab deleted successfully');
|
||||||
}, function() {
|
}, function() {
|
||||||
console.log('Failed to delete tab');
|
console.log('Failed to delete tab');
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue