로그인 개발하고 싶다면 interceptor
를 꼭 사용하게 된다.
spring boot는 interceptor, next.js는 middleware가 있다.
우리는 비밀번호를 인코딩해서 저장해야 하기 때문에 spring security도 필요하고, 그냥 db 조회하면 db가 뻑 가기 때문에 캐싱과 성능을 위해 redis도 필요하다.
여기에 필요한 설정들 잊지 말고 기억하자!
프로젝트당 1개의 middleware.ts
파일을 선언할 수 있으며, 서버 컴포넌트다.
미들웨어가 등록되기를 원하는 경로만을 지정한다.
export const config = {
matcher: [
// '/chat/:path*',
"/my-page/:path*",
"/user/sign-in",
"/user/sign-up",
// '/test/:path*',
],
};
/next/headers
로 쿠키 관련 메서드를 사용할 수 있다.
request.nextUrl.pathname
request.nextUrl.clone()
을 사용하면 현재 경로를 객체로 받을 수 있다. (pathname도 여기 포함)서버 컴포넌트는 url이 절대경로여야 한다.
.env.development
등에서 등록한 도메인 url 붙여서 호출해야 한다.new URL()
로 request.url
과 함께 감싸주어야 한다.middleware.ts
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
import { cookies } from "next/headers";
export async function middleware(request: NextRequest) {
const cookieStore = cookies();
const userSession = cookieStore.get("userSession");
const currentPath = request.nextUrl.pathname;
if (userSession === undefined || !userSession?.value) {
if (currentPath === "/user/sign-in" || currentPath === "/user/sign-up") {
// 로그인을 안 했는데 로그인/회원가입으로 오면 그냥 통과
return NextResponse.next();
}
// 그외 전부 로그인 페이지로 이동
return NextResponse.redirect(new URL("/user/sign-in", request.url));
} else {
// 로그인을 했는데 로그인/회원가입으로 오면 메인(promotion)으로 보내기
if (currentPath === "/user/sign-in" || currentPath === "/user/sign-up") {
return NextResponse.redirect(new URL("/promotion", request.url));
}
}
return NextResponse.next();
}
export const config = {
matcher: [
"/my-page/:path*",
"/user/sign-in",
"/user/sign-up",
],
};
spring boot에서도 특정 경로 요청이 도달하기 전에 체크를 하고 싶다면 인터셉터를 추가한다.
WebConfig의 일부
context-path
가 /api
경로여도 /api
경로를 제외하고 controller 경로 기준으로 등록한다.
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthenticationInterceptor())
.addPathPatterns("/user/**", "/mypage/**", "/chat/**");
}
존재하지 않는 api에 대해서는 인터셉터가 핸들링하지 않으니 GlobalControllerAdvice
에서 별도 404 예외처리를 해둬야 한다.
/**
* 404 예외 처리
*/
@ExceptionHandler({NoHandlerFoundException.class})
public ResponseEntity<ErrorResponse> handleException(NoHandlerFoundException e, WebRequest req) {
ErrorResponse response = new ErrorResponse(ErrorCode.NOT_FOUND, req);
return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR);
}
build.gradle
implementation 'org.springframework.boot:spring-boot-starter-security:3.4.1'
의존성과 config에 passwordEncoder 빈을 등록한다.
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
시큐리티 의존성을 추가하면 무조건 기본 시큐리티 로그인 페이지로 이동하는데 이것을 꺼줘야 한다. exclude
속성에 SecurityAutoConfiguration
클래스를 추가한다.
Application
@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
@EnableMongoAuditing
@MapperScan("com.jinvicky.website.mapper") // Mapper가 위치한 패키지 경로
public class KtalkReviewApplication {
public static void main(String[] args) {
SpringApplication.run(KtalkReviewApplication.class, args);
}
}
jinvicky
Front-End, Back-End Developer / SD Illustrator
✉️ Email: jinvicky@naver.com
💻 Github: https://github.com/jinvicky
🍏 Blog: https://velog.io/@jinvicky/posts
🌟 Website: https://jinvicky.shop