diff --git a/build.gradle b/build.gradle
index d8e06fa..4bd8192 100644
--- a/build.gradle
+++ b/build.gradle
@@ -37,6 +37,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.4'
implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16'
+ implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.17.0'
runtimeOnly 'com.ibm.db2:jcc'
runtimeOnly 'com.microsoft.sqlserver:mssql-jdbc'
runtimeOnly 'com.mysql:mysql-connector-j'
diff --git a/src/database/create-database.sql b/src/database/create-database.sql
index 59919af..118813b 100644
--- a/src/database/create-database.sql
+++ b/src/database/create-database.sql
@@ -1,19 +1,54 @@
CREATE SCHEMA DFXCONSOLE;
-CREATE TABLE TB_CONSOLE_USER (
+CREATE TABLE TB_CODE (
+ CODE_GROUP VARCHAR(64) NOT NULL
+ , CODE_NAME VARCHAR(64) NOT NULL
+ , CODE_VALUE VARCHAR(1024) NOT NULL
+ , CODE_DESCRIPTION VARCHAR(1024)
+ , ORDER_NO DECIMAL(5) NOT NULL
+ , PARENT_CODE_NAME VARCHAR(64)
+ , USE_YN VARCHAR(1) NOT NULL
+ , CONSTRAINT PK_CODE PRIMARY KEY (CODE_GROUP, CODE_NAME)
+);
+
+CREATE TABLE TB_DFX_USER (
USER_UUID VARCHAR(64) NOT NULL
, USER_EMAIL VARCHAR(320) NOT NULL
, USER_PASSWORD VARCHAR(512)
, USER_NICK VARCHAR(512) NOT NULL
, USER_REGISTER_TIME VARCHAR(64)
, LAST_LOGIN_TIME VARCHAR(64)
- , CONSTRAINT PK_CONSOLE_USER PRIMARY KEY (USER_UUID)
+ , CONSTRAINT PK_DFX_USER PRIMARY KEY (USER_UUID)
);
-COMMENT ON TABLE TB_CONSOLE_USER IS 'CMS 사용자';
-COMMENT ON COLUMN TB_CONSOLE_USER.USER_UUID IS '사용자 UUID - 자동생성됨';
-COMMENT ON COLUMN TB_CONSOLE_USER.USER_EMAIL IS '사용자 email - 로그인 아이디로 사용됨';
-COMMENT ON COLUMN TB_CONSOLE_USER.USER_PASSWORD IS '사용자 비밀번호';
-COMMENT ON COLUMN TB_CONSOLE_USER.USER_NICK IS '닉네임';
-COMMENT ON COLUMN TB_CONSOLE_USER.USER_REGISTER_TIME IS '가입일시';
-COMMENT ON COLUMN TB_CONSOLE_USER.LAST_LOGIN_TIME IS '마지막 로그인 일시';
-CREATE UNIQUE INDEX IX_CONSOLE_USER_01 ON TB_CONSOLE_USER(USER_EMAIL);
+COMMENT ON TABLE TB_DFX_USER IS 'DFXCONSOLE 사용자';
+COMMENT ON COLUMN TB_DFX_USER.USER_UUID IS '사용자 UUID - 자동생성됨';
+COMMENT ON COLUMN TB_DFX_USER.USER_EMAIL IS '사용자 email - 로그인 아이디로 사용됨';
+COMMENT ON COLUMN TB_DFX_USER.USER_PASSWORD IS '사용자 비밀번호';
+COMMENT ON COLUMN TB_DFX_USER.USER_NICK IS '닉네임';
+COMMENT ON COLUMN TB_DFX_USER.USER_REGISTER_TIME IS '가입일시';
+COMMENT ON COLUMN TB_DFX_USER.LAST_LOGIN_TIME IS '마지막 로그인 일시';
+CREATE UNIQUE INDEX IX_DFX_USER_01 ON TB_DFX_USER(USER_EMAIL);
+
+CREATE TABLE TB_DFX_AGENT_CONFIG (
+ AGENT_ID VARCHAR(256) NOT NULL
+ , HOST_NAME VARCHAR(256)
+ , LISTEN_PORT DECIMAL(5) NOT NULL
+ , DESCRIPTION VARCHAR(2048)
+ , POSTMAN_COUNT DECIMAL(9)
+ , DROPBOX_COUNT DECIMAL(9)
+ , STATUS_CODE VARCHAR(64) NOT NULL
+ , LAST_STATUS_TS TIMESTAMP NOT NULL
+ , SETTINGS_DATA CLOB
+ , CONSTRAINT PK_DFX_AGENT_CONFIG PRIMARY KEY (AGENT_ID)
+);
+COMMENT ON TABLE TB_DFX_AGENT_CONFIG IS '에이전트 설정';
+COMMENT ON COLUMN TB_DFX_AGENT_CONFIG.AGENT_ID IS '에이전트ID';
+COMMENT ON COLUMN TB_DFX_AGENT_CONFIG.HOST_NAME IS '에이전트가 설치된 HOSTNAME 또는 IP';
+COMMENT ON COLUMN TB_DFX_AGENT_CONFIG.LISTEN_PORT IS '에이전트 수신 포트';
+COMMENT ON COLUMN TB_DFX_AGENT_CONFIG.DESCRIPTION IS '에이전트 설명';
+COMMENT ON COLUMN TB_DFX_AGENT_CONFIG.POSTMAN_COUNT IS 'POSTMAN 갯수';
+COMMENT ON COLUMN TB_DFX_AGENT_CONFIG.DROPBOX_COUNT IS 'DROPBOX 갯수';
+COMMENT ON COLUMN TB_DFX_AGENT_CONFIG.STATUS_CODE IS '상태코드 CODE_GROUP: AGENT_STATUS_CODE';
+COMMENT ON COLUMN TB_DFX_AGENT_CONFIG.LAST_STATUS_TS IS '최종상태확인 시간';
+COMMENT ON COLUMN TB_DFX_AGENT_CONFIG.SETTINGS_DATA IS '에이전스 설정 파일 내용';
+
diff --git a/src/database/create-initial-data.sql b/src/database/create-initial-data.sql
index 360b2af..2b77d6f 100644
--- a/src/database/create-initial-data.sql
+++ b/src/database/create-initial-data.sql
@@ -1 +1,14 @@
-INSERT INTO TB_CONSOLE_USER (USER_UUID, USER_EMAIL, USER_PASSWORD, USER_NICK) VALUES ('dad9f3b6-45bf-49f9-85c5-1a83810d921c', 'smbaek@bsm-lab.com', 'qortpals1!', '백세민');
+INSERT INTO TB_CODE (
+ CODE_GROUP, CODE_NAME, CODE_VALUE, CODE_DESCRIPTION, ORDER_NO, PARENT_CODE_NAME, USE_YN
+)
+VALUES (
+ 'AGENT_STATUS_CODE', 'STATUS_OK', '정상', '정상', 1, NULL, 'Y'
+);
+INSERT INTO TB_CODE (
+ CODE_GROUP, CODE_NAME, CODE_VALUE, CODE_DESCRIPTION, ORDER_NO, PARENT_CODE_NAME, USE_YN
+)
+VALUES (
+ 'AGENT_STATUS_CODE', 'STATUS_UNKNOWN', '확인불가', '확인불가', 2, NULL, 'Y'
+);
+
+INSERT INTO TB_DFX_USER (USER_UUID, USER_EMAIL, USER_PASSWORD, USER_NICK) VALUES ('dad9f3b6-45bf-49f9-85c5-1a83810d921c', 'smbaek@bsm-lab.com', 'qortpals1!', '백세민');
diff --git a/src/main/front/src/router/index.js b/src/main/front/src/router/index.js
index 4f30514..07cc6cb 100644
--- a/src/main/front/src/router/index.js
+++ b/src/main/front/src/router/index.js
@@ -15,7 +15,7 @@ const router = createRouter({
meta: { isRequiredAuth: false },
},
{
- path: '/about',
+ path: '/about.html',
name: 'about',
// route level code-splitting
// this generates a separate chunk (About.[hash].js) for this route
@@ -24,19 +24,19 @@ const router = createRouter({
meta: { isRequiredAuth: false },
},
{
- path: '/login',
+ path: '/login.html',
name: 'login',
component: LoginView,
meta: { isRequiredAuth: false },
},
{
- path: '/main',
+ path: '/main.html',
name: 'main',
component: MainView,
meta: { isRequiredAuth: true },
},
{
- path: '/main-example',
+ path: '/main-example.html',
name: 'main-example',
component: MainViewExample,
meta: { isRequiredAuth: false },
@@ -47,9 +47,9 @@ console.log('test')
router.beforeEach((to, from, next) => {
if (to.meta.isRequiredAuth && !userInfo.value.isLogin) {
- next('/login')
- } else if ((to.path === '/login' || to.path === '/') && userInfo.value.isLogin) {
- next('/main')
+ next('/login.html')
+ } else if ((to.path === '/login.html' || to.path === '/') && userInfo.value.isLogin) {
+ next('/main.html')
} else {
next()
}
diff --git a/src/main/front/src/views/MainView.vue b/src/main/front/src/views/MainView.vue
index 87078a2..7ee8188 100644
--- a/src/main/front/src/views/MainView.vue
+++ b/src/main/front/src/views/MainView.vue
@@ -1,16 +1,30 @@
@@ -48,8 +62,8 @@ const shortThroughputChartOptions = {
agent-mkami
-
상태 : 아이콘
-
처리량 : 실시간 처리량 숫자
+
Host : mkami-oracle
+
처리량 : 789
@@ -57,8 +71,8 @@ const shortThroughputChartOptions = {
agent-ami
-
상태 : 아이콘
-
처리량 : 실시간 처리량 숫자
+
상태 : ami-cubrid
+
처리량 : 345
@@ -78,9 +92,7 @@ const shortThroughputChartOptions = {
-
주간 처리량
-
그래프
-
에이전트 throughtput 모니터링 요약
+
diff --git a/src/main/java/com/bsmlab/dfx/dfxconsole/app/user/ConsoleUserMapper.java b/src/main/java/com/bsmlab/dfx/dfxconsole/app/user/ConsoleUserMapper.java
deleted file mode 100644
index 4f188ec..0000000
--- a/src/main/java/com/bsmlab/dfx/dfxconsole/app/user/ConsoleUserMapper.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.bsmlab.dfx.dfxconsole.app.user;
-
-import org.apache.ibatis.annotations.Mapper;
-
-import java.util.List;
-
-@Mapper
-public interface ConsoleUserMapper {
- ConsoleUserDto selectConsoleUserByUserUuid(ConsoleUserDto consoleUserDto);
- ConsoleUserDto selectConsoleUserByUserEmail(ConsoleUserDto consoleUserDto);
- List selectConsoleUserSearchListForPage(UserSearchParameterDto userSearchParameterDto);
- void insertConsoleUser(ConsoleUserDto consoleUserDto);
-}
diff --git a/src/main/java/com/bsmlab/dfx/dfxconsole/app/user/ConsoleUserDto.java b/src/main/java/com/bsmlab/dfx/dfxconsole/app/user/DfxUserDto.java
similarity index 93%
rename from src/main/java/com/bsmlab/dfx/dfxconsole/app/user/ConsoleUserDto.java
rename to src/main/java/com/bsmlab/dfx/dfxconsole/app/user/DfxUserDto.java
index 4f99716..a5ccf1d 100644
--- a/src/main/java/com/bsmlab/dfx/dfxconsole/app/user/ConsoleUserDto.java
+++ b/src/main/java/com/bsmlab/dfx/dfxconsole/app/user/DfxUserDto.java
@@ -9,7 +9,7 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Builder
-public class ConsoleUserDto {
+public class DfxUserDto {
private String userUuid;
private String userEmail;
private String userPassword;
diff --git a/src/main/java/com/bsmlab/dfx/dfxconsole/app/user/DfxUserMapper.java b/src/main/java/com/bsmlab/dfx/dfxconsole/app/user/DfxUserMapper.java
new file mode 100644
index 0000000..7569208
--- /dev/null
+++ b/src/main/java/com/bsmlab/dfx/dfxconsole/app/user/DfxUserMapper.java
@@ -0,0 +1,13 @@
+package com.bsmlab.dfx.dfxconsole.app.user;
+
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface DfxUserMapper {
+ DfxUserDto selectConsoleUserByUserUuid(DfxUserDto dfxUserDto);
+ DfxUserDto selectConsoleUserByUserEmail(DfxUserDto dfxUserDto);
+ List selectConsoleUserSearchListForPage(UserSearchParameterDto userSearchParameterDto);
+ void insertConsoleUser(DfxUserDto dfxUserDto);
+}
diff --git a/src/main/java/com/bsmlab/dfx/dfxconsole/framework/config/AppUserDetails.java b/src/main/java/com/bsmlab/dfx/dfxconsole/framework/config/AppUserDetails.java
index 84a1d98..e464d6b 100644
--- a/src/main/java/com/bsmlab/dfx/dfxconsole/framework/config/AppUserDetails.java
+++ b/src/main/java/com/bsmlab/dfx/dfxconsole/framework/config/AppUserDetails.java
@@ -1,6 +1,6 @@
package com.bsmlab.dfx.dfxconsole.framework.config;
-import com.bsmlab.dfx.dfxconsole.app.user.ConsoleUserDto;
+import com.bsmlab.dfx.dfxconsole.app.user.DfxUserDto;
import io.micrometer.common.util.StringUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
@@ -11,11 +11,11 @@ import java.util.Collection;
import java.util.List;
public class AppUserDetails implements UserDetails {
- private final ConsoleUserDto consoleUserDto;
+ private final DfxUserDto dfxUserDto;
private final Collection extends GrantedAuthority> authorities;
- public AppUserDetails(ConsoleUserDto consoleUserDto) {
- this.consoleUserDto = consoleUserDto;
+ public AppUserDetails(DfxUserDto dfxUserDto) {
+ this.dfxUserDto = dfxUserDto;
this.authorities = List.of(new SimpleGrantedAuthority("USER"));
}
@@ -27,32 +27,32 @@ public class AppUserDetails implements UserDetails {
@Override
public String getPassword() {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
- return bCryptPasswordEncoder.encode(this.consoleUserDto.getUserPassword());
+ return bCryptPasswordEncoder.encode(this.dfxUserDto.getUserPassword());
//return this.consoleUserDto.getUserPassword();
}
@Override
public String getUsername() {
- return this.consoleUserDto.getUserEmail();
+ return this.dfxUserDto.getUserEmail();
}
@Override
public boolean isAccountNonExpired() {
- return this.consoleUserDto != null && StringUtils.isNotBlank(this.consoleUserDto.getUserUuid());
+ return this.dfxUserDto != null && StringUtils.isNotBlank(this.dfxUserDto.getUserUuid());
}
@Override
public boolean isAccountNonLocked() {
- return this.consoleUserDto != null && StringUtils.isNotBlank(this.consoleUserDto.getUserUuid());
+ return this.dfxUserDto != null && StringUtils.isNotBlank(this.dfxUserDto.getUserUuid());
}
@Override
public boolean isCredentialsNonExpired() {
- return this.consoleUserDto != null && StringUtils.isNotBlank(this.consoleUserDto.getUserUuid());
+ return this.dfxUserDto != null && StringUtils.isNotBlank(this.dfxUserDto.getUserUuid());
}
@Override
public boolean isEnabled() {
- return this.consoleUserDto != null && StringUtils.isNotBlank(this.consoleUserDto.getUserUuid());
+ return this.dfxUserDto != null && StringUtils.isNotBlank(this.dfxUserDto.getUserUuid());
}
}
diff --git a/src/main/java/com/bsmlab/dfx/dfxconsole/framework/config/AppUserDetailsService.java b/src/main/java/com/bsmlab/dfx/dfxconsole/framework/config/AppUserDetailsService.java
index 436d6b3..4d3ff1d 100644
--- a/src/main/java/com/bsmlab/dfx/dfxconsole/framework/config/AppUserDetailsService.java
+++ b/src/main/java/com/bsmlab/dfx/dfxconsole/framework/config/AppUserDetailsService.java
@@ -1,7 +1,7 @@
package com.bsmlab.dfx.dfxconsole.framework.config;
-import com.bsmlab.dfx.dfxconsole.app.user.ConsoleUserDto;
-import com.bsmlab.dfx.dfxconsole.app.user.ConsoleUserMapper;
+import com.bsmlab.dfx.dfxconsole.app.user.DfxUserDto;
+import com.bsmlab.dfx.dfxconsole.app.user.DfxUserMapper;
import io.micrometer.common.util.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -14,13 +14,13 @@ import org.springframework.stereotype.Service;
@Slf4j
@RequiredArgsConstructor
public class AppUserDetailsService implements UserDetailsService {
- private final ConsoleUserMapper consoleUserMapper;
+ private final DfxUserMapper dfxUserMapper;
@Override
public UserDetails loadUserByUsername(String userEmail) throws UsernameNotFoundException {
- ConsoleUserDto consoleUserDto = consoleUserMapper.selectConsoleUserByUserEmail(ConsoleUserDto.builder().userEmail(userEmail).build());
- if(consoleUserDto == null || StringUtils.isBlank(consoleUserDto.getUserUuid())) {
+ DfxUserDto dfxUserDto = dfxUserMapper.selectConsoleUserByUserEmail(DfxUserDto.builder().userEmail(userEmail).build());
+ if(dfxUserDto == null || StringUtils.isBlank(dfxUserDto.getUserUuid())) {
throw new UsernameNotFoundException("사용자 정보를 찾을 수 없습니다.");
}
- return new AppUserDetails(consoleUserDto);
+ return new AppUserDetails(dfxUserDto);
}
}
diff --git a/src/main/java/com/bsmlab/dfx/dfxconsole/framework/config/JsonUsernamePasswordAuthenticationFilter.java b/src/main/java/com/bsmlab/dfx/dfxconsole/framework/config/JsonUsernamePasswordAuthenticationFilter.java
index 662d538..0866354 100644
--- a/src/main/java/com/bsmlab/dfx/dfxconsole/framework/config/JsonUsernamePasswordAuthenticationFilter.java
+++ b/src/main/java/com/bsmlab/dfx/dfxconsole/framework/config/JsonUsernamePasswordAuthenticationFilter.java
@@ -1,8 +1,11 @@
package com.bsmlab.dfx.dfxconsole.framework.config;
import com.fasterxml.jackson.databind.ObjectMapper;
+import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -11,9 +14,13 @@ import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import java.io.IOException;
+import java.util.HashMap;
import java.util.Map;
+@Slf4j
+@RequiredArgsConstructor
public class JsonUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
+ ObjectMapper objectMapper = new ObjectMapper();
@SuppressWarnings("unchecked")
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
@@ -21,7 +28,6 @@ public class JsonUsernamePasswordAuthenticationFilter extends UsernamePasswordAu
throw new IllegalArgumentException("not application/json");
}
try {
- ObjectMapper objectMapper = new ObjectMapper();
Map userInfoMap = objectMapper.readValue(request.getInputStream(), Map.class);
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userInfoMap.get("username"), userInfoMap.get("password"));
this.setDetails(request, usernamePasswordAuthenticationToken);
@@ -31,4 +37,28 @@ public class JsonUsernamePasswordAuthenticationFilter extends UsernamePasswordAu
throw new AuthenticationServiceException("사용자 정보를 확인할 수 없습니다.");
}
}
+
+ // 로그인 성공 후 결과 메시지 전달. 자동 호출됨.
+ @Override
+ protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException {
+ log.info("로그인 성공: {}", authResult.getName());
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.setContentType("application/json");
+ Map result = new HashMap<>();
+ result.put("success", true);
+ result.put("username", authResult.getName());
+ objectMapper.writeValue(response.getWriter(), result);
+ }
+
+ // 로그인 실패 후 결과 메시지 전달. 자동 호출됨.
+ @Override
+ protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException {
+ log.warn("로그인 실패: {}", failed.getMessage());
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ response.setContentType("application/json");
+ Map result = new HashMap<>();
+ result.put("success", false);
+ result.put("message", "인증에 실패했습니다.");
+ objectMapper.writeValue(response.getWriter(), result);
+ }
}
diff --git a/src/main/java/com/bsmlab/dfx/dfxconsole/framework/config/PasswordGeneratorController.java b/src/main/java/com/bsmlab/dfx/dfxconsole/framework/config/PasswordGeneratorController.java
new file mode 100644
index 0000000..0a80921
--- /dev/null
+++ b/src/main/java/com/bsmlab/dfx/dfxconsole/framework/config/PasswordGeneratorController.java
@@ -0,0 +1,32 @@
+package com.bsmlab.dfx.dfxconsole.framework.config;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Slf4j
+@RequiredArgsConstructor
+@Controller
+public class PasswordGeneratorController {
+ private final PasswordEncoder passwordEncoder;
+
+ @RequestMapping(value = "/public-api/passwordGenerator")
+ public Map passwordGenerator(Map paramMap) {
+ Map resultMap = new HashMap<>();
+ String plainPassword = paramMap.get("password");
+ if(StringUtils.isNotEmpty(plainPassword)) {
+ String encryptedPassword = passwordEncoder.encode(plainPassword);
+ resultMap.put("password", encryptedPassword);
+ }
+ else {
+ resultMap.put("password", "");
+ }
+ return resultMap;
+ }
+}
diff --git a/src/main/java/com/bsmlab/dfx/dfxconsole/framework/config/SecurityConfig.java b/src/main/java/com/bsmlab/dfx/dfxconsole/framework/config/SecurityConfig.java
index 218c797..b2646a3 100644
--- a/src/main/java/com/bsmlab/dfx/dfxconsole/framework/config/SecurityConfig.java
+++ b/src/main/java/com/bsmlab/dfx/dfxconsole/framework/config/SecurityConfig.java
@@ -5,10 +5,13 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
+import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
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.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
+import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@@ -31,12 +34,12 @@ public class SecurityConfig {
)
.formLogin(form -> form
.loginPage("/login.html")
- .loginProcessingUrl("/loginProcess")
+ .loginProcessingUrl("/public-api/loginProcess")
.defaultSuccessUrl("/index.html")
.permitAll()
)
.logout(logout -> logout
- .logoutUrl("/logout")
+ .logoutUrl("/public-api/logoutProcess")
.logoutSuccessUrl("/login.html")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
@@ -46,15 +49,31 @@ public class SecurityConfig {
return httpSecurity.build();
}
+ /*
+1. 사용자가 POST /public-api/loginProcess 요청 (username, password)
+2. JsonUsernamePasswordAuthenticationFilter → attemptAuthentication()
+3. UsernamePasswordAuthenticationToken 생성
+4. AuthenticationManager → DaoAuthenticationProvider로 위임
+5. DaoAuthenticationProvider
+ ├─ AppUserDetailsService.loadUserByUsername() 호출
+ ├─ UserDetails.getPassword() ← 암호화된 비밀번호
+ ├─ 입력값 password 와 비교: passwordEncoder.matches(raw, encoded)
+ └─ 성공 or 실패
+ */
@Bean
- public SecurityFilterChain securityFilterChainAjax(HttpSecurity httpSecurity) throws Exception {
+ public JsonUsernamePasswordAuthenticationFilter jsonUsernamePasswordAuthenticationFilter(AuthenticationManager authenticationManager) {
JsonUsernamePasswordAuthenticationFilter jsonUsernamePasswordAuthenticationFilter = new JsonUsernamePasswordAuthenticationFilter();
- jsonUsernamePasswordAuthenticationFilter.setAuthenticationManager(httpSecurity.getSharedObject(AuthenticationManager.class));
+ jsonUsernamePasswordAuthenticationFilter.setAuthenticationManager(authenticationManager);
jsonUsernamePasswordAuthenticationFilter.setFilterProcessesUrl("/public-api/loginProcess");
+ return jsonUsernamePasswordAuthenticationFilter;
+ }
+
+ @Bean
+ public SecurityFilterChain securityFilterChainAjax(HttpSecurity httpSecurity, AuthenticationConfiguration authenticationConfiguration) throws Exception {
httpSecurity
.csrf(AbstractHttpConfigurer::disable)
- .authorizeHttpRequests(authorize -> authorize.requestMatchers("/app-api/**").hasRole("USER").anyRequest().permitAll())
- .addFilterAt(jsonUsernamePasswordAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
+ .authorizeHttpRequests(authorize -> authorize.requestMatchers("/app-api/**").authenticated().anyRequest().permitAll())
+ .addFilterAt(this.jsonUsernamePasswordAuthenticationFilter(this.authenticationManager(authenticationConfiguration)), UsernamePasswordAuthenticationFilter.class)
.sessionManagement(session -> session.maximumSessions(1).maxSessionsPreventsLogin(false))
;
return httpSecurity.build();
@@ -70,4 +89,17 @@ public class SecurityConfig {
return new GrantedAuthorityDefaults(""); // "ROLE_" prefix 를 제거한다.
}
+ @Bean
+ public DaoAuthenticationProvider daoAuthenticationProvider(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
+ DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
+ daoAuthenticationProvider.setUserDetailsService(userDetailsService);
+ daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
+ return daoAuthenticationProvider;
+ }
+
+ @Bean
+ public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
+ return authenticationConfiguration.getAuthenticationManager();
+ }
+
}
diff --git a/src/main/java/com/bsmlab/dfx/dfxconsole/framework/dto/SearchParameterDto.java b/src/main/java/com/bsmlab/dfx/dfxconsole/framework/dto/SearchParameterDto.java
new file mode 100644
index 0000000..30091fa
--- /dev/null
+++ b/src/main/java/com/bsmlab/dfx/dfxconsole/framework/dto/SearchParameterDto.java
@@ -0,0 +1,25 @@
+package com.bsmlab.dfx.dfxconsole.framework.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.SuperBuilder;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@SuperBuilder
+public class SearchParameterDto {
+ @Builder.Default
+ private long page = 1;
+ @Builder.Default
+ private int itemCountPerPage = 20;
+ @Builder.Default
+ private long totalItemCount = 0;
+ @Builder.Default
+ private Map parameters = new HashMap<>();
+}
diff --git a/src/main/resources/mapper/app/user.xml b/src/main/resources/mapper/app/user.xml
index 527ee66..5a99650 100644
--- a/src/main/resources/mapper/app/user.xml
+++ b/src/main/resources/mapper/app/user.xml
@@ -1,22 +1,22 @@
-
+
-