[SSO] 추가
This commit is contained in:
@@ -38,3 +38,5 @@ out/
|
|||||||
|
|
||||||
### Claude Code ###
|
### Claude Code ###
|
||||||
.claude/
|
.claude/
|
||||||
|
|
||||||
|
AGENTS.md
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
# CLAUDE.md - alist API 프로젝트
|
|
||||||
|
|
||||||
## Claude 작업 규칙 (중요!)
|
|
||||||
|
|
||||||
### 코드 수정 시 반드시 따를 것
|
|
||||||
1. **절대로 바로 파일을 수정하지 말 것**
|
|
||||||
2. **먼저 수정 방향과 계획을 설명**
|
|
||||||
3. **긴 소스 코드를 보여주기 전에 먼저 물어보기**
|
|
||||||
- "코드 보여드릴까요?" 또는 "직접 수정하시겠어요?"
|
|
||||||
- 사용자가 원하면 코드 보여주기 (사용자가 직접 수정할 수도 있도록)
|
|
||||||
4. **파일 작성/수정은 사용자가 요청할 때만**
|
|
||||||
|
|
||||||
### 작업 순서 예시
|
|
||||||
```
|
|
||||||
1. "CORS 설정을 yml로 분리하겠습니다."
|
|
||||||
2. "수정 내용:"
|
|
||||||
- CorsProperties.java 생성 필요
|
|
||||||
- CorsConfig.java 수정 필요
|
|
||||||
- application-local.yaml 수정 필요
|
|
||||||
3. "코드 보여드릴까요? 아니면 직접 수정하시겠어요?"
|
|
||||||
4. (사용자가 "보여줘"라고 하면) 코드 보여주기
|
|
||||||
5. (사용자가 "작성해줘"라고 하면) 파일 수정 진행
|
|
||||||
```
|
|
||||||
|
|
||||||
### 주의사항
|
|
||||||
- **짧은 설명(수정 위치, 수정 방향)은 바로 보여줘도 됨**
|
|
||||||
- **전체 메서드/클래스 같은 긴 코드는 반드시 물어본 후 보여주기**
|
|
||||||
- **화면이 너무 길어지는 것 방지**
|
|
||||||
|
|
||||||
## 프로젝트 개요
|
|
||||||
- **프로젝트명**: alist API
|
|
||||||
- **그룹**: com.alist
|
|
||||||
- **포트**: 8106
|
|
||||||
- **빌드 결과물**: `api.jar`
|
|
||||||
|
|
||||||
## 기술 스택
|
|
||||||
- **Java**: 21
|
|
||||||
- **Framework**: Spring Boot 3.5.10
|
|
||||||
- **빌드 도구**: Gradle
|
|
||||||
- **DB**: MariaDB
|
|
||||||
- **ORM**: MyBatis (mapper XML: `classpath:mapper/**/*.xml`)
|
|
||||||
- **인증**: JWT (jjwt 0.11.5) + Spring Security
|
|
||||||
- **API 문서**: Swagger (springdoc-openapi 2.6.0)
|
|
||||||
- **기타**: Lombok, Validation, Actuator, log4jdbc
|
|
||||||
|
|
||||||
## 패키지 구조
|
|
||||||
```
|
|
||||||
com.alist.api
|
|
||||||
├── common
|
|
||||||
│ ├── response/ # ApiResponse, ApiResponseCode
|
|
||||||
│ └── utils/ # 공통 유틸리티
|
|
||||||
├── config
|
|
||||||
│ ├── jwt/ # JWT 필터, 핸들러, Provider
|
|
||||||
│ ├── exception/ # GlobalExceptionHandler
|
|
||||||
│ ├── properties/ # JwtProperties 등
|
|
||||||
│ ├── SecurityConfig.java
|
|
||||||
│ └── OpenApiConfig.java
|
|
||||||
└── modules
|
|
||||||
└── {도메인}/ # Controller, Service, Mapper, DTO
|
|
||||||
```
|
|
||||||
|
|
||||||
## 프로파일
|
|
||||||
| 프로파일 | 설명 |
|
|
||||||
|---------|------|
|
|
||||||
| `local` | 로컬 개발 환경 |
|
|
||||||
| `pjt` | 프로젝트(개발) 환경 |
|
|
||||||
|
|
||||||
## 보안 구조
|
|
||||||
- **Swagger**: `/v3/api-docs/**`, `/swagger-ui/**` → HTTP Basic 인증 (InMemory)
|
|
||||||
- **API**: JWT Bearer 토큰 인증 (Stateless)
|
|
||||||
- **공개 경로**: `/`, `/actuator/health`, `/auth/**`, `/api/user/signup`
|
|
||||||
|
|
||||||
## 응답 코드 규칙
|
|
||||||
|
|
||||||
`ApiResponseCode` enum으로 관리. 주요 코드:
|
|
||||||
|
|
||||||
| 코드 | 메시지 | HTTP Status | 용도 |
|
|
||||||
|------|--------|-------------|------|
|
|
||||||
| `CODE_200` | 성공 | 200 OK | 일반 성공 |
|
|
||||||
| `CODE_400` | 잘못된 요청 | 400 Bad Request | 일반 클라이언트 오류 |
|
|
||||||
| `CODE_401` | 인증 필요 합니다. | 401 Unauthorized | 인증 없음 |
|
|
||||||
| `CODE_403` | 접근 권한 필요 합니다. | 403 Forbidden | 권한 없음 |
|
|
||||||
| `CODE_404` | 페이지를 찾을 수 없습니다. | 404 Not Found | 리소스 없음 |
|
|
||||||
| `CODE_405` | 잘못된 요청입니다. 요청 방식을 확인해 주세요. | 405 Method Not Allowed | 메서드 불일치 |
|
|
||||||
| `CODE_500` | 요청을 처리하는 중 오류가 발생했습니다. | 500 Internal Server Error | 서버 오류 |
|
|
||||||
| `CODE_2001` | {0} 정보 조회에 성공하였습니다. | 200 OK | 단건 조회 성공 |
|
|
||||||
| `CODE_2002` | {0} 등록 되었습니다. | 201 Created | 등록 성공 |
|
|
||||||
| `CODE_2003` | 조회된 정보가 없습니다. | 200 OK | 조회 결과 없음 |
|
|
||||||
| `CODE_2004` | 중복된 {0} 정보 입니다. | 409 Conflict | 중복 데이터 |
|
|
||||||
| `CODE_4001` | 입력값을 확인해주세요. | 400 Bad Request | `@Valid` / 바인딩 / 타입오류 / JSON 파싱 실패 |
|
|
||||||
| `CODE_4003` | 필수 요청 파라미터가 누락되었습니다. | 400 Bad Request | 필수 파라미터 누락 |
|
|
||||||
|
|
||||||
- `{0}` 자리에 대상명 삽입 (예: `CODE_2001` → "회원 정보 조회에 성공하였습니다.")
|
|
||||||
|
|
||||||
## 빌드 및 실행
|
|
||||||
```bash
|
|
||||||
# 빌드
|
|
||||||
./gradlew bootJar
|
|
||||||
|
|
||||||
# 로컬 실행
|
|
||||||
./gradlew bootRun --args='--spring.profiles.active=local'
|
|
||||||
|
|
||||||
# JAR 실행
|
|
||||||
java -jar build/libs/api.jar --spring.profiles.active=local
|
|
||||||
```
|
|
||||||
|
|
||||||
## Swagger 접속
|
|
||||||
- URL: `http://localhost:8106/swagger-ui.html`
|
|
||||||
- 인증: `swagger.login.id` / `swagger.login.password` (환경별 yaml에 설정)
|
|
||||||
|
|
||||||
## 코드 작성 규칙
|
|
||||||
- 응답은 `ApiResponse<T>` 래퍼 사용
|
|
||||||
- 응답 코드는 `ApiResponseCode` enum 사용
|
|
||||||
- MyBatis Mapper XML은 `src/main/resources/mapper/` 하위에 작성
|
|
||||||
- 카멜케이스 자동 변환 활성화 (`map-underscore-to-camel-case: true`)
|
|
||||||
- 새 모듈 추가 시: `modules/{moduleName}/` 하위에 Controller, Service, Mapper, dto/, vo/ 구조로 생성
|
|
||||||
- Mapper XML은 `resources/mapper/{moduleName}/` 에 위치
|
|
||||||
|
|
||||||
## MyBatis 규칙
|
|
||||||
- Mapper XML 위치: `src/main/resources/mapper/**/*.xml`
|
|
||||||
- `map-underscore-to-camel-case: true` 설정 → DB 컬럼 `user_idx` → Java 필드 `userIdx` 자동 매핑
|
|
||||||
- Mapper 인터페이스와 XML의 namespace, id 반드시 일치시킬 것
|
|
||||||
- VO: DB 조회 결과 매핑용 / DTO: 서비스 레이어 간 데이터 전달용 / Form: 컨트롤러 입력 검증용
|
|
||||||
|
|
||||||
## CI/CD
|
|
||||||
- **Jenkins**: `Jenkinsfile.pjt`
|
|
||||||
- **Docker**: `Dockerfile`
|
|
||||||
- **배포 스크립트**: `deploy/` 디렉토리
|
|
||||||
|
|
||||||
## 개발 서버 (pjt)
|
|
||||||
|
|
||||||
### 도메인
|
|
||||||
- **API**: `api-alist.pjt.kr`
|
|
||||||
- **파일(업로드)**: `file-alist.pjt.kr`
|
|
||||||
- **Swagger**: `https://api-alist.pjt.kr/swagger-ui/index.html`
|
|
||||||
|
|
||||||
### Docker
|
|
||||||
- **레지스트리**: `registry.pjt.kr`
|
|
||||||
- **이미지**: `registry.pjt.kr/alist/api`
|
|
||||||
- **컨테이너명**: `alist-api`
|
|
||||||
- **포트**: `127.0.0.1:8106->8106/tcp`
|
|
||||||
|
|
||||||
### 서버 디렉토리 (`/srv/project/alist/`)
|
|
||||||
```
|
|
||||||
/srv/project/alist/
|
|
||||||
├── compose/ # docker-compose 파일
|
|
||||||
├── data/ # 데이터
|
|
||||||
├── env/ # 환경변수 파일
|
|
||||||
├── logs/ # 로그
|
|
||||||
├── scripts/ # 배포/운영 스크립트
|
|
||||||
└── uploads/ # 업로드 파일 (file-alist.pjt.kr 루트)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Nginx
|
|
||||||
- `file-alist.pjt.kr` → `/srv/project/alist/uploads` (정적 파일 서빙)
|
|
||||||
- HTTP(80) → HTTPS(301) 리다이렉트
|
|
||||||
- SSL: Let's Encrypt
|
|
||||||
- 직접 접근 차단 (`allow 127.0.0.1; deny all;`)
|
|
||||||
|
|
||||||
### 파일 업로드
|
|
||||||
- 업로드 저장 경로: `/srv/project/alist/uploads/`
|
|
||||||
- 업로드 파일 접근 URL: `https://file-alist.pjt.kr/{파일경로}`
|
|
||||||
@@ -56,6 +56,10 @@ dependencies {
|
|||||||
|
|
||||||
// health
|
// health
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
||||||
|
|
||||||
|
// Redis (SSO 세션 공유)
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
|
||||||
|
implementation 'org.springframework.session:spring-session-data-redis'
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.named('test') {
|
tasks.named('test') {
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.alist.api.common.utils;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.springframework.http.ResponseCookie;
|
||||||
|
|
||||||
|
public class SessionUtil {
|
||||||
|
// 쿠키 삭제
|
||||||
|
public static void expireCookie(HttpServletResponse response, String name, String cookieDomain, boolean cookieSecure) {
|
||||||
|
ResponseCookie cookie = ResponseCookie.from(name, "")
|
||||||
|
.domain(cookieDomain)
|
||||||
|
.path("/")
|
||||||
|
.httpOnly(true)
|
||||||
|
.secure(cookieSecure)
|
||||||
|
.sameSite("Lax")
|
||||||
|
.maxAge(0)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
response.addHeader("Set-Cookie", cookie.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 쿠키 입력
|
||||||
|
public static void addTokenCookie(HttpServletResponse response, String name, String value, String cookieDomain, boolean cookieSecure, long maxAgeSeconds) {
|
||||||
|
ResponseCookie cookie = ResponseCookie.from(name, value)
|
||||||
|
.domain(cookieDomain)
|
||||||
|
.path("/")
|
||||||
|
.httpOnly(true)
|
||||||
|
.secure(cookieSecure)
|
||||||
|
.sameSite("Lax")
|
||||||
|
.maxAge(maxAgeSeconds)
|
||||||
|
.build();
|
||||||
|
response.addHeader("Set-Cookie", cookie.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
@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("Lax"); // CSRF 방지
|
||||||
|
|
||||||
|
return serializer;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -55,7 +55,7 @@ public class SecurityConfig {
|
|||||||
http
|
http
|
||||||
.cors(Customizer.withDefaults())
|
.cors(Customizer.withDefaults())
|
||||||
.csrf(csrf -> csrf.disable())
|
.csrf(csrf -> csrf.disable())
|
||||||
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
// SSO를 위해 Spring Session 사용 (sessionManagement 설정 제거하여 기본값 사용)
|
||||||
.exceptionHandling(ex -> ex
|
.exceptionHandling(ex -> ex
|
||||||
.authenticationEntryPoint(new JwtAuthenticationEntryPoint())
|
.authenticationEntryPoint(new JwtAuthenticationEntryPoint())
|
||||||
.accessDeniedHandler(new JwtAccessDeniedHandler())
|
.accessDeniedHandler(new JwtAccessDeniedHandler())
|
||||||
|
|||||||
@@ -24,9 +24,7 @@ public class DynamicCorsFilter extends OncePerRequestFilter {
|
|||||||
private final CorsAllowedOriginsCache corsCache;
|
private final CorsAllowedOriginsCache corsCache;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doFilterInternal(HttpServletRequest request,
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||||
HttpServletResponse response,
|
|
||||||
FilterChain filterChain) throws ServletException, IOException {
|
|
||||||
|
|
||||||
String origin = request.getHeader("Origin");
|
String origin = request.getHeader("Origin");
|
||||||
|
|
||||||
|
|||||||
@@ -22,11 +22,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doFilterInternal(
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||||
HttpServletRequest request,
|
|
||||||
HttpServletResponse response,
|
|
||||||
FilterChain filterChain
|
|
||||||
) throws ServletException, IOException {
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String token = resolveToken(request);
|
String token = resolveToken(request);
|
||||||
@@ -48,14 +44,28 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String resolveToken(HttpServletRequest request) {
|
private String resolveToken(HttpServletRequest request) {
|
||||||
|
// 1) Authorization: Bearer xxx 우선
|
||||||
String bearer = request.getHeader(HttpHeaders.AUTHORIZATION);
|
String bearer = request.getHeader(HttpHeaders.AUTHORIZATION);
|
||||||
if (bearer == null) return null;
|
if (bearer != null && bearer.startsWith("Bearer ")) {
|
||||||
|
|
||||||
// "Bearer " 뒤 토큰만 추출
|
|
||||||
if (bearer.startsWith("Bearer ")) {
|
|
||||||
String token = bearer.substring(7).trim();
|
String token = bearer.substring(7).trim();
|
||||||
return token.isEmpty() ? null : token;
|
if (!token.isEmpty()) {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2) 쿠키 fallback (브라우저용)
|
||||||
|
Cookie[] cookies = request.getCookies();
|
||||||
|
if (cookies != null) {
|
||||||
|
for (Cookie cookie : cookies) {
|
||||||
|
if ("accessToken".equals(cookie.getName())) {
|
||||||
|
String token = cookie.getValue();
|
||||||
|
if (token != null && !token.isBlank()) {
|
||||||
|
return token.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public class JwtTokenProvider {
|
|||||||
/* 리프레시 토큰 생성 */
|
/* 리프레시 토큰 생성 */
|
||||||
public String createRefreshToken(long userTokenIdx) {
|
public String createRefreshToken(long userTokenIdx) {
|
||||||
Instant now = Instant.now();
|
Instant now = Instant.now();
|
||||||
Instant expiry = now.plusSeconds(jwtProperties.getAccessTokenValiditySeconds());
|
Instant expiry = now.plusSeconds(jwtProperties.getRefreshTokenValiditySeconds());
|
||||||
|
|
||||||
return Jwts.builder()
|
return Jwts.builder()
|
||||||
.setSubject(String.valueOf(userTokenIdx))
|
.setSubject(String.valueOf(userTokenIdx))
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
package com.alist.api.modules.auth;
|
package com.alist.api.modules.auth;
|
||||||
|
|
||||||
|
import com.alist.api.common.utils.SessionUtil;
|
||||||
|
import com.alist.api.modules.auth.dto.TestLoginDto;
|
||||||
import com.alist.api.modules.auth.dto.TokenDto;
|
import com.alist.api.modules.auth.dto.TokenDto;
|
||||||
|
import com.alist.api.modules.auth.service.TestAuthService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import jakarta.servlet.http.HttpSession;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import com.alist.api.common.response.ApiResponse;
|
import com.alist.api.common.response.ApiResponse;
|
||||||
import com.alist.api.common.response.ApiResponseCode;
|
import com.alist.api.common.response.ApiResponseCode;
|
||||||
@@ -16,14 +20,35 @@ import com.alist.api.modules.auth.form.TokenForm;
|
|||||||
|
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Tag(name = "00. 엑세스 토큰 발급", description = "강제 엑세스 토큰 발급 (JSON 전달, 테스트용)")
|
@Tag(name = "00. 엑세스 토큰 발급", description = "강제 엑세스 토큰 발급 (JSON 전달, 테스트용)")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/auth")
|
@RequestMapping("/auth")
|
||||||
public class AuthController {
|
public class AuthController {
|
||||||
private final JwtTokenProvider jwtTokenProvider;
|
|
||||||
|
|
||||||
public AuthController(JwtTokenProvider jwtTokenProvider) {
|
@Value("${cookie.secure}")
|
||||||
|
private boolean cookieSecure;
|
||||||
|
|
||||||
|
@Value("${cookie.domain}")
|
||||||
|
private String cookieDomain;
|
||||||
|
|
||||||
|
@Value("${cookie.name}")
|
||||||
|
private String cookieName;
|
||||||
|
|
||||||
|
@Value("${jwt.access-token-validity-seconds}")
|
||||||
|
private long accessTokenValiditySeconds;
|
||||||
|
|
||||||
|
@Value("${jwt.refresh-token-validity-seconds}")
|
||||||
|
private long refreshTokenValiditySeconds;
|
||||||
|
|
||||||
|
private final JwtTokenProvider jwtTokenProvider;
|
||||||
|
private final TestAuthService testAuthService;
|
||||||
|
|
||||||
|
public AuthController(JwtTokenProvider jwtTokenProvider, TestAuthService testAuthService) {
|
||||||
this.jwtTokenProvider = jwtTokenProvider;
|
this.jwtTokenProvider = jwtTokenProvider;
|
||||||
|
this.testAuthService = testAuthService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(
|
@Operation(
|
||||||
@@ -37,4 +62,77 @@ public class AuthController {
|
|||||||
|
|
||||||
return ApiResponse.entity(tokenDto, ApiResponseCode.CODE_2001, "엑세스 토큰");
|
return ApiResponse.entity(tokenDto, ApiResponseCode.CODE_2001, "엑세스 토큰");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Operation(
|
||||||
|
summary = "리프레시 토큰으로 엑세스 토큰 재발급",
|
||||||
|
description = "리프레시 토큰으로 엑세스 토큰 재발급"
|
||||||
|
)
|
||||||
|
@PostMapping("/refresh")
|
||||||
|
public ResponseEntity<ApiResponse<Map<String, Object>>> refresh(@CookieValue(name = "refreshToken", required = false) String refreshToken, HttpServletResponse response) {
|
||||||
|
|
||||||
|
TestLoginDto testLogin = testAuthService.refreshByToken(refreshToken);
|
||||||
|
|
||||||
|
if (testLogin == null) {
|
||||||
|
return ApiResponse.entity(Map.of("refreshed", false), ApiResponseCode.CODE_401);
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionUtil.addTokenCookie(response, "accessToken", testLogin.getAccessToken(), cookieDomain, cookieSecure, accessTokenValiditySeconds);
|
||||||
|
SessionUtil.addTokenCookie(response, "refreshToken", testLogin.getRefreshToken(), cookieDomain, cookieSecure, refreshTokenValiditySeconds);
|
||||||
|
|
||||||
|
return ApiResponse.entity(Map.of("refreshed", true), ApiResponseCode.CODE_200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(
|
||||||
|
summary = "SSO 로그인 상태 확인",
|
||||||
|
description = "SSO 인증 받은 후 현재 세션이 있는지 확인"
|
||||||
|
)
|
||||||
|
@GetMapping("/loginChecked")
|
||||||
|
public ResponseEntity<ApiResponse<Map<String, Object>>> loginChecked(HttpServletRequest request) {
|
||||||
|
Map<String, Object> sessionInfo = new HashMap<>();
|
||||||
|
HttpSession session = request.getSession(false); // 새 세션 생성 금지
|
||||||
|
|
||||||
|
if (session == null) {
|
||||||
|
sessionInfo.put("loggedIn", false);
|
||||||
|
return ApiResponse.entity(sessionInfo, ApiResponseCode.CODE_200);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
SessionUtil.expireCookie(response, "accessToken", cookieDomain, cookieSecure);
|
||||||
|
SessionUtil.expireCookie(response, "refreshToken", cookieDomain, cookieSecure);
|
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
result.put("message", "로그아웃되었습니다.");
|
||||||
|
|
||||||
|
return ApiResponse.entity(result, ApiResponseCode.CODE_200);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,31 +2,37 @@ package com.alist.api.modules.auth;
|
|||||||
|
|
||||||
import com.alist.api.common.response.ApiResponse;
|
import com.alist.api.common.response.ApiResponse;
|
||||||
import com.alist.api.common.response.ApiResponseCode;
|
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.dto.TestLoginDto;
|
||||||
import com.alist.api.modules.auth.form.TestApikeyLoginForm;
|
import com.alist.api.modules.auth.form.TestApikeyLoginForm;
|
||||||
import com.alist.api.modules.auth.form.TestLoginForm;
|
import com.alist.api.modules.auth.form.TestLoginForm;
|
||||||
import com.alist.api.modules.auth.service.TestAuthService;
|
import com.alist.api.modules.auth.service.TestAuthService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.servlet.http.Cookie;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import jakarta.servlet.http.HttpSession;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
@Tag(name = "01. 테스트 인증", description = "테스트 사용자 로그인 및 API Key 인증 관련 API")
|
@Tag(name = "01. 테스트 인증", description = "테스트 사용자 로그인 및 API Key 인증 관련 API")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/test")
|
@RequestMapping("/test")
|
||||||
public class TestAuthController {
|
public class TestAuthController {
|
||||||
private final TestAuthService testAuthService;
|
private final TestAuthService testAuthService;
|
||||||
|
|
||||||
@Value("${cookie.secure}")
|
@Value("${cookie.secure}")
|
||||||
private boolean cookieSecure;
|
private boolean cookieSecure;
|
||||||
|
|
||||||
|
@Value("${cookie.domain}")
|
||||||
|
private String cookieDomain;
|
||||||
|
|
||||||
|
@Value("${jwt.access-token-validity-seconds}")
|
||||||
|
private long accessTokenValiditySeconds;
|
||||||
|
|
||||||
|
@Value("${jwt.refresh-token-validity-seconds}")
|
||||||
|
private long refreshTokenValiditySeconds;
|
||||||
|
|
||||||
public TestAuthController(TestAuthService testAuthService) {
|
public TestAuthController(TestAuthService testAuthService) {
|
||||||
this.testAuthService = testAuthService;
|
this.testAuthService = testAuthService;
|
||||||
}
|
}
|
||||||
@@ -36,30 +42,24 @@ public class TestAuthController {
|
|||||||
description = "아이디/비밀번호로 로그인하고 HttpOnly 쿠키로 토큰을 전달합니다. (웹 브라우저용)"
|
description = "아이디/비밀번호로 로그인하고 HttpOnly 쿠키로 토큰을 전달합니다. (웹 브라우저용)"
|
||||||
)
|
)
|
||||||
@PostMapping("/testLogin")
|
@PostMapping("/testLogin")
|
||||||
public ResponseEntity<ApiResponse<TestLoginDto>> testUserLogin(
|
public ResponseEntity<ApiResponse<TestLoginDto>> testUserLogin(@Valid @RequestBody TestLoginForm testLoginForm, HttpServletResponse response, HttpSession session) {
|
||||||
@Valid @RequestBody TestLoginForm testLoginForm,
|
|
||||||
HttpServletResponse response) {
|
|
||||||
TestLoginDto testLoginDto = testAuthService.selectTestLogin(testLoginForm.testLoginDto());
|
TestLoginDto testLoginDto = testAuthService.selectTestLogin(testLoginForm.testLoginDto());
|
||||||
|
|
||||||
if (testLoginDto.getResultCode() == 2003) {
|
if (testLoginDto.getResultCode() == 2003) {
|
||||||
return ApiResponse.entity(testLoginDto, ApiResponseCode.CODE_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 쿠키 설정
|
// accessToken 쿠키 설정
|
||||||
Cookie accessCookie = new Cookie("accessToken", testLoginDto.getAccessToken());
|
SessionUtil.addTokenCookie(response, "accessToken", testLoginDto.getAccessToken(), cookieDomain, cookieSecure, accessTokenValiditySeconds);
|
||||||
accessCookie.setHttpOnly(true); // JS 접근 차단 (XSS 방지)
|
|
||||||
accessCookie.setSecure(cookieSecure); // HTTPS 전송 (환경별 설정)
|
|
||||||
accessCookie.setPath("/");
|
|
||||||
accessCookie.setMaxAge(3600); // 1시간
|
|
||||||
response.addCookie(accessCookie);
|
|
||||||
|
|
||||||
// refreshToken 쿠키 설정
|
// refreshToken 쿠키 설정
|
||||||
Cookie refreshCookie = new Cookie("refreshToken", testLoginDto.getRefreshToken());
|
SessionUtil.addTokenCookie(response, "refreshToken", testLoginDto.getRefreshToken(), cookieDomain, cookieSecure, refreshTokenValiditySeconds);
|
||||||
refreshCookie.setHttpOnly(true);
|
|
||||||
refreshCookie.setSecure(cookieSecure); // HTTPS 전송 (환경별 설정)
|
|
||||||
refreshCookie.setPath("/");
|
|
||||||
refreshCookie.setMaxAge(7 * 24 * 3600); // 7일
|
|
||||||
response.addCookie(refreshCookie);
|
|
||||||
|
|
||||||
// JSON 응답에서는 토큰 제거 (쿠키로만 전달)
|
// JSON 응답에서는 토큰 제거 (쿠키로만 전달)
|
||||||
testLoginDto.setAccessToken(null);
|
testLoginDto.setAccessToken(null);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.alist.api.modules.auth.dto.TestLoginDto;
|
|||||||
import com.alist.api.modules.auth.vo.TestLoginTokenVo;
|
import com.alist.api.modules.auth.vo.TestLoginTokenVo;
|
||||||
import com.alist.api.modules.auth.vo.TestLoginVo;
|
import com.alist.api.modules.auth.vo.TestLoginVo;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface TestAuthMapper {
|
public interface TestAuthMapper {
|
||||||
@@ -14,4 +15,10 @@ public interface TestAuthMapper {
|
|||||||
TestLoginTokenVo selectTestUserTokenByUserApiKey(TestLoginDto testLoginDto);
|
TestLoginTokenVo selectTestUserTokenByUserApiKey(TestLoginDto testLoginDto);
|
||||||
|
|
||||||
void updateRefreshToken(TestLoginDto testLoginDto);
|
void updateRefreshToken(TestLoginDto testLoginDto);
|
||||||
|
|
||||||
|
TestLoginTokenVo selectTestUserTokenByUserTokenIdx(@Param("userTokenIdx") int userTokenIdx);
|
||||||
|
|
||||||
|
void clearRefreshTokenByUserTokenIdx(@Param("userTokenIdx") int userTokenIdx);
|
||||||
|
|
||||||
|
void updateTestLoginByLastAt(TestLoginDto testLoginDto);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,60 +28,106 @@ public class TestAuthService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// id login
|
// id login
|
||||||
public TestLoginDto selectTestLogin(TestLoginDto loginDto) {
|
public TestLoginDto selectTestLogin(TestLoginDto testLoginDto) {
|
||||||
TestLoginVo testLoginVo = testAuthMapper.selectTestLogin(loginDto);
|
TestLoginVo testLoginVo = testAuthMapper.selectTestLogin(testLoginDto);
|
||||||
|
|
||||||
if (testLoginVo != null) {
|
if (testLoginVo != null) {
|
||||||
if (passwordEncoder.matches(loginDto.getPassword(), testLoginVo.getPassword())) {
|
if (passwordEncoder.matches(testLoginDto.getPassword(), testLoginVo.getPassword())) {
|
||||||
|
|
||||||
loginDto.setUserIdx(testLoginVo.getUserIdx());
|
testLoginDto.setUserIdx(testLoginVo.getUserIdx());
|
||||||
|
|
||||||
TestLoginTokenVo testLoginTokenVo = testAuthMapper.selectTestUserTokenByUserId(loginDto);
|
TestLoginTokenVo testLoginTokenVo = testAuthMapper.selectTestUserTokenByUserId(testLoginDto);
|
||||||
|
|
||||||
if (testLoginTokenVo != null) {
|
if (testLoginTokenVo != null) {
|
||||||
loginDto.setAccessToken(jwtTokenProvider.createAccessToken(testLoginTokenVo.getUserTokenIdx(), testLoginTokenVo.getUserRole()));
|
testLoginDto.setAccessToken(jwtTokenProvider.createAccessToken(testLoginTokenVo.getUserTokenIdx(), testLoginTokenVo.getUserRole()));
|
||||||
loginDto.setRefreshToken(jwtTokenProvider.createRefreshToken(testLoginTokenVo.getUserTokenIdx()));
|
testLoginDto.setRefreshToken(jwtTokenProvider.createRefreshToken(testLoginTokenVo.getUserTokenIdx()));
|
||||||
|
|
||||||
loginDto.setUserTokenIdx(testLoginTokenVo.getUserTokenIdx());
|
testLoginDto.setUserTokenIdx(testLoginTokenVo.getUserTokenIdx());
|
||||||
|
|
||||||
Instant now = Instant.now();
|
Instant now = Instant.now();
|
||||||
Instant expiresAt = now.plusSeconds(jwtProperties.getRefreshTokenValiditySeconds());
|
Instant expiresAt = now.plusSeconds(jwtProperties.getRefreshTokenValiditySeconds());
|
||||||
|
|
||||||
loginDto.setExpiresAt(expiresAt);
|
testLoginDto.setExpiresAt(expiresAt);
|
||||||
|
|
||||||
testAuthMapper.updateRefreshToken(loginDto);
|
testAuthMapper.updateRefreshToken(testLoginDto);
|
||||||
|
|
||||||
loginDto.setResultCode(2001);
|
// 마지막 로그인 시간 추가
|
||||||
|
testAuthMapper.updateTestLoginByLastAt(testLoginDto);
|
||||||
|
|
||||||
|
testLoginDto.setResultCode(2001);
|
||||||
} else {
|
} else {
|
||||||
loginDto.setResultCode(2003);
|
testLoginDto.setResultCode(2003);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
loginDto.setResultCode(2003);
|
testLoginDto.setResultCode(2003);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
loginDto.setResultCode(2003);
|
testLoginDto.setResultCode(2003);
|
||||||
}
|
}
|
||||||
|
|
||||||
return loginDto;
|
return testLoginDto;
|
||||||
}
|
}
|
||||||
|
|
||||||
// api key login
|
// api key login
|
||||||
public TestLoginDto selectTestUserApiKeyLogin(TestLoginDto loginDto) {
|
public TestLoginDto selectTestUserApiKeyLogin(TestLoginDto testLoginDto) {
|
||||||
if (loginDto.getUserApiKey() != null) {
|
if (testLoginDto.getUserApiKey() != null) {
|
||||||
TestLoginTokenVo testLoginTokenVo = testAuthMapper.selectTestUserTokenByUserApiKey(loginDto);
|
TestLoginTokenVo testLoginTokenVo = testAuthMapper.selectTestUserTokenByUserApiKey(testLoginDto);
|
||||||
|
|
||||||
if (testLoginTokenVo != null) {
|
if (testLoginTokenVo != null) {
|
||||||
loginDto.setAccessToken(jwtTokenProvider.createAccessToken(testLoginTokenVo.getUserTokenIdx(), testLoginTokenVo.getUserRole()));
|
testLoginDto.setAccessToken(jwtTokenProvider.createAccessToken(testLoginTokenVo.getUserTokenIdx(), testLoginTokenVo.getUserRole()));
|
||||||
loginDto.setRefreshToken(jwtTokenProvider.createRefreshToken(testLoginTokenVo.getUserTokenIdx()));
|
testLoginDto.setRefreshToken(jwtTokenProvider.createRefreshToken(testLoginTokenVo.getUserTokenIdx()));
|
||||||
|
|
||||||
loginDto.setResultCode(2001);
|
testLoginDto.setResultCode(2001);
|
||||||
} else {
|
} else {
|
||||||
loginDto.setResultCode(2003);
|
testLoginDto.setResultCode(2003);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
loginDto.setResultCode(2003);
|
testLoginDto.setResultCode(2003);
|
||||||
}
|
}
|
||||||
|
|
||||||
return loginDto;
|
return testLoginDto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestLoginDto refreshByToken(String refreshToken) {
|
||||||
|
if (refreshToken == null || !jwtTokenProvider.validateToken(refreshToken)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int userTokenIdx;
|
||||||
|
try {
|
||||||
|
userTokenIdx = Integer.parseInt(jwtTokenProvider.getUserId(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.getUserId(refreshToken));
|
||||||
|
testAuthMapper.clearRefreshTokenByUserTokenIdx(userTokenIdx);
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,18 @@ spring:
|
|||||||
connection-timeout: 10000
|
connection-timeout: 10000
|
||||||
idle-timeout: 30000
|
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:
|
logging:
|
||||||
config: classpath:logback-local.xml
|
config: classpath:logback-local.xml
|
||||||
|
|
||||||
@@ -21,7 +33,9 @@ jwt:
|
|||||||
refresh-token-validity-seconds: 2592000
|
refresh-token-validity-seconds: 2592000
|
||||||
|
|
||||||
cookie:
|
cookie:
|
||||||
secure: false # 로컬 개발 환경 (HTTP)
|
secure: true # 로컬 개발 환경 (HTTP)
|
||||||
|
domain: pjt.kr
|
||||||
|
name: ALIST_SESSION
|
||||||
|
|
||||||
swagger:
|
swagger:
|
||||||
login:
|
login:
|
||||||
|
|||||||
@@ -14,6 +14,18 @@ spring:
|
|||||||
connection-timeout: 10000
|
connection-timeout: 10000
|
||||||
idle-timeout: 30000
|
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:
|
logging:
|
||||||
config: classpath:logback-pjt.xml
|
config: classpath:logback-pjt.xml
|
||||||
|
|
||||||
@@ -24,6 +36,8 @@ jwt:
|
|||||||
|
|
||||||
cookie:
|
cookie:
|
||||||
secure: true # 프로젝트 환경 (HTTPS)
|
secure: true # 프로젝트 환경 (HTTPS)
|
||||||
|
domain: pjt.kr
|
||||||
|
name: ALIST_SESSION
|
||||||
|
|
||||||
swagger:
|
swagger:
|
||||||
login:
|
login:
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
|
||||||
|
|
||||||
<mapper namespace="com.alist.api.modules.auth.mapper.TestCorsMapper">
|
<mapper namespace="com.alist.api.modules.auth.mapper.TestCorsMapper">
|
||||||
|
|
||||||
<select id="selectTestCorsAllowedList" resultType="com.alist.api.modules.auth.vo.TestCorsOriginVo">
|
<select id="selectTestCorsAllowedList" resultType="com.alist.api.modules.auth.vo.TestCorsOriginVo">
|
||||||
/* TestCorsMapper.selectTestCorsAllowedList */
|
/* TestCorsMapper.selectTestCorsAllowedList */
|
||||||
SELECT allowed_origin
|
SELECT allowed_origin
|
||||||
@@ -11,5 +9,4 @@
|
|||||||
WHERE del_yn = 1
|
WHERE del_yn = 1
|
||||||
ORDER BY cors_idx
|
ORDER BY cors_idx
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -1,15 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<!DOCTYPE mapper
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
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.TestAuthMapper">
|
||||||
<update id="updateRefreshToken">
|
<update id="updateRefreshToken">
|
||||||
/*TestLoginMapper.selectTestLogin*/
|
/*TestLoginMapper.selectTestLogin*/
|
||||||
update test_user_token
|
update test_user_token
|
||||||
set refresh_token = #{refreshToken}
|
set refresh_token = #{refreshToken}
|
||||||
, expires_at = #{expiresAt}
|
, expires_at = #{expiresAt}
|
||||||
, updated_at = now()
|
, updated_at = now()
|
||||||
where user_token_idx = #{userTokenIdx}
|
where user_token_idx = #{userTokenIdx}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
@@ -35,9 +33,35 @@
|
|||||||
<select id="selectTestUserTokenByUserApiKey" resultType="com.alist.api.modules.auth.vo.TestLoginTokenVo">
|
<select id="selectTestUserTokenByUserApiKey" resultType="com.alist.api.modules.auth.vo.TestLoginTokenVo">
|
||||||
/*TestLoginMapper.selectTestUserTokenByUserApiKey*/
|
/*TestLoginMapper.selectTestUserTokenByUserApiKey*/
|
||||||
select user_token_idx
|
select user_token_idx
|
||||||
, user_role
|
, user_role
|
||||||
, refresh_token
|
, refresh_token
|
||||||
from test_user_token
|
from test_user_token
|
||||||
where user_api_key = #{userApiKey}
|
where user_api_key = #{userApiKey}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectTestUserTokenByUserTokenIdx" resultType="com.alist.api.modules.auth.vo.TestLoginTokenVo">
|
||||||
|
/*TestLoginMapper.selectTestUserTokenByUserTokenIdx*/
|
||||||
|
select user_token_idx
|
||||||
|
, user_role
|
||||||
|
, refresh_token
|
||||||
|
from test_user_token
|
||||||
|
where user_token_idx = #{userTokenIdx}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<update id="clearRefreshTokenByUserTokenIdx">
|
||||||
|
/*TestLoginMapper.clearRefreshTokenByUserTokenIdx*/
|
||||||
|
update 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
|
||||||
|
set last_login_at = now()
|
||||||
|
, update_at = now()
|
||||||
|
where user_idx = #{userIdx}
|
||||||
|
</update>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<!DOCTYPE mapper
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
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">
|
<mapper namespace="com.alist.api.modules.testUser.mapper.TestUserMapper">
|
||||||
<insert id="insertTestUserSignup" useGeneratedKeys="true" keyProperty="userIdx">
|
<insert id="insertTestUserSignup" useGeneratedKeys="true" keyProperty="userIdx">
|
||||||
|
|||||||
Reference in New Issue
Block a user