[API] SSO 다중 도메인 로그인 작업 커밋
This commit is contained in:
@@ -1,44 +0,0 @@
|
||||
package com.alist.api.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
|
||||
import org.springframework.session.web.http.CookieSerializer;
|
||||
import org.springframework.session.web.http.DefaultCookieSerializer;
|
||||
|
||||
@Configuration
|
||||
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 7200) // 2시간
|
||||
public class RedisSessionConfig {
|
||||
|
||||
@Value("${cookie.secure}")
|
||||
private boolean cookieSecure;
|
||||
|
||||
@Value("${cookie.domain:}")
|
||||
private String cookieDomain;
|
||||
|
||||
@Value("${cookie.name}")
|
||||
private String cookieName;
|
||||
|
||||
@Value("${cookie.same-site:Lax}")
|
||||
private String cookieSameSite;
|
||||
|
||||
@Bean
|
||||
public CookieSerializer cookieSerializer() {
|
||||
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
|
||||
|
||||
// SSO를 위한 쿠키 설정
|
||||
serializer.setCookieName(cookieName);
|
||||
serializer.setDomainName(cookieDomain); // 모든 서브도메인에서 공유
|
||||
serializer.setCookiePath("/");
|
||||
serializer.setUseSecureCookie(cookieSecure); // 환경별 설정 (local: false, pjt: true)
|
||||
serializer.setUseHttpOnlyCookie(true); // XSS 방지
|
||||
serializer.setSameSite(cookieSameSite); // CSRF 방지
|
||||
|
||||
if (cookieDomain != null && !cookieDomain.isBlank()) {
|
||||
serializer.setDomainName(cookieDomain.trim());
|
||||
}
|
||||
|
||||
return serializer;
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,7 @@ public class SecurityConfig {
|
||||
.accessDeniedHandler(new JwtAccessDeniedHandler())
|
||||
)
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.requestMatchers("/", "/actuator/health", "/sso/**", "/auth/**", "/test/**", "/files/tusHook").permitAll()
|
||||
.requestMatchers("/", "/actuator/health", "/sso/**", "/auth/**", "/user/signup", "/files/tusHook").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.alist.api.config.cache;
|
||||
|
||||
import com.alist.api.modules.auth.vo.TestCorsOriginVo;
|
||||
import com.alist.api.modules.auth.mapper.TestCorsMapper;
|
||||
import com.alist.api.modules.auth.vo.CorsOriginVo;
|
||||
import com.alist.api.modules.auth.mapper.CorsMapper;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -16,7 +16,7 @@ import java.util.stream.Collectors;
|
||||
@RequiredArgsConstructor
|
||||
public class CorsAllowedOriginsCache {
|
||||
|
||||
private final TestCorsMapper testCorsMapper;
|
||||
private final CorsMapper corsMapper;
|
||||
|
||||
// Thread-safe List (volatile로 가시성 보장)
|
||||
private volatile List<String> allowedOrigins = new ArrayList<>();
|
||||
@@ -35,9 +35,9 @@ public class CorsAllowedOriginsCache {
|
||||
*/
|
||||
public synchronized void refresh() {
|
||||
try {
|
||||
List<String> origins = testCorsMapper.selectTestCorsAllowedList()
|
||||
List<String> origins = corsMapper.selectCorsAllowedList()
|
||||
.stream()
|
||||
.map(TestCorsOriginVo::getAllowedOrigin)
|
||||
.map(CorsOriginVo::getAllowedOrigin)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
package com.alist.api.modules.auth;
|
||||
|
||||
import com.alist.api.common.response.ApiResponse;
|
||||
import com.alist.api.common.response.ApiResponseCode;
|
||||
import com.alist.api.common.utils.SessionUtil;
|
||||
import com.alist.api.config.jwt.JwtTokenProvider;
|
||||
import com.alist.api.modules.auth.dto.SsoExchangeDto;
|
||||
import com.alist.api.modules.auth.dto.TestLoginDto;
|
||||
import com.alist.api.modules.auth.dto.LoginDto;
|
||||
import com.alist.api.modules.auth.dto.TokenDto;
|
||||
import com.alist.api.modules.auth.form.ApikeyLoginForm;
|
||||
import com.alist.api.modules.auth.form.TokenForm;
|
||||
import com.alist.api.modules.auth.service.SsoService;
|
||||
import com.alist.api.modules.auth.service.TestAuthService;
|
||||
import com.alist.api.modules.auth.service.AuthService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import com.alist.api.common.response.ApiResponse;
|
||||
import com.alist.api.common.response.ApiResponseCode;
|
||||
import com.alist.api.config.jwt.JwtTokenProvider;
|
||||
import com.alist.api.modules.auth.form.TokenForm;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Tag(name = "00. 엑세스 토큰 발급", description = "강제 엑세스 토큰 발급 (JSON 전달, 테스트용)")
|
||||
@Tag(name = "02. 엑세스 토큰 발급", description = "엑세스 토큰 발급")
|
||||
@RestController
|
||||
@RequestMapping("/auth")
|
||||
public class AuthController {
|
||||
@@ -36,9 +34,6 @@ public class AuthController {
|
||||
@Value("${cookie.domain}")
|
||||
private String cookieDomain;
|
||||
|
||||
@Value("${cookie.name}")
|
||||
private String cookieName;
|
||||
|
||||
@Value("${cookie.same-site:Lax}")
|
||||
private String cookieSameSite;
|
||||
|
||||
@@ -54,22 +49,22 @@ public class AuthController {
|
||||
private final SsoService ssoService;
|
||||
|
||||
private final JwtTokenProvider jwtTokenProvider;
|
||||
private final TestAuthService testAuthService;
|
||||
private final AuthService authService;
|
||||
|
||||
public AuthController(SsoService ssoService, JwtTokenProvider jwtTokenProvider, TestAuthService testAuthService) {
|
||||
public AuthController(SsoService ssoService, JwtTokenProvider jwtTokenProvider, AuthService authService) {
|
||||
this.ssoService = ssoService;
|
||||
this.jwtTokenProvider = jwtTokenProvider;
|
||||
this.testAuthService = testAuthService;
|
||||
this.authService = authService;
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "엑세스 토큰 발급",
|
||||
summary = "엑세스 토큰 발급 (테스트용 실사용X)",
|
||||
description = "엑세스 토큰이 발급됩니다. (테스트용 실사용X)"
|
||||
)
|
||||
@PostMapping("/token")
|
||||
public ResponseEntity<ApiResponse<TokenDto>> token(@Valid @RequestBody TokenForm tokenForm) {
|
||||
TokenDto tokenDto = new TokenDto();
|
||||
tokenDto.setAccessToken(jwtTokenProvider.createToken(tokenForm.tokenDto().getId()));
|
||||
tokenDto.setAccessToken(jwtTokenProvider.createToken(tokenForm.toTokenDto().getId()));
|
||||
|
||||
return ApiResponse.entity(tokenDto, ApiResponseCode.CODE_2001, "엑세스 토큰");
|
||||
}
|
||||
@@ -93,11 +88,11 @@ public class AuthController {
|
||||
String accessToken = jwtTokenProvider.createAccessToken(ssoSession.getUserTokenIdx(), ssoSession.getUserRole());
|
||||
String refreshToken = jwtTokenProvider.createRefreshToken(ssoSession.getUserTokenIdx());
|
||||
|
||||
TestLoginDto testLoginDto = new TestLoginDto();
|
||||
testLoginDto.setUserTokenIdx(ssoSession.getUserTokenIdx());
|
||||
testLoginDto.setRefreshToken(refreshToken);
|
||||
LoginDto loginDto = new LoginDto();
|
||||
loginDto.setUserTokenIdx(ssoSession.getUserTokenIdx());
|
||||
loginDto.setRefreshToken(refreshToken);
|
||||
|
||||
testAuthService.updateRefreshToken(testLoginDto);
|
||||
authService.updateRefreshToken(loginDto);
|
||||
|
||||
SessionUtil.addTokenCookie(response, "accessToken", accessToken, cookieDomain, cookieSecure, cookieSameSite, accessTokenValiditySeconds);
|
||||
SessionUtil.addTokenCookie(response,"refreshToken", refreshToken, cookieDomain, cookieSecure, cookieSameSite, refreshTokenValiditySeconds);
|
||||
@@ -121,73 +116,30 @@ public class AuthController {
|
||||
, HttpServletResponse response
|
||||
) {
|
||||
|
||||
TestLoginDto testLogin = testAuthService.refreshByToken(refreshToken);
|
||||
LoginDto result = authService.refreshByToken(refreshToken);
|
||||
|
||||
if (testLogin == null) {
|
||||
if (result == null) {
|
||||
return ApiResponse.entity(Map.of("refreshed", false), ApiResponseCode.CODE_401);
|
||||
}
|
||||
|
||||
SessionUtil.addTokenCookie(response, "accessToken", testLogin.getAccessToken(), cookieDomain, cookieSecure, cookieSameSite, accessTokenValiditySeconds);
|
||||
SessionUtil.addTokenCookie(response, "refreshToken", testLogin.getRefreshToken(), cookieDomain, cookieSecure, cookieSameSite, refreshTokenValiditySeconds);
|
||||
SessionUtil.addTokenCookie(response, "accessToken", result.getAccessToken(), cookieDomain, cookieSecure, cookieSameSite, accessTokenValiditySeconds);
|
||||
SessionUtil.addTokenCookie(response, "refreshToken", result.getRefreshToken(), cookieDomain, cookieSecure, cookieSameSite, refreshTokenValiditySeconds);
|
||||
|
||||
return ApiResponse.entity(Map.of("refreshed", true), ApiResponseCode.CODE_200);
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "SSO 로그인 상태 확인",
|
||||
description = "SSO 인증 받은 후 현재 세션이 있는지 확인"
|
||||
summary = "API Key 로그인",
|
||||
description = "API Key로 인증하고 JSON으로 토큰을 반환합니다. (OpenAPI/외부 서비스용)"
|
||||
)
|
||||
@GetMapping("/loginChecked")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> loginChecked(HttpServletRequest request) {
|
||||
Map<String, Object> sessionInfo = new HashMap<>();
|
||||
HttpSession session = request.getSession(false); // 새 세션 생성 금지
|
||||
@PostMapping("/apiKeyLogin")
|
||||
public ResponseEntity<ApiResponse<LoginDto>> apiKeyLogin(@Valid @RequestBody ApikeyLoginForm apiKeyLoginForm) {
|
||||
LoginDto result = authService.selectUserApiKeyLogin(apiKeyLoginForm.toLoginDto());
|
||||
|
||||
if (session == null) {
|
||||
sessionInfo.put("loggedIn", false);
|
||||
return ApiResponse.entity(sessionInfo, ApiResponseCode.CODE_200);
|
||||
if (result.getResultCode() == 2003) {
|
||||
return ApiResponse.entity(result, ApiResponseCode.CODE_2003);
|
||||
}
|
||||
|
||||
Integer userIdx = (Integer) session.getAttribute("userIdx");
|
||||
if (userIdx == null) {
|
||||
sessionInfo.put("loggedIn", false);
|
||||
return ApiResponse.entity(sessionInfo, ApiResponseCode.CODE_200);
|
||||
}
|
||||
|
||||
sessionInfo.put("loggedIn", true);
|
||||
sessionInfo.put("userIdx", userIdx);
|
||||
sessionInfo.put("userTokenIdx", session.getAttribute("userTokenIdx"));
|
||||
sessionInfo.put("userRole", session.getAttribute("userRole"));
|
||||
sessionInfo.put("userId", session.getAttribute("userId"));
|
||||
sessionInfo.put("sessionId", session.getId());
|
||||
|
||||
return ApiResponse.entity(sessionInfo, ApiResponseCode.CODE_200);
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "로그아웃",
|
||||
description = "로그아웃시 redis 에 세션 삭제 합니다."
|
||||
)
|
||||
@PostMapping("/logout")
|
||||
public ResponseEntity<ApiResponse<Map<String, Object>>> logout(
|
||||
HttpServletRequest request
|
||||
, HttpServletResponse response
|
||||
, @CookieValue(name = "refreshToken", required = false) String refreshToken
|
||||
) {
|
||||
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session != null) {
|
||||
session.invalidate();
|
||||
}
|
||||
|
||||
testAuthService.clearRefreshToken(refreshToken);
|
||||
|
||||
SessionUtil.expireCookie(response, cookieName, cookieDomain, cookieSecure, cookieSameSite);
|
||||
SessionUtil.expireCookie(response, "accessToken", cookieDomain, cookieSecure, cookieSameSite);
|
||||
SessionUtil.expireCookie(response, "refreshToken", cookieDomain, cookieSecure, cookieSameSite);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("message", "로그아웃되었습니다.");
|
||||
|
||||
return ApiResponse.entity(result, ApiResponseCode.CODE_200);
|
||||
return ApiResponse.entity(result, ApiResponseCode.CODE_2001, "엑세스 토큰");
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -13,11 +13,11 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Tag(name = "03. 테스트 CRS 갱신", description = "테스트 CORS 설정 관리 API")
|
||||
@Tag(name = "04. CRS 갱신", description = "테스트 CORS 설정 관리 API")
|
||||
@RestController
|
||||
@RequestMapping("/test")
|
||||
@RequestMapping("/cors")
|
||||
@RequiredArgsConstructor
|
||||
public class TestCorsAllowController {
|
||||
public class CorsAllowController {
|
||||
|
||||
private final CorsAllowedOriginsCache corsCache;
|
||||
|
||||
@@ -25,7 +25,7 @@ public class TestCorsAllowController {
|
||||
summary = "CORS 화이트리스트 갱신",
|
||||
description = "DB에서 CORS 허용 도메인 목록을 다시 로딩합니다. DB에 도메인 추가 후 호출하세요."
|
||||
)
|
||||
@PostMapping("/reloadCors")
|
||||
@PostMapping("/reload")
|
||||
public ResponseEntity<ApiResponse<List<String>>> reloadCors() {
|
||||
corsCache.refresh();
|
||||
List<String> cacheStatus = corsCache.getCacheStatus();
|
||||
@@ -9,7 +9,7 @@ import com.alist.api.modules.auth.dto.SsoLoginDto;
|
||||
import com.alist.api.modules.auth.form.SsoExchangeForm;
|
||||
import com.alist.api.modules.auth.form.SsoLoginForm;
|
||||
import com.alist.api.modules.auth.service.SsoService;
|
||||
import com.alist.api.modules.auth.service.TestAuthService;
|
||||
import com.alist.api.modules.auth.service.AuthService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
@@ -23,7 +23,7 @@ import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Tag(name = "02. SSO 인증", description = "공통 로그인, 인가 코드 발급, 코드 교환, 로그아웃 관련 API")
|
||||
@Tag(name = "01. SSO 인증", description = "공통 로그인, 인가 코드 발급, 코드 교환, 로그아웃 관련 API")
|
||||
@RestController
|
||||
@RequestMapping("/sso")
|
||||
public class SsoController {
|
||||
@@ -42,11 +42,11 @@ public class SsoController {
|
||||
@Value("${sso.cookie.name}")
|
||||
private String ssoCookieName;
|
||||
private final SsoService ssoService;
|
||||
private final TestAuthService testAuthService;
|
||||
private final AuthService authService;
|
||||
|
||||
public SsoController(SsoService ssoService, TestAuthService testAuthService) {
|
||||
public SsoController(SsoService ssoService, AuthService authService) {
|
||||
this.ssoService = ssoService;
|
||||
this.testAuthService = testAuthService;
|
||||
this.authService = authService;
|
||||
}
|
||||
|
||||
@Operation(
|
||||
@@ -59,7 +59,7 @@ public class SsoController {
|
||||
, HttpServletRequest request
|
||||
, HttpServletResponse response
|
||||
) {
|
||||
SsoLoginDto ssoLoginDto = ssoService.login(ssoLoginForm.ssoLoginDto(), request);
|
||||
SsoLoginDto ssoLoginDto = ssoService.login(ssoLoginForm.toSsoLoginDto(), request);
|
||||
|
||||
SsoLoginCheckDto result = new SsoLoginCheckDto();
|
||||
|
||||
@@ -136,7 +136,7 @@ public class SsoController {
|
||||
@Valid @RequestBody SsoExchangeForm ssoExchangeForm
|
||||
, HttpServletResponse response
|
||||
) {
|
||||
SsoExchangeDto result = ssoService.exchange(ssoExchangeForm.ssoExchangeDto());
|
||||
SsoExchangeDto result = ssoService.exchange(ssoExchangeForm.toSsoExchangeDto());
|
||||
|
||||
SessionUtil.addTokenCookie(response, ssoCookieName, result.getSsoSessionId(), cookieDomain, cookieSecure, cookieSameSite, ssoSessionTtlSeconds);
|
||||
|
||||
@@ -156,7 +156,7 @@ public class SsoController {
|
||||
String ssoSessionId = SessionUtil.resolveSsoCookieValue(request, ssoCookieName);
|
||||
|
||||
ssoService.logout(ssoSessionId);
|
||||
testAuthService.clearRefreshToken(refreshToken);
|
||||
authService.clearRefreshToken(refreshToken);
|
||||
|
||||
SessionUtil.expireCookie(response, ssoCookieName, cookieDomain, cookieSecure, cookieSameSite);
|
||||
SessionUtil.expireCookie(response, "accessToken", cookieDomain, cookieSecure, cookieSameSite);
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
package com.alist.api.modules.auth;
|
||||
|
||||
import com.alist.api.common.response.ApiResponse;
|
||||
import com.alist.api.common.response.ApiResponseCode;
|
||||
import com.alist.api.common.utils.SessionUtil;
|
||||
import com.alist.api.modules.auth.dto.TestLoginDto;
|
||||
import com.alist.api.modules.auth.form.TestApikeyLoginForm;
|
||||
import com.alist.api.modules.auth.form.TestLoginForm;
|
||||
import com.alist.api.modules.auth.service.TestAuthService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@Tag(name = "01. 테스트 인증", description = "테스트 사용자 로그인 및 API Key 인증 관련 API")
|
||||
@RestController
|
||||
@RequestMapping("/test")
|
||||
public class TestAuthController {
|
||||
private final TestAuthService testAuthService;
|
||||
@Value("${cookie.secure}")
|
||||
private boolean cookieSecure;
|
||||
|
||||
@Value("${cookie.domain}")
|
||||
private String cookieDomain;
|
||||
|
||||
@Value("${cookie.same-site:Lax}")
|
||||
private String cookieSameSite;
|
||||
|
||||
@Value("${jwt.access-token-validity-seconds}")
|
||||
private long accessTokenValiditySeconds;
|
||||
|
||||
@Value("${jwt.refresh-token-validity-seconds}")
|
||||
private long refreshTokenValiditySeconds;
|
||||
|
||||
public TestAuthController(TestAuthService testAuthService) {
|
||||
this.testAuthService = testAuthService;
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "테스트 사용자 로그인",
|
||||
description = "아이디/비밀번호로 로그인하고 HttpOnly 쿠키로 토큰을 전달합니다. (웹 브라우저용)"
|
||||
)
|
||||
@PostMapping("/testLogin")
|
||||
public ResponseEntity<ApiResponse<TestLoginDto>> testUserLogin(
|
||||
@Valid @RequestBody TestLoginForm testLoginForm
|
||||
, HttpServletResponse response
|
||||
, HttpSession session
|
||||
) {
|
||||
TestLoginDto testLoginDto = testAuthService.selectTestLogin(testLoginForm.testLoginDto());
|
||||
|
||||
if (testLoginDto.getResultCode() == 2003) {
|
||||
return ApiResponse.entity(testLoginDto, ApiResponseCode.CODE_2003);
|
||||
}
|
||||
|
||||
// SSO를 위한 세션에 사용자 정보 저장
|
||||
session.setAttribute("userIdx", testLoginDto.getUserIdx());
|
||||
session.setAttribute("userTokenIdx", testLoginDto.getUserTokenIdx());
|
||||
session.setAttribute("userId", testLoginDto.getId());
|
||||
session.setAttribute("userRole", "USER");
|
||||
|
||||
// accessToken 쿠키 설정
|
||||
SessionUtil.addTokenCookie(response, "accessToken", testLoginDto.getAccessToken(), cookieDomain, cookieSecure, cookieSameSite, accessTokenValiditySeconds);
|
||||
|
||||
// refreshToken 쿠키 설정
|
||||
SessionUtil.addTokenCookie(response, "refreshToken", testLoginDto.getRefreshToken(), cookieDomain, cookieSecure, cookieSameSite, refreshTokenValiditySeconds);
|
||||
|
||||
// JSON 응답에서는 토큰 제거 (쿠키로만 전달)
|
||||
testLoginDto.setAccessToken(null);
|
||||
testLoginDto.setRefreshToken(null);
|
||||
|
||||
return ApiResponse.entity(testLoginDto, ApiResponseCode.CODE_2001, "로그인");
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "테스트 API Key 로그인",
|
||||
description = "API Key로 인증하고 JSON으로 토큰을 반환합니다. (OpenAPI/외부 서비스용)"
|
||||
)
|
||||
@PostMapping("/testApiKeyLogin")
|
||||
public ResponseEntity<ApiResponse<TestLoginDto>> testUserApkKeyLogin(@Valid @RequestBody TestApikeyLoginForm testApiKeyLoginForm) {
|
||||
TestLoginDto testLoginDto = testAuthService.selectTestUserApiKeyLogin(testApiKeyLoginForm.testLoginDto());
|
||||
|
||||
if (testLoginDto.getResultCode() == 2003) {
|
||||
return ApiResponse.entity(testLoginDto, ApiResponseCode.CODE_2003);
|
||||
}
|
||||
|
||||
return ApiResponse.entity(testLoginDto, ApiResponseCode.CODE_2001, "엑세스 토큰");
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -9,7 +9,7 @@ import java.time.Instant;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestLoginDto {
|
||||
public class LoginDto {
|
||||
@Schema(description = "아이디")
|
||||
private String id;
|
||||
@Schema(description = "엑세스 토큰")
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.alist.api.modules.auth.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@@ -17,10 +16,10 @@ public class SsoLoginDto {
|
||||
private String userId;
|
||||
private String userRole;
|
||||
|
||||
public TestLoginDto testLoginDto() {
|
||||
TestLoginDto testLoginDto = new TestLoginDto();
|
||||
testLoginDto.setId(this.id);
|
||||
testLoginDto.setPassword(this.password);
|
||||
return testLoginDto;
|
||||
public LoginDto toLoginDto() {
|
||||
LoginDto loginDto = new LoginDto();
|
||||
loginDto.setId(this.id);
|
||||
loginDto.setPassword(this.password);
|
||||
return loginDto;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-8
@@ -1,16 +1,14 @@
|
||||
package com.alist.api.modules.auth.form;
|
||||
|
||||
import com.alist.api.modules.auth.dto.TestLoginDto;
|
||||
import com.alist.api.modules.auth.dto.LoginDto;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestApikeyLoginForm {
|
||||
public class ApikeyLoginForm {
|
||||
@Schema(
|
||||
description = "api key",
|
||||
example = "aaaa111dsddd"
|
||||
@@ -18,10 +16,10 @@ public class TestApikeyLoginForm {
|
||||
@NotBlank(message = "apiKey를 입력해주세요.")
|
||||
private String userApiKey;
|
||||
|
||||
public TestLoginDto testLoginDto() {
|
||||
TestLoginDto testLoginDto = new TestLoginDto();
|
||||
testLoginDto.setUserApiKey(this.userApiKey.trim());
|
||||
public LoginDto toLoginDto() {
|
||||
LoginDto loginDto = new LoginDto();
|
||||
loginDto.setUserApiKey(this.userApiKey.trim());
|
||||
|
||||
return testLoginDto;
|
||||
return loginDto;
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ public class SsoExchangeForm {
|
||||
@NotBlank
|
||||
private String clientId;
|
||||
|
||||
public SsoExchangeDto ssoExchangeDto() {
|
||||
public SsoExchangeDto toSsoExchangeDto() {
|
||||
SsoExchangeDto ssoExchangeDto = new SsoExchangeDto();
|
||||
ssoExchangeDto.setCode(code == null ? null : code.trim());
|
||||
ssoExchangeDto.setClientId(clientId == null ? null : clientId.trim());
|
||||
|
||||
@@ -12,7 +12,7 @@ public class SsoLoginForm {
|
||||
@NotBlank
|
||||
private String password;
|
||||
|
||||
public SsoLoginDto ssoLoginDto() {
|
||||
public SsoLoginDto toSsoLoginDto() {
|
||||
SsoLoginDto ssoLoginDto = new SsoLoginDto();
|
||||
ssoLoginDto.setId(id == null ? null : id.trim());
|
||||
ssoLoginDto.setPassword(password == null ? null : password.trim());
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
package com.alist.api.modules.auth.form;
|
||||
|
||||
import com.alist.api.modules.auth.dto.TestLoginDto;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestLoginForm {
|
||||
@Schema(
|
||||
description = "사용자 아이디 (공백 불가)",
|
||||
example = "test"
|
||||
)
|
||||
@NotBlank(message = "아이디를 입력해주세요.")
|
||||
private String id;
|
||||
|
||||
@Schema(
|
||||
description = "비밀번호 (8~64자, 영문 + 숫자 조합, 공백 불가)",
|
||||
example = "pass1234"
|
||||
)
|
||||
@NotBlank(message = "비밀번호를 입력해주세요.")
|
||||
@Size(min = 8, max = 64, message = "비밀번호는 8~64자여야 합니다.")
|
||||
@Pattern(
|
||||
regexp = "^(?=.*[A-Za-z])(?=.*\\d)\\S+$",
|
||||
message = "비밀번호는 영문과 숫자를 포함하고 공백이 없어야 합니다."
|
||||
)
|
||||
private String password;
|
||||
|
||||
public TestLoginDto testLoginDto() {
|
||||
TestLoginDto testLoginDto = new TestLoginDto();
|
||||
testLoginDto.setId(this.id.trim());
|
||||
testLoginDto.setPassword(this.password);
|
||||
|
||||
return testLoginDto;
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ public class TokenForm {
|
||||
@Schema(description = "사용자명", example = "test")
|
||||
private String id;
|
||||
|
||||
public TokenDto tokenDto() {
|
||||
public TokenDto toTokenDto() {
|
||||
TokenDto tokenDto = new TokenDto();
|
||||
tokenDto.setId(this.id.trim());
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.alist.api.modules.auth.mapper;
|
||||
|
||||
import com.alist.api.modules.auth.dto.LoginDto;
|
||||
import com.alist.api.modules.auth.vo.LoginTokenVo;
|
||||
import com.alist.api.modules.auth.vo.LoginVo;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
@Mapper
|
||||
public interface AuthMapper {
|
||||
LoginVo selectLogin(LoginDto loginDto);
|
||||
|
||||
LoginTokenVo selectUserTokenByUserId(LoginDto loginDto);
|
||||
|
||||
LoginTokenVo selectUserTokenByUserApiKey(LoginDto loginDto);
|
||||
|
||||
void updateRefreshToken(LoginDto loginDto);
|
||||
|
||||
LoginTokenVo selectUserTokenByUserTokenIdx(int userTokenIdx);
|
||||
|
||||
void clearRefreshTokenByUserTokenIdx(int userTokenIdx);
|
||||
|
||||
void updateLoginByLastAt(LoginDto loginDto);
|
||||
}
|
||||
+3
-3
@@ -1,15 +1,15 @@
|
||||
package com.alist.api.modules.auth.mapper;
|
||||
|
||||
import com.alist.api.modules.auth.vo.TestCorsOriginVo;
|
||||
import com.alist.api.modules.auth.vo.CorsOriginVo;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface TestCorsMapper {
|
||||
public interface CorsMapper {
|
||||
/**
|
||||
* 전체 CORS 허용 도메인 목록 조회 (user_token_idx별로)
|
||||
* @return CorsOriginDto 리스트
|
||||
*/
|
||||
List<TestCorsOriginVo> selectTestCorsAllowedList();
|
||||
List<CorsOriginVo> selectCorsAllowedList();
|
||||
}
|
||||
@@ -5,5 +5,5 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface SsoMapper {
|
||||
SsoClientVo selectSsoClient(String clientId, String redirectUri);
|
||||
SsoClientVo selectSsoClient(String clientId);
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.alist.api.modules.auth.mapper;
|
||||
|
||||
import com.alist.api.modules.auth.dto.TestLoginDto;
|
||||
import com.alist.api.modules.auth.vo.TestLoginTokenVo;
|
||||
import com.alist.api.modules.auth.vo.TestLoginVo;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
@Mapper
|
||||
public interface TestAuthMapper {
|
||||
TestLoginVo selectTestLogin(TestLoginDto testLoginDto);
|
||||
|
||||
TestLoginTokenVo selectTestUserTokenByUserId(TestLoginDto testLoginDto);
|
||||
|
||||
TestLoginTokenVo selectTestUserTokenByUserApiKey(TestLoginDto testLoginDto);
|
||||
|
||||
void updateRefreshToken(TestLoginDto testLoginDto);
|
||||
|
||||
TestLoginTokenVo selectTestUserTokenByUserTokenIdx(@Param("userTokenIdx") int userTokenIdx);
|
||||
|
||||
void clearRefreshTokenByUserTokenIdx(@Param("userTokenIdx") int userTokenIdx);
|
||||
|
||||
void updateTestLoginByLastAt(TestLoginDto testLoginDto);
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package com.alist.api.modules.auth.service;
|
||||
|
||||
import com.alist.api.config.jwt.JwtTokenProvider;
|
||||
import com.alist.api.config.properties.JwtProperties;
|
||||
import com.alist.api.modules.auth.dto.LoginDto;
|
||||
import com.alist.api.modules.auth.mapper.AuthMapper;
|
||||
import com.alist.api.modules.auth.vo.LoginTokenVo;
|
||||
import com.alist.api.modules.auth.vo.LoginVo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class AuthService {
|
||||
private final AuthMapper authMapper;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
private final JwtTokenProvider jwtTokenProvider;
|
||||
private final JwtProperties jwtProperties;
|
||||
|
||||
public AuthService(AuthMapper authMapper, PasswordEncoder passwordEncoder, JwtTokenProvider jwtTokenProvider, JwtProperties jwtProperties) {
|
||||
this.authMapper = authMapper;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
this.jwtTokenProvider = jwtTokenProvider;
|
||||
this.jwtProperties = jwtProperties;
|
||||
}
|
||||
|
||||
// id login
|
||||
public LoginDto selectLogin(LoginDto loginDto) {
|
||||
LoginVo loginVo = authMapper.selectLogin(loginDto);
|
||||
|
||||
if (loginVo != null) {
|
||||
if (passwordEncoder.matches(loginDto.getPassword(), loginVo.getPassword())) {
|
||||
|
||||
loginDto.setUserIdx(loginVo.getUserIdx());
|
||||
|
||||
LoginTokenVo loginTokenVo = authMapper.selectUserTokenByUserId(loginDto);
|
||||
|
||||
if (loginTokenVo != null) {
|
||||
loginDto.setAccessToken(jwtTokenProvider.createAccessToken(loginTokenVo.getUserTokenIdx(), loginTokenVo.getUserRole()));
|
||||
loginDto.setRefreshToken(jwtTokenProvider.createRefreshToken(loginTokenVo.getUserTokenIdx()));
|
||||
|
||||
loginDto.setUserTokenIdx(loginTokenVo.getUserTokenIdx());
|
||||
|
||||
Instant now = Instant.now();
|
||||
Instant expiresAt = now.plusSeconds(jwtProperties.getRefreshTokenValiditySeconds());
|
||||
|
||||
loginDto.setExpiresAt(expiresAt);
|
||||
|
||||
authMapper.updateRefreshToken(loginDto);
|
||||
|
||||
// 마지막 로그인 시간 추가
|
||||
authMapper.updateLoginByLastAt(loginDto);
|
||||
|
||||
loginDto.setResultCode(2001);
|
||||
} else {
|
||||
loginDto.setResultCode(2003);
|
||||
}
|
||||
} else {
|
||||
loginDto.setResultCode(2003);
|
||||
}
|
||||
} else {
|
||||
loginDto.setResultCode(2003);
|
||||
}
|
||||
|
||||
return loginDto;
|
||||
}
|
||||
|
||||
// api key login
|
||||
public LoginDto selectUserApiKeyLogin(LoginDto loginDto) {
|
||||
if (loginDto.getUserApiKey() != null) {
|
||||
LoginTokenVo loginTokenVo = authMapper.selectUserTokenByUserApiKey(loginDto);
|
||||
|
||||
if (loginTokenVo != null) {
|
||||
loginDto.setAccessToken(jwtTokenProvider.createAccessToken(loginTokenVo.getUserTokenIdx(), loginTokenVo.getUserRole()));
|
||||
loginDto.setRefreshToken(jwtTokenProvider.createRefreshToken(loginTokenVo.getUserTokenIdx()));
|
||||
|
||||
loginDto.setResultCode(2001);
|
||||
} else {
|
||||
loginDto.setResultCode(2003);
|
||||
}
|
||||
} else {
|
||||
loginDto.setResultCode(2003);
|
||||
}
|
||||
|
||||
return loginDto;
|
||||
}
|
||||
|
||||
public LoginDto refreshByToken(String refreshToken) {
|
||||
if (refreshToken == null || !jwtTokenProvider.validateToken(refreshToken)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int userTokenIdx;
|
||||
try {
|
||||
userTokenIdx = Integer.parseInt(jwtTokenProvider.getUserTokenIdx(refreshToken));
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
LoginTokenVo tokenVo = authMapper.selectUserTokenByUserTokenIdx(userTokenIdx);
|
||||
if (tokenVo == null || tokenVo.getRefreshToken() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!refreshToken.equals(tokenVo.getRefreshToken())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
LoginDto result = new LoginDto();
|
||||
result.setUserTokenIdx(userTokenIdx);
|
||||
result.setAccessToken(jwtTokenProvider.createAccessToken(tokenVo.getUserTokenIdx(), tokenVo.getUserRole()));
|
||||
result.setRefreshToken(jwtTokenProvider.createRefreshToken(tokenVo.getUserTokenIdx()));
|
||||
result.setExpiresAt(Instant.now().plusSeconds(jwtProperties.getRefreshTokenValiditySeconds()));
|
||||
|
||||
authMapper.updateRefreshToken(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void clearRefreshToken(String refreshToken) {
|
||||
if (refreshToken == null || !jwtTokenProvider.validateToken(refreshToken)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
int userTokenIdx = Integer.parseInt(jwtTokenProvider.getUserTokenIdx(refreshToken));
|
||||
authMapper.clearRefreshTokenByUserTokenIdx(userTokenIdx);
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void updateRefreshToken(LoginDto loginDto) {
|
||||
Instant now = Instant.now();
|
||||
Instant expiresAt = now.plusSeconds(jwtProperties.getRefreshTokenValiditySeconds());
|
||||
|
||||
loginDto.setExpiresAt(expiresAt);
|
||||
|
||||
authMapper.updateRefreshToken(loginDto);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package com.alist.api.modules.auth.service;
|
||||
|
||||
import com.alist.api.modules.auth.dto.SsoExchangeDto;
|
||||
import com.alist.api.modules.auth.dto.SsoLoginDto;
|
||||
import com.alist.api.modules.auth.dto.TestLoginDto;
|
||||
import com.alist.api.modules.auth.dto.LoginDto;
|
||||
import com.alist.api.modules.auth.mapper.SsoMapper;
|
||||
import com.alist.api.modules.auth.vo.SsoClientVo;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
@@ -18,34 +18,32 @@ import java.util.UUID;
|
||||
|
||||
@Service
|
||||
public class SsoService {
|
||||
private final TestAuthService testAuthService;
|
||||
|
||||
private final AuthService authService;
|
||||
private final SsoMapper ssoMapper;
|
||||
private final StringRedisTemplate redisTemplate;
|
||||
|
||||
private final Duration ssoSessionTtl;
|
||||
private final Duration ssoCodeTtl;
|
||||
|
||||
public SsoService(TestAuthService testAuthService, SsoMapper ssoMapper, StringRedisTemplate redisTemplate, @Value("${sso.session.ttl-seconds}") long ssoSessionTtlSeconds, @Value("${sso.code.ttl-seconds}") long ssoCodeTtlSeconds) {
|
||||
this.testAuthService = testAuthService;
|
||||
public SsoService(AuthService authService, SsoMapper ssoMapper, StringRedisTemplate redisTemplate, @Value("${sso.session.ttl-seconds}") long ssoSessionTtlSeconds, @Value("${sso.code.ttl-seconds}") long ssoCodeTtlSeconds) {
|
||||
this.authService = authService;
|
||||
this.ssoMapper = ssoMapper;
|
||||
this.redisTemplate = redisTemplate;
|
||||
this.ssoSessionTtl = Duration.ofSeconds(ssoSessionTtlSeconds);
|
||||
this.ssoCodeTtl = Duration.ofSeconds(ssoCodeTtlSeconds);
|
||||
}
|
||||
|
||||
public SsoLoginDto login(SsoLoginDto loginDto, HttpServletRequest request) {
|
||||
TestLoginDto testLoginDto = testAuthService.selectTestLogin(loginDto.testLoginDto());
|
||||
public SsoLoginDto login(SsoLoginDto ssoLoginDto, HttpServletRequest request) {
|
||||
LoginDto loginDto = authService.selectLogin(ssoLoginDto.toLoginDto());
|
||||
|
||||
SsoLoginDto result = new SsoLoginDto();
|
||||
result.setResultCode(testLoginDto.getResultCode());
|
||||
result.setResultCode(loginDto.getResultCode());
|
||||
|
||||
if (testLoginDto.getResultCode() == 2003) {
|
||||
if (loginDto.getResultCode() == 2003) {
|
||||
return result;
|
||||
}
|
||||
|
||||
String ssoSessionId = "SSO_" + UUID.randomUUID();
|
||||
String latestSessionKey = "alist:sso:userIdx:" + testLoginDto.getUserIdx();
|
||||
String latestSessionKey = "alist:sso:userIdx:" + loginDto.getUserIdx();
|
||||
String sessionKey = "alist:sso:session:" + ssoSessionId;
|
||||
|
||||
String oldSsoSessionId = redisTemplate.opsForValue().get(latestSessionKey);
|
||||
@@ -53,17 +51,17 @@ public class SsoService {
|
||||
redisTemplate.delete("alist:sso:session:" + oldSsoSessionId);
|
||||
}
|
||||
|
||||
redisTemplate.opsForHash().put(sessionKey, "userIdx", String.valueOf(testLoginDto.getUserIdx()));
|
||||
redisTemplate.opsForHash().put(sessionKey, "userTokenIdx", String.valueOf(testLoginDto.getUserTokenIdx()));
|
||||
redisTemplate.opsForHash().put(sessionKey, "userId", testLoginDto.getId());
|
||||
redisTemplate.opsForHash().put(sessionKey, "userIdx", String.valueOf(loginDto.getUserIdx()));
|
||||
redisTemplate.opsForHash().put(sessionKey, "userTokenIdx", String.valueOf(loginDto.getUserTokenIdx()));
|
||||
redisTemplate.opsForHash().put(sessionKey, "userId", loginDto.getId());
|
||||
redisTemplate.opsForHash().put(sessionKey, "userRole", "USER");
|
||||
redisTemplate.expire(sessionKey, ssoSessionTtl);
|
||||
|
||||
redisTemplate.opsForValue().set(latestSessionKey, ssoSessionId, ssoSessionTtl);
|
||||
|
||||
result.setSsoSessionId(ssoSessionId);
|
||||
result.setUserId(testLoginDto.getId());
|
||||
result.setUserIdx(testLoginDto.getUserIdx());
|
||||
result.setUserId(loginDto.getId());
|
||||
result.setUserIdx(loginDto.getUserIdx());
|
||||
result.setUserRole("USER");
|
||||
result.setResultCode(200);
|
||||
|
||||
@@ -119,7 +117,7 @@ public class SsoService {
|
||||
return "/login";
|
||||
}
|
||||
|
||||
SsoClientVo ssoClientVo = ssoMapper.selectSsoClient(clientId, redirectUri);
|
||||
SsoClientVo ssoClientVo = ssoMapper.selectSsoClient(clientId);
|
||||
if (ssoClientVo == null) {
|
||||
throw new IllegalArgumentException("허용되지 않은 clientId 또는 redirectUri 입니다.");
|
||||
}
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
package com.alist.api.modules.auth.service;
|
||||
|
||||
import com.alist.api.config.jwt.JwtTokenProvider;
|
||||
import com.alist.api.config.properties.JwtProperties;
|
||||
import com.alist.api.modules.auth.dto.TestLoginDto;
|
||||
import com.alist.api.modules.auth.mapper.TestAuthMapper;
|
||||
import com.alist.api.modules.auth.vo.TestLoginTokenVo;
|
||||
import com.alist.api.modules.auth.vo.TestLoginVo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class TestAuthService {
|
||||
private final TestAuthMapper testAuthMapper;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
private final JwtTokenProvider jwtTokenProvider;
|
||||
private final JwtProperties jwtProperties;
|
||||
|
||||
public TestAuthService(TestAuthMapper testAuthMapper, PasswordEncoder passwordEncoder, JwtTokenProvider jwtTokenProvider, JwtProperties jwtProperties) {
|
||||
this.testAuthMapper = testAuthMapper;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
this.jwtTokenProvider = jwtTokenProvider;
|
||||
this.jwtProperties = jwtProperties;
|
||||
}
|
||||
|
||||
// id login
|
||||
public TestLoginDto selectTestLogin(TestLoginDto testLoginDto) {
|
||||
TestLoginVo testLoginVo = testAuthMapper.selectTestLogin(testLoginDto);
|
||||
|
||||
if (testLoginVo != null) {
|
||||
if (passwordEncoder.matches(testLoginDto.getPassword(), testLoginVo.getPassword())) {
|
||||
|
||||
testLoginDto.setUserIdx(testLoginVo.getUserIdx());
|
||||
|
||||
TestLoginTokenVo testLoginTokenVo = testAuthMapper.selectTestUserTokenByUserId(testLoginDto);
|
||||
|
||||
if (testLoginTokenVo != null) {
|
||||
testLoginDto.setAccessToken(jwtTokenProvider.createAccessToken(testLoginTokenVo.getUserTokenIdx(), testLoginTokenVo.getUserRole()));
|
||||
testLoginDto.setRefreshToken(jwtTokenProvider.createRefreshToken(testLoginTokenVo.getUserTokenIdx()));
|
||||
|
||||
testLoginDto.setUserTokenIdx(testLoginTokenVo.getUserTokenIdx());
|
||||
|
||||
Instant now = Instant.now();
|
||||
Instant expiresAt = now.plusSeconds(jwtProperties.getRefreshTokenValiditySeconds());
|
||||
|
||||
testLoginDto.setExpiresAt(expiresAt);
|
||||
|
||||
testAuthMapper.updateRefreshToken(testLoginDto);
|
||||
|
||||
// 마지막 로그인 시간 추가
|
||||
testAuthMapper.updateTestLoginByLastAt(testLoginDto);
|
||||
|
||||
testLoginDto.setResultCode(2001);
|
||||
} else {
|
||||
testLoginDto.setResultCode(2003);
|
||||
}
|
||||
} else {
|
||||
testLoginDto.setResultCode(2003);
|
||||
}
|
||||
} else {
|
||||
testLoginDto.setResultCode(2003);
|
||||
}
|
||||
|
||||
return testLoginDto;
|
||||
}
|
||||
|
||||
// api key login
|
||||
public TestLoginDto selectTestUserApiKeyLogin(TestLoginDto testLoginDto) {
|
||||
if (testLoginDto.getUserApiKey() != null) {
|
||||
TestLoginTokenVo testLoginTokenVo = testAuthMapper.selectTestUserTokenByUserApiKey(testLoginDto);
|
||||
|
||||
if (testLoginTokenVo != null) {
|
||||
testLoginDto.setAccessToken(jwtTokenProvider.createAccessToken(testLoginTokenVo.getUserTokenIdx(), testLoginTokenVo.getUserRole()));
|
||||
testLoginDto.setRefreshToken(jwtTokenProvider.createRefreshToken(testLoginTokenVo.getUserTokenIdx()));
|
||||
|
||||
testLoginDto.setResultCode(2001);
|
||||
} else {
|
||||
testLoginDto.setResultCode(2003);
|
||||
}
|
||||
} else {
|
||||
testLoginDto.setResultCode(2003);
|
||||
}
|
||||
|
||||
return testLoginDto;
|
||||
}
|
||||
|
||||
public TestLoginDto refreshByToken(String refreshToken) {
|
||||
if (refreshToken == null || !jwtTokenProvider.validateToken(refreshToken)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int userTokenIdx;
|
||||
try {
|
||||
userTokenIdx = Integer.parseInt(jwtTokenProvider.getUserTokenIdx(refreshToken));
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TestLoginTokenVo tokenVo = testAuthMapper.selectTestUserTokenByUserTokenIdx(userTokenIdx);
|
||||
if (tokenVo == null || tokenVo.getRefreshToken() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!refreshToken.equals(tokenVo.getRefreshToken())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
TestLoginDto testLogin = new TestLoginDto();
|
||||
testLogin.setUserTokenIdx(userTokenIdx);
|
||||
testLogin.setAccessToken(jwtTokenProvider.createAccessToken(tokenVo.getUserTokenIdx(), tokenVo.getUserRole()));
|
||||
testLogin.setRefreshToken(jwtTokenProvider.createRefreshToken(tokenVo.getUserTokenIdx()));
|
||||
testLogin.setExpiresAt(Instant.now().plusSeconds(jwtProperties.getRefreshTokenValiditySeconds()));
|
||||
|
||||
testAuthMapper.updateRefreshToken(testLogin);
|
||||
return testLogin;
|
||||
}
|
||||
|
||||
public void clearRefreshToken(String refreshToken) {
|
||||
if (refreshToken == null || !jwtTokenProvider.validateToken(refreshToken)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
int userTokenIdx = Integer.parseInt(jwtTokenProvider.getUserTokenIdx(refreshToken));
|
||||
testAuthMapper.clearRefreshTokenByUserTokenIdx(userTokenIdx);
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void updateRefreshToken(TestLoginDto testLoginDto) {
|
||||
Instant now = Instant.now();
|
||||
Instant expiresAt = now.plusSeconds(jwtProperties.getRefreshTokenValiditySeconds());
|
||||
|
||||
testLoginDto.setExpiresAt(expiresAt);
|
||||
|
||||
testAuthMapper.updateRefreshToken(testLoginDto);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -5,6 +5,6 @@ import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestCorsOriginVo {
|
||||
public class CorsOriginVo {
|
||||
private String allowedOrigin;
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@ package com.alist.api.modules.auth.vo;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class TestLoginTokenVo {
|
||||
public class LoginTokenVo {
|
||||
private Integer userTokenIdx;
|
||||
private String userApiKey;
|
||||
private String userRole;
|
||||
+1
-1
@@ -3,7 +3,7 @@ package com.alist.api.modules.auth.vo;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class TestLoginVo {
|
||||
public class LoginVo {
|
||||
private Integer userIdx;
|
||||
private String id;
|
||||
private String password;
|
||||
@@ -1,20 +1,22 @@
|
||||
package com.alist.api.modules.file;
|
||||
|
||||
import com.alist.api.common.response.ApiResponse;
|
||||
import com.alist.api.common.response.ApiResponseCode;
|
||||
import com.alist.api.common.utils.SecurityUtil;
|
||||
import com.alist.api.modules.file.dto.*;
|
||||
import com.alist.api.modules.file.form.*;
|
||||
import com.alist.api.common.response.ApiResponse;
|
||||
import com.alist.api.common.response.ApiResponseCode;
|
||||
import com.alist.api.modules.file.service.FileService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.http.ContentDisposition;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -44,7 +46,7 @@ public class FileController {
|
||||
public ResponseEntity<ApiResponse<FileUploadDto>> uploadInit(
|
||||
@Valid @RequestBody FileUploadForm fileUploadForm
|
||||
) {
|
||||
FileUploadDto fileUploadDto = fileUploadForm.fileUploadDto();
|
||||
FileUploadDto fileUploadDto = fileUploadForm.toFileUploadDto();
|
||||
|
||||
Integer userTokenIdx = SecurityUtil.getLoginUserTokenIdx();
|
||||
|
||||
@@ -109,7 +111,7 @@ public class FileController {
|
||||
public ResponseEntity<ApiResponse<UploadStatusDto>> uploadStatus(
|
||||
@Valid @RequestBody UploadStatusForm uploadStatusForm
|
||||
) {
|
||||
UploadStatusDto status = fileService.getUploadStatus(uploadStatusForm.uploadStatusDto());
|
||||
UploadStatusDto status = fileService.getUploadStatus(uploadStatusForm.toUploadStatusDto());
|
||||
if (status == null) {
|
||||
return ApiResponse.entity(new UploadStatusDto(), ApiResponseCode.CODE_2003);
|
||||
}
|
||||
@@ -122,10 +124,10 @@ public class FileController {
|
||||
)
|
||||
@PostMapping("/tusHook")
|
||||
public ResponseEntity<ApiResponse<String>> tusHook(@RequestBody TusHookForm tusHookForm) {
|
||||
boolean accepted = fileService.updateFileUploadStatus(tusHookForm.tusHookDto());
|
||||
boolean accepted = fileService.updateFileUploadStatus(tusHookForm.toTusHookDto());
|
||||
|
||||
if (accepted) {
|
||||
fileService.saveUploadStatusRedisTusHook(tusHookForm.tusHookDto());
|
||||
fileService.saveUploadStatusRedisTusHook(tusHookForm.toTusHookDto());
|
||||
}
|
||||
|
||||
return ApiResponse.entity("", ApiResponseCode.CODE_200);
|
||||
@@ -273,7 +275,7 @@ public class FileController {
|
||||
public ResponseEntity<ApiResponse<String>> fileDelete(
|
||||
@Valid @RequestBody FileDeleteForm fileDeleteForm
|
||||
) {
|
||||
boolean deleted = fileService.updateFileDelete(fileDeleteForm.fileDeleteDto());
|
||||
boolean deleted = fileService.updateFileDelete(fileDeleteForm.toFileDeleteDto());
|
||||
|
||||
if (!deleted) {
|
||||
return ApiResponse.entity("", ApiResponseCode.CODE_2005, "파일 삭제");
|
||||
|
||||
@@ -11,7 +11,7 @@ public class FileDeleteForm {
|
||||
@NotBlank
|
||||
private String fileUuid;
|
||||
|
||||
public FileDeleteDto fileDeleteDto() {
|
||||
public FileDeleteDto toFileDeleteDto() {
|
||||
FileDeleteDto fileDeleteDto = new FileDeleteDto();
|
||||
fileDeleteDto.setFileUuid(fileUuid == null ? null : fileUuid.trim());
|
||||
return fileDeleteDto;
|
||||
|
||||
@@ -23,7 +23,7 @@ public class FileUploadForm {
|
||||
@Valid
|
||||
private List<FileUploadItemForm> itemList;
|
||||
|
||||
public FileUploadDto fileUploadDto() {
|
||||
public FileUploadDto toFileUploadDto() {
|
||||
FileUploadDto fileUploadDto = new FileUploadDto();
|
||||
|
||||
fileUploadDto.setFileCategory(this.fileCategory.trim());
|
||||
|
||||
@@ -16,7 +16,7 @@ public class TusHookForm {
|
||||
@JsonProperty("Event")
|
||||
private TusHookEventForm tusHookEventForm;
|
||||
|
||||
public TusHookDto tusHookDto() {
|
||||
public TusHookDto toTusHookDto() {
|
||||
TusHookDto tusHookDto = new TusHookDto();
|
||||
|
||||
tusHookDto.setType(this.type);
|
||||
|
||||
@@ -11,7 +11,7 @@ public class UploadStatusForm {
|
||||
@NotBlank
|
||||
private String fileUuid;
|
||||
|
||||
public UploadStatusDto uploadStatusDto() {
|
||||
public UploadStatusDto toUploadStatusDto() {
|
||||
UploadStatusDto uploadStatusDto = new UploadStatusDto();
|
||||
uploadStatusDto.setFileUuid(this.fileUuid == null ? null : this.fileUuid.trim());
|
||||
return uploadStatusDto;
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.alist.api.modules.testUser;
|
||||
|
||||
import com.alist.api.common.response.ApiResponse;
|
||||
import com.alist.api.common.response.ApiResponseCode;
|
||||
import com.alist.api.modules.testUser.dto.TestUserDto;
|
||||
import com.alist.api.modules.testUser.form.TestUserSignupForm;
|
||||
import com.alist.api.modules.testUser.service.TestUserService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Tag(name = "02. 테스트 사용자 관리", description = "테스트 사용자 회원가입 및 관리 API")
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/test")
|
||||
public class TestUserController {
|
||||
|
||||
public final TestUserService testUserService;
|
||||
|
||||
public TestUserController(TestUserService testUserService) {
|
||||
this.testUserService = testUserService;
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "테스트 사용자 회원가입",
|
||||
description = "새로운 테스트 사용자를 등록합니다. 아이디 중복 시 오류를 반환합니다."
|
||||
)
|
||||
@PostMapping("/testSignup")
|
||||
public ResponseEntity<ApiResponse<TestUserDto>> testSignup(@Valid @RequestBody TestUserSignupForm testUserSignupForm) {
|
||||
|
||||
TestUserDto testUserDto = testUserService.insertTestUserProc(testUserSignupForm.testUserDto());
|
||||
|
||||
if (testUserDto.getResultCode() == 2004) {
|
||||
return ApiResponse.entity(testUserDto, ApiResponseCode.CODE_2004, "아이디");
|
||||
}
|
||||
|
||||
return ApiResponse.entity(testUserDto, ApiResponseCode.CODE_2002, "아이디");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.alist.api.modules.testUser.mapper;
|
||||
|
||||
import com.alist.api.modules.testUser.dto.TestUserDto;
|
||||
import com.alist.api.modules.testUser.dto.TestUserTokenDto;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface TestUserMapper {
|
||||
int selectDuplicateTestUserCount(TestUserDto testUserDto);
|
||||
|
||||
int insertTestUserSignup(TestUserDto testUserDto);
|
||||
|
||||
int insertTestUserTokenSignup(TestUserTokenDto testUserTokenDto);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package com.alist.api.modules.testUser.service;
|
||||
|
||||
import com.alist.api.common.utils.ApiKeyGenerator;
|
||||
import com.alist.api.modules.testUser.dto.TestUserDto;
|
||||
import com.alist.api.modules.testUser.dto.TestUserTokenDto;
|
||||
import com.alist.api.modules.testUser.mapper.TestUserMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class TestUserService {
|
||||
private final TestUserMapper testUserMapper;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
public TestUserService(TestUserMapper testUserMapper, PasswordEncoder passwordEncoder) {
|
||||
this.testUserMapper = testUserMapper;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public TestUserDto insertTestUserProc(TestUserDto testUserDto) {
|
||||
// 중복체크
|
||||
if (testUserMapper.selectDuplicateTestUserCount(testUserDto) > 0) {
|
||||
testUserDto.setResultCode(2004);
|
||||
return testUserDto;
|
||||
}
|
||||
|
||||
// 비밀번호 생성
|
||||
testUserDto.setNewPassword(passwordEncoder.encode(testUserDto.getPassword()));
|
||||
|
||||
// 회원정보 입력
|
||||
int result = testUserMapper.insertTestUserSignup(testUserDto);
|
||||
|
||||
if (result > 0) {
|
||||
// user_api_key 생성
|
||||
TestUserTokenDto testUserTokenDto = new TestUserTokenDto();
|
||||
testUserTokenDto.setUserIdx(testUserDto.getUserIdx());
|
||||
|
||||
apiKeyWithRetry(testUserTokenDto);
|
||||
}
|
||||
|
||||
log.info("cnt : " + testUserDto.getUserIdx());
|
||||
log.info("userIdx : " + testUserDto.getUserIdx());
|
||||
|
||||
return testUserDto;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public int apiKeyWithRetry(TestUserTokenDto testUserTokenDto) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
testUserTokenDto.setUserApiKey(ApiKeyGenerator.userApiKeyProc());
|
||||
try {
|
||||
return testUserMapper.insertTestUserTokenSignup(testUserTokenDto);
|
||||
} catch (DuplicateKeyException e) {
|
||||
// 충돌이면 다시 생성
|
||||
log.warn("Duplicate API key. retrying... userId={}", testUserTokenDto.getUserIdx());
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("API key generation failed after retries.");
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package com.alist.api.modules.testUser.vo;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class TestUserVo {
|
||||
private String id;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.alist.api.modules.user;
|
||||
|
||||
import com.alist.api.common.response.ApiResponse;
|
||||
import com.alist.api.common.response.ApiResponseCode;
|
||||
import com.alist.api.modules.user.dto.UserDto;
|
||||
import com.alist.api.modules.user.form.UserSignupForm;
|
||||
import com.alist.api.modules.user.service.UserService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Tag(name = "05. 사용자 관리", description = "사용자 회원가입 및 관리 API")
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/user")
|
||||
public class UserController {
|
||||
|
||||
public final UserService userService;
|
||||
|
||||
public UserController(UserService userService) {
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@Operation(
|
||||
summary = "사용자 회원가입",
|
||||
description = "새로운 사용자를 등록합니다. 아이디 중복 시 오류를 반환합니다."
|
||||
)
|
||||
@PostMapping("/signup")
|
||||
public ResponseEntity<ApiResponse<UserDto>> signup(@Valid @RequestBody UserSignupForm userSignupForm) {
|
||||
|
||||
UserDto userDto = userService.insertUser(userSignupForm.toUserDto());
|
||||
|
||||
if (userDto.getResultCode() == 2004) {
|
||||
return ApiResponse.entity(userDto, ApiResponseCode.CODE_2004, "아이디");
|
||||
}
|
||||
|
||||
return ApiResponse.entity(userDto, ApiResponseCode.CODE_2002, "아이디");
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package com.alist.api.modules.testUser.dto;
|
||||
package com.alist.api.modules.user.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Getter;
|
||||
@@ -6,7 +6,7 @@ import lombok.Setter;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public class TestUserDto {
|
||||
public class UserDto {
|
||||
private Integer userIdx;
|
||||
private String id;
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
package com.alist.api.modules.testUser.dto;
|
||||
package com.alist.api.modules.user.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public class TestUserTokenDto {
|
||||
public class UserTokenDto {
|
||||
private Integer userTokenIdx;
|
||||
private Integer userIdx;
|
||||
private String userApiKey;
|
||||
+8
-8
@@ -1,6 +1,6 @@
|
||||
package com.alist.api.modules.testUser.form;
|
||||
package com.alist.api.modules.user.form;
|
||||
|
||||
import com.alist.api.modules.testUser.dto.TestUserDto;
|
||||
import com.alist.api.modules.user.dto.UserDto;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
@@ -11,7 +11,7 @@ import lombok.Setter;
|
||||
@Setter
|
||||
@Getter
|
||||
@Schema(description = "회원 가입 요청 폼")
|
||||
public class TestUserSignupForm {
|
||||
public class UserSignupForm {
|
||||
@Schema(
|
||||
description = "사용자 아이디 (공백 불가)",
|
||||
example = "test"
|
||||
@@ -31,10 +31,10 @@ public class TestUserSignupForm {
|
||||
)
|
||||
private String password;
|
||||
|
||||
public TestUserDto testUserDto() {
|
||||
TestUserDto testUserDto = new TestUserDto();
|
||||
testUserDto.setId(id.trim());
|
||||
testUserDto.setPassword(password);
|
||||
return testUserDto;
|
||||
public UserDto toUserDto() {
|
||||
UserDto userDto = new UserDto();
|
||||
userDto.setId(id.trim());
|
||||
userDto.setPassword(password);
|
||||
return userDto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.alist.api.modules.user.mapper;
|
||||
|
||||
import com.alist.api.modules.user.dto.UserDto;
|
||||
import com.alist.api.modules.user.dto.UserTokenDto;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface UserMapper {
|
||||
int selectDuplicateUserCount(UserDto userDto);
|
||||
|
||||
int insertUserSignup(UserDto userDto);
|
||||
|
||||
int insertUserTokenSignup(UserTokenDto userTokenDto);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.alist.api.modules.user.service;
|
||||
|
||||
import com.alist.api.common.utils.ApiKeyGenerator;
|
||||
import com.alist.api.modules.user.dto.UserDto;
|
||||
import com.alist.api.modules.user.dto.UserTokenDto;
|
||||
import com.alist.api.modules.user.mapper.UserMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class UserService {
|
||||
private final UserMapper userMapper;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
public UserService(UserMapper userMapper, PasswordEncoder passwordEncoder) {
|
||||
this.userMapper = userMapper;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public UserDto insertUser(UserDto userDto) {
|
||||
// 중복체크
|
||||
if (userMapper.selectDuplicateUserCount(userDto) > 0) {
|
||||
userDto.setResultCode(2004);
|
||||
return userDto;
|
||||
}
|
||||
|
||||
// 비밀번호 생성
|
||||
userDto.setNewPassword(passwordEncoder.encode(userDto.getPassword()));
|
||||
|
||||
// 회원정보 입력
|
||||
int result = userMapper.insertUserSignup(userDto);
|
||||
|
||||
if (result > 0) {
|
||||
// user_api_key 생성
|
||||
UserTokenDto userTokenDto = new UserTokenDto();
|
||||
userTokenDto.setUserIdx(userDto.getUserIdx());
|
||||
|
||||
apiKeyWithRetry(userTokenDto);
|
||||
}
|
||||
|
||||
return userDto;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public int apiKeyWithRetry(UserTokenDto userTokenDto) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
userTokenDto.setUserApiKey(ApiKeyGenerator.userApiKeyProc());
|
||||
try {
|
||||
return userMapper.insertUserTokenSignup(userTokenDto);
|
||||
} catch (DuplicateKeyException e) {
|
||||
// 충돌이면 다시 생성
|
||||
log.warn("Duplicate API key. retrying... userId={}", userTokenDto.getUserIdx());
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("API key generation failed after retries.");
|
||||
}
|
||||
}
|
||||
@@ -11,19 +11,12 @@ spring:
|
||||
minimum-idle: 1 # 최소로
|
||||
connection-timeout: 10000
|
||||
idle-timeout: 30000
|
||||
|
||||
data:
|
||||
redis:
|
||||
host: 121.160.234.222
|
||||
port: 3001
|
||||
password: 1qaz2wsx!@
|
||||
|
||||
session:
|
||||
store-type: redis
|
||||
timeout: 7200 # 2시간 (초 단위)
|
||||
redis:
|
||||
namespace: spring:session:alist
|
||||
|
||||
logging:
|
||||
config: classpath:logback-local.xml
|
||||
|
||||
@@ -33,10 +26,10 @@ jwt:
|
||||
refresh-token-validity-seconds: 2592000
|
||||
|
||||
cookie:
|
||||
secure: true # 로컬 개발 환경 (HTTP)
|
||||
domain: api-alist.pjt.kr
|
||||
secure: true # (HTTP) -> false
|
||||
domain: api-alist.pjt.kr # (HTTP) -> 비워두세요
|
||||
name: ALIST_SSO
|
||||
same-site: None
|
||||
same-site: None # (HTTP) -> Lax
|
||||
|
||||
swagger:
|
||||
login:
|
||||
|
||||
@@ -13,19 +13,12 @@ spring:
|
||||
minimum-idle: 1 # 최소로
|
||||
connection-timeout: 10000
|
||||
idle-timeout: 30000
|
||||
|
||||
data:
|
||||
redis:
|
||||
host: ${REDIS_HOST}
|
||||
port: ${REDIS_PORT}
|
||||
password: ${REDIS_PASSWORD}
|
||||
|
||||
session:
|
||||
store-type: redis
|
||||
timeout: 7200 # 2시간 (초 단위)
|
||||
redis:
|
||||
namespace: spring:session:alist
|
||||
|
||||
logging:
|
||||
config: classpath:logback-pjt.xml
|
||||
|
||||
@@ -36,7 +29,7 @@ jwt:
|
||||
|
||||
cookie:
|
||||
secure: true # 프로젝트 환경 (HTTPS)
|
||||
domain: api-alist.pjt.kr # sso 인증시 주석해제
|
||||
domain: api-alist.pjt.kr
|
||||
name: ALIST_SSO
|
||||
same-site: None
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
||||
<mapper namespace="com.alist.api.modules.user.mapper.UserMapper">
|
||||
<insert id="insertUserSignup" useGeneratedKeys="true" keyProperty="userIdx">
|
||||
/*UserMapper.insertUserSignup*/
|
||||
insert into ALISTLMS.test_user (id, password, del_yn, create_at, update_at)
|
||||
value (#{id}, #{newPassword}, 1, now(), now())
|
||||
</insert>
|
||||
<insert id="insertUserTokenSignup" useGeneratedKeys="true" keyProperty="userTokenIdx">
|
||||
/*UserMapper.insertUserTokenSignup*/
|
||||
insert into ALISTLMS.test_user_token (user_idx, user_api_key, user_role, created_at, updated_at)
|
||||
value (#{userIdx}, #{userApiKey}, 'user', now(), now())
|
||||
</insert>
|
||||
|
||||
<select id="selectDuplicateUserCount" resultType="int">
|
||||
/*UserMapper.selectDuplicateUserCount*/
|
||||
select count(*)
|
||||
from ALISTLMS.test_user
|
||||
where id = #{id}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
||||
<mapper namespace="com.alist.api.modules.auth.mapper.CorsMapper">
|
||||
<select id="selectCorsAllowedList" resultType="com.alist.api.modules.auth.vo.CorsOriginVo">
|
||||
/* CorsMapper.selectCorsAllowedList */
|
||||
SELECT allowed_origin
|
||||
FROM ALISTLMS.test_cors_allowed_list
|
||||
WHERE del_yn = 1
|
||||
ORDER BY cors_idx
|
||||
</select>
|
||||
</mapper>
|
||||
+20
-20
@@ -1,65 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
||||
<mapper namespace="com.alist.api.modules.auth.mapper.TestAuthMapper">
|
||||
<mapper namespace="com.alist.api.modules.auth.mapper.AuthMapper">
|
||||
<update id="updateRefreshToken">
|
||||
/*TestLoginMapper.selectTestLogin*/
|
||||
update test_user_token
|
||||
/*LoginMapper.updateRefreshToken*/
|
||||
update ALISTLMS.test_user_token
|
||||
set refresh_token = #{refreshToken}
|
||||
, expires_at = #{expiresAt}
|
||||
, updated_at = now()
|
||||
where user_token_idx = #{userTokenIdx}
|
||||
</update>
|
||||
|
||||
<select id="selectTestLogin" resultType="com.alist.api.modules.auth.vo.TestLoginVo">
|
||||
/*TestLoginMapper.selectTestLogin*/
|
||||
<select id="selectLogin" resultType="com.alist.api.modules.auth.vo.LoginVo">
|
||||
/*LoginMapper.selectLogin*/
|
||||
select user_idx
|
||||
, id
|
||||
, password
|
||||
from test_user
|
||||
from ALISTLMS.test_user
|
||||
where id = #{id}
|
||||
and del_yn = 1
|
||||
</select>
|
||||
|
||||
<select id="selectTestUserTokenByUserId" resultType="com.alist.api.modules.auth.vo.TestLoginTokenVo">
|
||||
/*TestLoginMapper.selectUserTokenByUserId*/
|
||||
<select id="selectUserTokenByUserId" resultType="com.alist.api.modules.auth.vo.LoginTokenVo">
|
||||
/*LoginMapper.selectUserTokenByUserId*/
|
||||
select user_token_idx
|
||||
, user_role
|
||||
, refresh_token
|
||||
from test_user_token
|
||||
from ALISTLMS.test_user_token
|
||||
where user_idx = #{userIdx}
|
||||
</select>
|
||||
|
||||
<select id="selectTestUserTokenByUserApiKey" resultType="com.alist.api.modules.auth.vo.TestLoginTokenVo">
|
||||
/*TestLoginMapper.selectTestUserTokenByUserApiKey*/
|
||||
<select id="selectUserTokenByUserApiKey" resultType="com.alist.api.modules.auth.vo.LoginTokenVo">
|
||||
/*LoginMapper.selectUserTokenByUserApiKey*/
|
||||
select user_token_idx
|
||||
, user_role
|
||||
, refresh_token
|
||||
from test_user_token
|
||||
from ALISTLMS.test_user_token
|
||||
where user_api_key = #{userApiKey}
|
||||
</select>
|
||||
|
||||
<select id="selectTestUserTokenByUserTokenIdx" resultType="com.alist.api.modules.auth.vo.TestLoginTokenVo">
|
||||
/*TestLoginMapper.selectTestUserTokenByUserTokenIdx*/
|
||||
<select id="selectUserTokenByUserTokenIdx" resultType="com.alist.api.modules.auth.vo.LoginTokenVo">
|
||||
/*LoginMapper.selectUserTokenByUserTokenIdx*/
|
||||
select user_token_idx
|
||||
, user_role
|
||||
, refresh_token
|
||||
from test_user_token
|
||||
from ALISTLMS.test_user_token
|
||||
where user_token_idx = #{userTokenIdx}
|
||||
</select>
|
||||
|
||||
<update id="clearRefreshTokenByUserTokenIdx">
|
||||
/*TestLoginMapper.clearRefreshTokenByUserTokenIdx*/
|
||||
update test_user_token
|
||||
/*LoginMapper.clearRefreshTokenByUserTokenIdx*/
|
||||
update ALISTLMS.test_user_token
|
||||
set refresh_token = null
|
||||
, expires_at = null
|
||||
, updated_at = now()
|
||||
where user_token_idx = #{userTokenIdx}
|
||||
</update>
|
||||
|
||||
<update id="updateTestLoginByLastAt">
|
||||
/*TestLoginMapper.updateTestLoginByLastAt*/
|
||||
update test_user
|
||||
<update id="updateLoginByLastAt">
|
||||
/*LoginMapper.updateLoginByLastAt*/
|
||||
update ALISTLMS.test_user
|
||||
set last_login_at = now()
|
||||
, update_at = now()
|
||||
where user_idx = #{userIdx}
|
||||
@@ -10,7 +10,7 @@
|
||||
, REDIRECT_URI
|
||||
, MEMO
|
||||
, USE_YN
|
||||
FROM SSO_CLIENT
|
||||
FROM ALISTLMS.SSO_CLIENT
|
||||
WHERE CLIENT_ID = #{clientId}
|
||||
AND USE_YN = 'Y'
|
||||
LIMIT 1
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
||||
<mapper namespace="com.alist.api.modules.auth.mapper.TestCorsMapper">
|
||||
<select id="selectTestCorsAllowedList" resultType="com.alist.api.modules.auth.vo.TestCorsOriginVo">
|
||||
/* TestCorsMapper.selectTestCorsAllowedList */
|
||||
SELECT allowed_origin
|
||||
FROM test_cors_allowed_list
|
||||
WHERE del_yn = 1
|
||||
ORDER BY cors_idx
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
||||
<mapper namespace="com.alist.api.modules.testUser.mapper.TestUserMapper">
|
||||
<insert id="insertTestUserSignup" useGeneratedKeys="true" keyProperty="userIdx">
|
||||
/*UserSignupMapper.insertTestUserSignup*/
|
||||
insert into test_user (id, password, del_yn, create_at, update_at)
|
||||
value (#{id}, #{newPassword}, 1, now(), now())
|
||||
</insert>
|
||||
<insert id="insertTestUserTokenSignup" useGeneratedKeys="true" keyProperty="userTokenIdx">
|
||||
/*UserSignupMapper.insertTestUserTokenSignup*/
|
||||
insert into test_user_token (user_idx, user_api_key, user_role, created_at, updated_at)
|
||||
value (#{userIdx}, #{userApiKey}, 'user', now(), now())
|
||||
</insert>
|
||||
|
||||
<select id="selectDuplicateTestUserCount" resultType="int">
|
||||
/*UserSignupMapper.selectDuplicateTestUserCount*/
|
||||
select count(*)
|
||||
from test_user
|
||||
where id = #{id}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user