commit
This commit is contained in:
@@ -61,6 +61,10 @@
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>2.2.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
|
||||
@@ -18,7 +18,7 @@ import lombok.RequiredArgsConstructor;
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api")
|
||||
public class AuthController {
|
||||
public class GenerateTokenApi {
|
||||
|
||||
private final AuthService authService;
|
||||
private final JwtTokenService jwtTokenService;
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.spring.domain.user.view;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/user")
|
||||
public class UserView {
|
||||
|
||||
@GetMapping("/sign-in")
|
||||
public String signin() {
|
||||
return "/views/user/signIn";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -77,7 +77,7 @@ public class QuartzConfig {
|
||||
factory.setDataSource(dataSource);
|
||||
factory.setTransactionManager(transactionManager);
|
||||
factory.setJobFactory(jobFactory);
|
||||
factory.setAutoStartup(true);
|
||||
factory.setAutoStartup(false);
|
||||
factory.setWaitForJobsToCompleteOnShutdown(true);
|
||||
return factory;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,11 @@ package com.spring.infra.security.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.ProviderManager;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
@@ -18,10 +21,15 @@ import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.spring.infra.security.filter.AuthenticationProcessingFilter;
|
||||
import com.spring.infra.security.filter.JwtAuthenticationFilter;
|
||||
import com.spring.infra.security.handler.JwtAccessDeniedHandler;
|
||||
import com.spring.infra.security.handler.JwtAuthenticationEntryPoint;
|
||||
import com.spring.infra.security.handler.SecurityAccessDeniedHandler;
|
||||
import com.spring.infra.security.handler.SecurityAuthenticationEntryPoint;
|
||||
import com.spring.infra.security.handler.SigninFailureHandler;
|
||||
import com.spring.infra.security.handler.SigninSuccessHandler;
|
||||
import com.spring.infra.security.jwt.JwtTokenService;
|
||||
import com.spring.infra.security.provider.UserAuthenticationProvider;
|
||||
|
||||
/**
|
||||
* 애플리케이션의 보안 설정을 담당하는 구성 클래스입니다.
|
||||
@@ -36,7 +44,7 @@ import com.spring.infra.security.jwt.JwtTokenService;
|
||||
@EnableMethodSecurity
|
||||
public class SecurityConfig {
|
||||
|
||||
private static final String[] PERMITTED_URI = {"/favicon.ico", "/api/auth/**", "/signIn", "/h2-console/**"};
|
||||
private static final String[] PERMITTED_URI = {"/favicon.ico", "/api/auth/**", "/user/sign-in", "/h2-console/**"};
|
||||
|
||||
/**
|
||||
* Spring Security의 필터 체인을 구성합니다.
|
||||
@@ -51,9 +59,10 @@ public class SecurityConfig {
|
||||
SecurityFilterChain securityFilterChain(
|
||||
HttpSecurity http,
|
||||
JwtTokenService tokenService,
|
||||
JwtAuthenticationEntryPoint authenticationEntryPoint,
|
||||
JwtAccessDeniedHandler accessDeniedHandler) throws Exception
|
||||
{
|
||||
SecurityAuthenticationEntryPoint authenticationEntryPoint,
|
||||
SecurityAccessDeniedHandler accessDeniedHandler,
|
||||
AuthenticationProcessingFilter authenticationProcessingFilter
|
||||
) throws Exception {
|
||||
http
|
||||
.headers(headers -> headers.frameOptions(FrameOptionsConfig::sameOrigin))
|
||||
.csrf(CsrfConfigurer::disable)
|
||||
@@ -64,12 +73,19 @@ public class SecurityConfig {
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.logout(logout -> logout
|
||||
.logoutSuccessUrl("/signIn")
|
||||
.logoutSuccessUrl("/user/sign-in")
|
||||
.invalidateHttpSession(true))
|
||||
.sessionManagement(session -> session
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
||||
)
|
||||
.addFilterBefore(new JwtAuthenticationFilter(tokenService, List.of(PERMITTED_URI)), UsernamePasswordAuthenticationFilter.class)
|
||||
.addFilterBefore(
|
||||
authenticationProcessingFilter,
|
||||
UsernamePasswordAuthenticationFilter.class
|
||||
)
|
||||
.addFilterAfter(
|
||||
new JwtAuthenticationFilter(tokenService, List.of(PERMITTED_URI)),
|
||||
AuthenticationProcessingFilter.class
|
||||
)
|
||||
.exceptionHandling(ex -> ex
|
||||
.authenticationEntryPoint(authenticationEntryPoint)
|
||||
.accessDeniedHandler(accessDeniedHandler)
|
||||
@@ -84,7 +100,8 @@ public class SecurityConfig {
|
||||
*/
|
||||
@Bean
|
||||
WebSecurityCustomizer ignoringCustomizer() {
|
||||
return web -> web.ignoring().antMatchers("/h2-console/**");
|
||||
return web -> web.ignoring()
|
||||
.requestMatchers(PathRequest.toStaticResources().atCommonLocations());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,4 +114,23 @@ public class SecurityConfig {
|
||||
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
AuthenticationManager authenticationManager(UserAuthenticationProvider provider) {
|
||||
return new ProviderManager(provider);
|
||||
}
|
||||
|
||||
@Bean
|
||||
AuthenticationProcessingFilter authenticationProcessingFilter(
|
||||
ObjectMapper objectMapper,
|
||||
AuthenticationManager authenticationManager,
|
||||
SigninSuccessHandler signinSuccessHandler,
|
||||
SigninFailureHandler signinFailureHandler
|
||||
) {
|
||||
var filter = new AuthenticationProcessingFilter(objectMapper);
|
||||
filter.setAuthenticationManager(authenticationManager);
|
||||
filter.setAuthenticationSuccessHandler(signinSuccessHandler);
|
||||
filter.setAuthenticationFailureHandler(signinFailureHandler);
|
||||
return filter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.spring.infra.security.dto;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class SignInRequest {
|
||||
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.spring.infra.security.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.spring.infra.security.dto.SignInRequest;
|
||||
|
||||
public class AuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
|
||||
|
||||
private static final String DEFAULT_LOGIN_REQUEST_URL = "/sign-in";
|
||||
private static final String HTTP_METHOD = "POST";
|
||||
private static final AntPathRequestMatcher DEFAULT_LOGIN_PATH_REQUEST_MATCHER =
|
||||
new AntPathRequestMatcher(DEFAULT_LOGIN_REQUEST_URL, HTTP_METHOD);
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public AuthenticationProcessingFilter(ObjectMapper objectMapper) {
|
||||
super(DEFAULT_LOGIN_PATH_REQUEST_MATCHER);
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
|
||||
throws AuthenticationException, IOException, ServletException {
|
||||
if (!isValidRequestType(request)) {
|
||||
throw new IllegalStateException("request is not supported. check request method and content-type");
|
||||
}
|
||||
var signInRequest = objectMapper.readValue(request.getReader(), SignInRequest.class);
|
||||
if (!isValidRequest(signInRequest)) {
|
||||
throw new IllegalArgumentException("Ussername & Password are not empty!!");
|
||||
}
|
||||
var token = new UsernamePasswordAuthenticationToken(signInRequest.getUsername(), signInRequest.getPassword());
|
||||
return this.getAuthenticationManager().authenticate(token);
|
||||
}
|
||||
|
||||
private boolean isValidRequestType(HttpServletRequest request) {
|
||||
return Objects.equals(request.getMethod(), HttpMethod.POST.name()) &&
|
||||
Objects.equals(request.getContentType(), MediaType.APPLICATION_JSON_VALUE);
|
||||
}
|
||||
|
||||
private boolean isValidRequest(SignInRequest signInRequest) {
|
||||
return StringUtils.hasText(signInRequest.getUsername()) ||
|
||||
StringUtils.hasText(signInRequest.getPassword());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import org.springframework.stereotype.Component;
|
||||
* @version 1.0
|
||||
*/
|
||||
@Component
|
||||
public class JwtAccessDeniedHandler implements AccessDeniedHandler {
|
||||
public class SecurityAccessDeniedHandler implements AccessDeniedHandler {
|
||||
|
||||
/**
|
||||
* 접근 거부 상황을 처리합니다.
|
||||
@@ -20,7 +20,7 @@ import org.springframework.stereotype.Component;
|
||||
* @version 1.0
|
||||
*/
|
||||
@Component
|
||||
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||
public class SecurityAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||
|
||||
/**
|
||||
* 인증되지 않은 접근을 처리합니다.
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.spring.infra.security.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class SigninFailureHandler implements AuthenticationFailureHandler {
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailure(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
AuthenticationException exception
|
||||
) throws IOException, ServletException {
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); //401 인증 실패
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.spring.infra.security.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.DefaultRedirectStrategy;
|
||||
import org.springframework.security.web.RedirectStrategy;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.security.web.savedrequest.RequestCache;
|
||||
import org.springframework.security.web.savedrequest.SavedRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.spring.infra.security.jwt.JwtTokenService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SigninSuccessHandler implements AuthenticationSuccessHandler {
|
||||
|
||||
private final JwtTokenService jwtTokenService;
|
||||
private RequestCache requestCache = new HttpSessionRequestCache();
|
||||
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
Authentication authentication
|
||||
) throws IOException, ServletException {
|
||||
jwtTokenService.generateAccessToken(response, authentication);
|
||||
jwtTokenService.generateRefreshToken(response, authentication);
|
||||
|
||||
SavedRequest savedRequest = requestCache.getRequest(request, response);
|
||||
if (savedRequest != null) { // 접근 권한 없는 경로 접근해서 스프링 시큐리티가 인터셉트해서 로그인폼으로 이동 후 로그인 성공한 경우
|
||||
redirectStrategy.sendRedirect(request, response, savedRequest.getRedirectUrl());
|
||||
} else { // 로그인 버튼 눌러서 로그인한 경우 기존에 있던 페이지로 리다이렉트
|
||||
String prevPage = String.valueOf(request.getSession().getAttribute("prevPage"));
|
||||
redirectStrategy.sendRedirect(request, response, prevPage);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.spring.infra.security.provider;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.spring.infra.security.service.UserPrincipalService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class UserAuthenticationProvider implements AuthenticationProvider {
|
||||
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
private final UserPrincipalService userPrincipalService;
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
String loginId = authentication.getName();
|
||||
String password = String.valueOf(authentication.getCredentials());
|
||||
UserDetails user = userPrincipalService.loadUserByUsername(loginId);
|
||||
if (isNotMatches(password, user.getPassword())) {
|
||||
throw new BadCredentialsException(loginId);
|
||||
}
|
||||
return new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> authentication) {
|
||||
return authentication.equals(UsernamePasswordAuthenticationToken.class);
|
||||
}
|
||||
|
||||
private boolean isNotMatches(String password, String encodePassword) {
|
||||
return !passwordEncoder.matches(password, encodePassword);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -73,6 +73,14 @@ spring:
|
||||
threadCount: 10
|
||||
threadPriority: 5
|
||||
|
||||
thymeleaf:
|
||||
cache: false
|
||||
check-template-location: false
|
||||
enabled: true
|
||||
prefix: classpath:/templates
|
||||
suffix: .html
|
||||
view-names: /views/*
|
||||
|
||||
h2:
|
||||
console: # H2 DB를 웹에서 관리할 수 있는 기능
|
||||
enabled: true # H2 Console 사용 여부
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
spring:
|
||||
quartz:
|
||||
scheduler:
|
||||
instanceName: batch-quartz
|
||||
instance-id: SYS_PROP
|
||||
name: BatchQuartzScheduler
|
||||
|
||||
org:
|
||||
quartz:
|
||||
jobStore:
|
||||
tablePrefix: QRTZ_
|
||||
isClustered: true
|
||||
misfireThreshold: 2000
|
||||
clusterCheckinInterval: 1000
|
||||
class: org.quartz.impl.jdbcjobstore.JobStoreTX
|
||||
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate #org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
|
||||
acquireTriggersWithinLock: true
|
||||
scheduler:
|
||||
instance-id:
|
||||
instanceName:
|
||||
rmi:
|
||||
export: false
|
||||
proxy: false
|
||||
batchTriggerAcquisitionMaxCount: 20
|
||||
idleWaitTime: 1000
|
||||
skipUpdateCheck: true
|
||||
threadPool:
|
||||
class: org.quartz.simpl.SimpleThreadPool
|
||||
threadCount: 10
|
||||
threadPriority: 5
|
||||
threadsInheritContextClassLoaderOfInitializingThread: true
|
||||
threadNamePrefix: BatchQuartz
|
||||
# dataSource:
|
||||
# nxcus:
|
||||
# driver: org.h2.Driver #oracle.jdbc.driver.OracleDriver
|
||||
# URL: 'jdbc:h2:mem:test' #jdbc:oracle:thin:@polarbear:1521:dev
|
||||
# user: mindol1004
|
||||
# password: 1111
|
||||
# maxConnections: 5
|
||||
# validationQuery: select 0 from dual
|
||||
87
batch-quartz/src/main/resources/static/css/style.css
Normal file
87
batch-quartz/src/main/resources/static/css/style.css
Normal file
@@ -0,0 +1,87 @@
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
background: linear-gradient(to right, #f0f0f5, #e9ecef);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
background-color: white;
|
||||
padding: 30px;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
|
||||
width: 350px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.icon img {
|
||||
width: 50px; /* 아이콘 크기 조정 */
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.input-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.input-icon img {
|
||||
margin-right: 10px; /* 아이콘과 인풋 간격 조정 */
|
||||
width: 20px; /* 아이콘 크기 조정 */
|
||||
height: 20px; /* 아이콘 크기 조정 */
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
border: none;
|
||||
outline: none;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
input::placeholder {
|
||||
color: #aaa; /* 플레이스홀더 색상 */
|
||||
}
|
||||
|
||||
.remember-me {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.remember-me label {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
background-color: #007aff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #005bb5;
|
||||
}
|
||||
BIN
batch-quartz/src/main/resources/static/favicon.ico
Normal file
BIN
batch-quartz/src/main/resources/static/favicon.ico
Normal file
Binary file not shown.
BIN
batch-quartz/src/main/resources/static/images/user-id.png
Normal file
BIN
batch-quartz/src/main/resources/static/images/user-id.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
batch-quartz/src/main/resources/static/images/user-lock.png
Normal file
BIN
batch-quartz/src/main/resources/static/images/user-lock.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.7 KiB |
BIN
batch-quartz/src/main/resources/static/images/user.png
Normal file
BIN
batch-quartz/src/main/resources/static/images/user.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,43 @@
|
||||
// Axios 인스턴스 생성
|
||||
const axiosInstance = axios.create({
|
||||
baseURL: 'http://localhost:8081', // 기본 URL 설정
|
||||
timeout: 10000, // 요청 타임아웃 설정 (10초)
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
// 필요한 경우 추가 헤더 설정
|
||||
}
|
||||
});
|
||||
|
||||
// 요청 인터셉터 (필요한 경우)
|
||||
axiosInstance.interceptors.request.use(
|
||||
config => {
|
||||
// 요청 전에 수행할 작업 (예: 토큰 추가)
|
||||
const token = localStorage.getItem('token'); // 예시: 로컬 스토리지에서 토큰 가져오기
|
||||
if (token) {
|
||||
config.headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
error => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// 응답 인터셉터 (필요한 경우)
|
||||
axiosInstance.interceptors.response.use(
|
||||
response => {
|
||||
return response;
|
||||
},
|
||||
error => {
|
||||
console.log(error.response);
|
||||
// 오류 처리 (예: 401 Unauthorized 처리)
|
||||
if (error.response && error.response.status === 401) {
|
||||
// 로그아웃 처리 또는 리다이렉트
|
||||
console.log("111111111111111");
|
||||
console.log(error.response);
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default axiosInstance;
|
||||
2
batch-quartz/src/main/resources/static/js/lib/axios/axios.min.js
vendored
Normal file
2
batch-quartz/src/main/resources/static/js/lib/axios/axios.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
20
batch-quartz/src/main/resources/static/js/user/signIn.js
Normal file
20
batch-quartz/src/main/resources/static/js/user/signIn.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import axiosInstance from '../common/axiosInstance.js';
|
||||
|
||||
const login = async (username, password) => {
|
||||
try {
|
||||
const response = await axiosInstance.post('/sign-in', {
|
||||
username,
|
||||
password
|
||||
});
|
||||
console.log('로그인 성공:', response.data);
|
||||
} catch (error) {
|
||||
console.error('로그인 실패:', error);
|
||||
}
|
||||
};
|
||||
|
||||
document.getElementById('signinForm').addEventListener('submit', function(event) {
|
||||
event.preventDefault(); // 기본 폼 제출 방지
|
||||
const username = document.getElementById('username').value;
|
||||
const password = document.getElementById('password').value;
|
||||
login(username, password);
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org" lang="ko" xml:lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>로그인 페이지</title>
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
<script src="/js/lib/axios/axios.min.js"></script>
|
||||
<script type="module" src="/js/user/signIn.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="icon">
|
||||
<img src="/images/user.png" alt="User Icon">
|
||||
</div>
|
||||
<h1>로그인</h1>
|
||||
<form id="signinForm" method="post">
|
||||
<div class="input-group">
|
||||
<div class="input-icon">
|
||||
<img src="/images/user-id.png" alt="User Icon">
|
||||
<input type="text" id="username" name="username" placeholder="아이디">
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<div class="input-icon">
|
||||
<img src="/images/user-lock.png" alt="Password Icon">
|
||||
<input type="password" id="password" name="password" placeholder="비밀번호">
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit">로그인</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user