admin: 인증 오류 처리 custom AuthenticationEntryPoint 추가
This commit is contained in:
parent
e5f350630f
commit
a153536521
|
|
@ -0,0 +1,27 @@
|
||||||
|
package com.bpgroup.poc.admin.common;
|
||||||
|
|
||||||
|
import com.bpgroup.poc.admin.security.jwt.JwtTokenConstants;
|
||||||
|
import jakarta.servlet.http.Cookie;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class CookieHelper {
|
||||||
|
public static Optional<String> getValueFromCookieWithName(String name) {
|
||||||
|
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
|
||||||
|
HttpServletRequest request = attr.getRequest();
|
||||||
|
|
||||||
|
Cookie[] cookies = request.getCookies();
|
||||||
|
if (null != cookies) {
|
||||||
|
for (Cookie cookie : cookies) {
|
||||||
|
if (JwtTokenConstants.NAME.equals(cookie.getName())) {
|
||||||
|
return Optional.of(cookie.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -43,9 +43,11 @@ public class LoggingFilter extends OncePerRequestFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loggingResponse(ContentCachingResponseWrapper response, String sessionId) {
|
private void loggingResponse(ContentCachingResponseWrapper response, String sessionId) {
|
||||||
log.info("Session ID: {} Response - status: {} Content-Type: {}", sessionId, response.getStatus(), response.getContentType());
|
String contentType = response.getContentType();
|
||||||
|
|
||||||
if (isLoggingContentType(response.getContentType())) {
|
log.info("Session ID: {} Response - status: {} Content-Type: {}", sessionId, response.getStatus(), contentType);
|
||||||
|
|
||||||
|
if (contentType != null && isLoggingContentType(contentType)) {
|
||||||
log.info("Session ID: {} Response - body: {}", sessionId, new String(response.getContentAsByteArray(), StandardCharsets.UTF_8));
|
log.info("Session ID: {} Response - body: {}", sessionId, new String(response.getContentAsByteArray(), StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
package com.bpgroup.poc.admin.security;
|
package com.bpgroup.poc.admin.security;
|
||||||
|
|
||||||
|
import com.bpgroup.poc.admin.security.authentication.CustomAuthenticationEntryPoint;
|
||||||
import com.bpgroup.poc.admin.security.authentication.CustomAuthenticationFilter;
|
import com.bpgroup.poc.admin.security.authentication.CustomAuthenticationFilter;
|
||||||
import com.bpgroup.poc.admin.security.authentication.CustomAuthenticationProvider;
|
import com.bpgroup.poc.admin.security.authentication.CustomAuthenticationProvider;
|
||||||
import com.bpgroup.poc.admin.security.authentication.service.LoginService;
|
import com.bpgroup.poc.admin.security.authentication.service.LoginService;
|
||||||
import com.bpgroup.poc.admin.security.jwt.JwtTokenValidatorFilter;
|
import com.bpgroup.poc.admin.security.jwt.JwtTokenConstants;
|
||||||
|
import com.bpgroup.poc.admin.security.jwt.JwtTokenValidateFilter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
@ -48,7 +50,7 @@ public class SecurityConfig {
|
||||||
|
|
||||||
// 인증 설정
|
// 인증 설정
|
||||||
http.authorizeHttpRequests(c -> c
|
http.authorizeHttpRequests(c -> c
|
||||||
.requestMatchers("/css/**", "/images/**", "/js/**", "/font/**").permitAll()
|
.requestMatchers("/css/**", "/images/**", "/js/**", "/font/**", "/favicon.ico").permitAll()
|
||||||
.requestMatchers("/common/modal/**").permitAll()
|
.requestMatchers("/common/modal/**").permitAll()
|
||||||
.requestMatchers(LOGIN_PATH, LOGOUT_PATH, ERROR_PATH).permitAll()
|
.requestMatchers(LOGIN_PATH, LOGOUT_PATH, ERROR_PATH).permitAll()
|
||||||
.anyRequest().authenticated());
|
.anyRequest().authenticated());
|
||||||
|
|
@ -56,13 +58,23 @@ public class SecurityConfig {
|
||||||
http.formLogin(AbstractHttpConfigurer::disable); // Form 로그인이 아닌 Json 로그인으로 분리
|
http.formLogin(AbstractHttpConfigurer::disable); // Form 로그인이 아닌 Json 로그인으로 분리
|
||||||
http.addFilterBefore(authenticationGenerateFilter(), UsernamePasswordAuthenticationFilter.class); // 로그인 관련 Filter 설정
|
http.addFilterBefore(authenticationGenerateFilter(), UsernamePasswordAuthenticationFilter.class); // 로그인 관련 Filter 설정
|
||||||
|
|
||||||
http.addFilterAfter(new JwtTokenValidatorFilter(), BasicAuthenticationFilter.class);
|
http.addFilterAfter(new JwtTokenValidateFilter(), BasicAuthenticationFilter.class);
|
||||||
|
|
||||||
http.logout(c -> c
|
http.logout(c -> c
|
||||||
.logoutRequestMatcher(new AntPathRequestMatcher(LOGOUT_PATH, "GET"))
|
.logoutRequestMatcher(new AntPathRequestMatcher(LOGOUT_PATH, "GET"))
|
||||||
.logoutSuccessUrl(LOGIN_PATH)
|
.logoutSuccessUrl(LOGIN_PATH)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
http.exceptionHandling(c -> {
|
||||||
|
c.authenticationEntryPoint(new CustomAuthenticationEntryPoint()); // Authentication 실패 처리
|
||||||
|
});
|
||||||
|
|
||||||
|
http.logout(c -> c
|
||||||
|
.logoutRequestMatcher(new AntPathRequestMatcher(LOGOUT_PATH, "GET"))
|
||||||
|
.logoutSuccessUrl(LOGIN_PATH)
|
||||||
|
.deleteCookies(JwtTokenConstants.NAME)
|
||||||
|
);
|
||||||
|
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.bpgroup.poc.admin.security.authentication;
|
||||||
|
|
||||||
|
import com.bpgroup.poc.admin.common.CookieHelper;
|
||||||
|
import com.bpgroup.poc.admin.security.jwt.JwtTokenConstants;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||||
|
@Override
|
||||||
|
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
|
||||||
|
Optional<String> jwtToken = CookieHelper.getValueFromCookieWithName(JwtTokenConstants.NAME);
|
||||||
|
if (jwtToken.isPresent()) {
|
||||||
|
response.sendRedirect("/login?error=" + URLEncoder.encode("로그인 세션이 만료되었습니다. 다시 로그인 해주세요.", StandardCharsets.UTF_8));
|
||||||
|
} else {
|
||||||
|
response.sendRedirect("/login?error=" + URLEncoder.encode("로그인이 필요합니다.", StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
package com.bpgroup.poc.admin.security.authentication;
|
package com.bpgroup.poc.admin.security.authentication;
|
||||||
|
|
||||||
import com.bpgroup.poc.admin.security.authentication.service.LoginResponse;
|
import com.bpgroup.poc.admin.security.authentication.service.LoginResponse;
|
||||||
import com.bpgroup.poc.admin.security.jwt.JwtConstants;
|
import com.bpgroup.poc.admin.security.jwt.JwtTokenGenerator;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import io.jsonwebtoken.Jwts;
|
|
||||||
import io.jsonwebtoken.security.Keys;
|
|
||||||
import jakarta.servlet.http.Cookie;
|
import jakarta.servlet.http.Cookie;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
@ -12,7 +10,6 @@ import org.springframework.http.MediaType;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||||
|
|
||||||
import javax.crypto.SecretKey;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
|
@ -23,11 +20,8 @@ public class CustomAuthenticationSuccessHandler implements AuthenticationSuccess
|
||||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||||
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||||
|
|
||||||
// JWT 토큰을 쿠키에 추가
|
String jwtToken = JwtTokenGenerator.generate(authentication.getName());
|
||||||
String jwtToken = createJwtToken(authentication);
|
Cookie jwtCookie = JwtTokenGenerator.createJwtCookie(jwtToken);
|
||||||
Cookie jwtCookie = new Cookie(JwtConstants.JWT_TOKEN_NAME, jwtToken);
|
|
||||||
jwtCookie.setHttpOnly(true);
|
|
||||||
jwtCookie.setPath("/");
|
|
||||||
response.addCookie(jwtCookie);
|
response.addCookie(jwtCookie);
|
||||||
|
|
||||||
String jsonResponse = new ObjectMapper().writeValueAsString(
|
String jsonResponse = new ObjectMapper().writeValueAsString(
|
||||||
|
|
@ -36,17 +30,4 @@ public class CustomAuthenticationSuccessHandler implements AuthenticationSuccess
|
||||||
|
|
||||||
response.getWriter().write(jsonResponse);
|
response.getWriter().write(jsonResponse);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private static String createJwtToken(Authentication authentication) {
|
|
||||||
SecretKey key = Keys.hmacShaKeyFor(JwtConstants.JWT_KEY.getBytes(StandardCharsets.UTF_8));
|
|
||||||
return Jwts.builder()
|
|
||||||
.issuer("BP Admin")
|
|
||||||
.subject("Jwt Token")
|
|
||||||
.claim("username", authentication.getName())
|
|
||||||
.claim("details", authentication.getDetails())
|
|
||||||
.issuedAt(new java.util.Date())
|
|
||||||
.expiration(new java.util.Date(System.currentTimeMillis() + JwtConstants.EXPIRATION_TIME))
|
|
||||||
.signWith(key)
|
|
||||||
.compact();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
package com.bpgroup.poc.admin.security.jwt;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: 사용 시 별도 property 파일로 관리 필요
|
|
||||||
*/
|
|
||||||
public class JwtConstants {
|
|
||||||
public static final String JWT_KEY = "8530b13adb4e420d9694b27570635b47";
|
|
||||||
public static final String JWT_TOKEN_NAME = "JWT-TOKEN";
|
|
||||||
public static final long EXPIRATION_TIME = 60 * 10 * 1000;
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.bpgroup.poc.admin.security.jwt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: 사용 시 별도 property 파일로 관리 필요
|
||||||
|
*/
|
||||||
|
public class JwtTokenConstants {
|
||||||
|
public static final String ISSUER = "BP";
|
||||||
|
public static final String SUBJECT = "Jwt Token";
|
||||||
|
public static final String KEY = "8530b13adb4e420d9694b27570635b47";
|
||||||
|
public static final String NAME = "JWT-TOKEN";
|
||||||
|
public static final long EXPIRATION_TIME = 30000;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
package com.bpgroup.poc.admin.security.jwt;
|
||||||
|
|
||||||
|
import io.jsonwebtoken.Jwts;
|
||||||
|
import io.jsonwebtoken.security.Keys;
|
||||||
|
import jakarta.servlet.http.Cookie;
|
||||||
|
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class JwtTokenGenerator {
|
||||||
|
|
||||||
|
public static String generate(String username) {
|
||||||
|
SecretKey key = Keys.hmacShaKeyFor(JwtTokenConstants.KEY.getBytes(StandardCharsets.UTF_8));
|
||||||
|
return Jwts.builder()
|
||||||
|
.issuer(JwtTokenConstants.ISSUER)
|
||||||
|
.subject(JwtTokenConstants.SUBJECT)
|
||||||
|
.claim("username", username)
|
||||||
|
.issuedAt(new java.util.Date())
|
||||||
|
.expiration(new java.util.Date(System.currentTimeMillis() + JwtTokenConstants.EXPIRATION_TIME))
|
||||||
|
.signWith(key)
|
||||||
|
.compact();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Cookie createJwtCookie(String jwtToken) {
|
||||||
|
Cookie jwtCookie = new Cookie(JwtTokenConstants.NAME, jwtToken);
|
||||||
|
jwtCookie.setHttpOnly(true);
|
||||||
|
jwtCookie.setPath("/");
|
||||||
|
return jwtCookie;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
package com.bpgroup.poc.admin.security.jwt;
|
||||||
|
|
||||||
|
import com.bpgroup.poc.admin.common.CookieHelper;
|
||||||
|
import io.jsonwebtoken.Claims;
|
||||||
|
import io.jsonwebtoken.Jwts;
|
||||||
|
import io.jsonwebtoken.security.Keys;
|
||||||
|
import jakarta.servlet.FilterChain;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class JwtTokenValidateFilter extends OncePerRequestFilter {
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
Optional<String> jwtToken = CookieHelper.getValueFromCookieWithName(JwtTokenConstants.NAME);
|
||||||
|
if (jwtToken.isPresent()) {
|
||||||
|
SecretKey key = Keys.hmacShaKeyFor(JwtTokenConstants.KEY.getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
|
Claims claims = Jwts.parser()
|
||||||
|
.verifyWith(key)
|
||||||
|
.build()
|
||||||
|
.parseSignedClaims(jwtToken.get())
|
||||||
|
.getPayload();
|
||||||
|
|
||||||
|
String username = claims.get("username", String.class);
|
||||||
|
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(username, null, null);
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("JWT validation failed: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean shouldNotFilter(HttpServletRequest request) {
|
||||||
|
return Stream.of(
|
||||||
|
"/login", "/logout", "/error", "/css", "/js", "/images", "/favicon.ico", "/common/modal", "/font"
|
||||||
|
).anyMatch(c -> request.getRequestURI().contains(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
package com.bpgroup.poc.admin.security.jwt;
|
|
||||||
|
|
||||||
import com.bpgroup.poc.admin.security.SecurityFilterConstants;
|
|
||||||
import com.bpgroup.poc.admin.security.authentication.AuthenticationDetail;
|
|
||||||
import io.jsonwebtoken.Claims;
|
|
||||||
import io.jsonwebtoken.Jwts;
|
|
||||||
import io.jsonwebtoken.security.Keys;
|
|
||||||
import jakarta.servlet.FilterChain;
|
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import jakarta.servlet.http.Cookie;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
|
||||||
|
|
||||||
import javax.crypto.SecretKey;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class JwtTokenValidatorFilter extends OncePerRequestFilter {
|
|
||||||
@Override
|
|
||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
|
||||||
String jwt = getJwtFromCookie(request);
|
|
||||||
if (null != jwt) {
|
|
||||||
try {
|
|
||||||
SecretKey key = Keys.hmacShaKeyFor(
|
|
||||||
JwtConstants.JWT_KEY.getBytes(StandardCharsets.UTF_8));
|
|
||||||
|
|
||||||
Claims claims = Jwts.parser()
|
|
||||||
.verifyWith(key)
|
|
||||||
.build()
|
|
||||||
.parseSignedClaims(jwt)
|
|
||||||
.getPayload();
|
|
||||||
String username = claims.get("username", String.class);
|
|
||||||
String details = claims.get("details", String.class);
|
|
||||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(username, null, null);
|
|
||||||
auth.setDetails(AuthenticationDetail.fromJsonString(details));
|
|
||||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new BadCredentialsException("Invalid Jwt Token");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
filterChain.doFilter(request, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getJwtFromCookie(HttpServletRequest request) {
|
|
||||||
Cookie[] cookies = request.getCookies();
|
|
||||||
if (null != cookies) {
|
|
||||||
for (Cookie cookie : cookies) {
|
|
||||||
if (JwtConstants.JWT_TOKEN_NAME.equals(cookie.getName())) {
|
|
||||||
return cookie.getValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean shouldNotFilter(HttpServletRequest request) {
|
|
||||||
List<String> paths = List.of(SecurityFilterConstants.EXCLUDE_FILTER_STARTS_WITH_URI);
|
|
||||||
return paths.stream().anyMatch(request.getRequestURI()::startsWith);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +1,21 @@
|
||||||
package com.bpgroup.poc.admin.web.login;
|
package com.bpgroup.poc.admin.web.login;
|
||||||
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping("/login")
|
@RequestMapping("/login")
|
||||||
public class LoginController {
|
public class LoginController {
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public String loginPage() {
|
public String loginPage(@RequestParam(required = false) String error, Model model) {
|
||||||
|
if (error != null) {
|
||||||
|
model.addAttribute("error", error);
|
||||||
|
}
|
||||||
|
|
||||||
return "login/login";
|
return "login/login";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,10 +90,10 @@
|
||||||
</body>
|
</body>
|
||||||
<body>
|
<body>
|
||||||
<script type="text/javascript" th:inline="javascript">
|
<script type="text/javascript" th:inline="javascript">
|
||||||
const errorMessage = /*[[${errorMessage}]]*/ '';
|
const error = /*[[${error}]]*/ '';
|
||||||
|
|
||||||
if (errorMessage) {
|
if (error) {
|
||||||
PageHelper.showErrorModal(errorMessage);
|
PageHelper.showErrorModal(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 로그인
|
// 로그인
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue