refactor: enhance session management and routing in middleware and API authentication
This commit is contained in:
parent
5048fe1c08
commit
05f4fe4e94
@ -12,10 +12,10 @@ const nextConfig: NextConfig = {
|
|||||||
source: '/api/user/login',
|
source: '/api/user/login',
|
||||||
destination: `${process.env.NEXT_PUBLIC_QSP_API_URL}/api/user/login`,
|
destination: `${process.env.NEXT_PUBLIC_QSP_API_URL}/api/user/login`,
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// source: '/api/:path*',
|
source: '/api/:path*',
|
||||||
// destination: `${process.env.NEXT_PUBLIC_API_URL}/api/:path*`,
|
destination: `${process.env.NEXT_PUBLIC_API_URL}/api/:path*`,
|
||||||
// },
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import Header from '@/components/ui/common/Header'
|
import Header from '@/components/ui/common/Header'
|
||||||
|
|
||||||
export default function page() {
|
export default async function page() {
|
||||||
return <Header name={'調査物件一覧'} />
|
return <Header name={'調査物件一覧'} />
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/app/api/auth/logout/route.ts
Normal file
15
src/app/api/auth/logout/route.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { sessionOptions } from '@/libs/session'
|
||||||
|
import { SessionData } from '@/types/Auth'
|
||||||
|
import { getIronSession } from 'iron-session'
|
||||||
|
import { cookies } from 'next/headers'
|
||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
|
||||||
|
export async function GET(request: Request) {
|
||||||
|
const cookieStore = await cookies()
|
||||||
|
const session = await getIronSession<SessionData>(cookieStore, sessionOptions)
|
||||||
|
|
||||||
|
session.destroy()
|
||||||
|
// return redirect('/login')
|
||||||
|
|
||||||
|
return NextResponse.json({ code: 200, message: 'Logout successful' })
|
||||||
|
}
|
||||||
@ -1,6 +1,12 @@
|
|||||||
import { axiosInstance } from '@/libs/axios'
|
import { cookies } from 'next/headers'
|
||||||
import { NextResponse } from 'next/server'
|
import { NextResponse } from 'next/server'
|
||||||
|
|
||||||
|
import { getIronSession } from 'iron-session'
|
||||||
|
import { axiosInstance } from '@/libs/axios'
|
||||||
|
import { sessionOptions } from '@/libs/session'
|
||||||
|
|
||||||
|
import type { SessionData } from '@/types/Auth'
|
||||||
|
|
||||||
export async function POST(request: Request) {
|
export async function POST(request: Request) {
|
||||||
const { loginId, pwd } = await request.json()
|
const { loginId, pwd } = await request.json()
|
||||||
|
|
||||||
@ -10,5 +16,43 @@ export async function POST(request: Request) {
|
|||||||
})
|
})
|
||||||
console.log('🚀 ~ result ~ result:', result)
|
console.log('🚀 ~ result ~ result:', result)
|
||||||
|
|
||||||
return NextResponse.json('ok')
|
if (result.data.result.code === 200) {
|
||||||
|
const cookieStore = await cookies()
|
||||||
|
const session = await getIronSession<SessionData>(cookieStore, sessionOptions)
|
||||||
|
|
||||||
|
console.log('start session edit!')
|
||||||
|
session.langCd = result.data.data.langCd
|
||||||
|
session.currPage = result.data.data.currPage
|
||||||
|
session.rowCount = result.data.data.rowCount
|
||||||
|
session.startRow = result.data.data.startRow
|
||||||
|
session.endRow = result.data.data.endRow
|
||||||
|
session.compCd = result.data.data.compCd
|
||||||
|
session.agencyStoreId = result.data.data.agencyStoreId
|
||||||
|
session.storeId = result.data.data.storeId
|
||||||
|
session.userId = result.data.data.userId
|
||||||
|
session.category = result.data.data.category
|
||||||
|
session.userNm = result.data.data.userNm
|
||||||
|
session.userNmKana = result.data.data.userNmKana
|
||||||
|
session.telNo = result.data.data.telNo
|
||||||
|
session.fax = result.data.data.fax
|
||||||
|
session.email = result.data.data.email
|
||||||
|
session.lastEditUser = result.data.data.lastEditUser
|
||||||
|
session.storeGubun = result.data.data.storeGubun
|
||||||
|
session.pwCurr = result.data.data.pwCurr
|
||||||
|
session.pwdInitYn = result.data.data.pwdInitYn
|
||||||
|
session.apprStatCd = result.data.data.apprStatCd
|
||||||
|
session.loginFailCnt = result.data.data.loginFailCnt
|
||||||
|
session.loginFailMinYn = result.data.data.loginFailMinYn
|
||||||
|
session.priceViewStatCd = result.data.data.priceViewStatCd
|
||||||
|
session.groupId = result.data.data.groupId
|
||||||
|
session.storeLvl = result.data.data.storeLvl
|
||||||
|
session.custCd = result.data.data.custCd
|
||||||
|
session.builderNo = result.data.data.builderNo
|
||||||
|
session.isLoggedIn = true
|
||||||
|
console.log('end session edit!')
|
||||||
|
|
||||||
|
await session.save()
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextResponse.json({ code: 200, message: 'Login is Succecss!!' })
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,14 @@
|
|||||||
import Main from '@/components/ui/Main'
|
import Main from '@/components/ui/Main'
|
||||||
|
import { sessionOptions } from '@/libs/session'
|
||||||
|
import type { SessionData } from '@/types/Auth'
|
||||||
|
import { getIronSession } from 'iron-session'
|
||||||
|
import { cookies } from 'next/headers'
|
||||||
|
|
||||||
export default async function Home() {
|
export default async function Home() {
|
||||||
|
const cookieStore = await cookies()
|
||||||
|
const session = await getIronSession<SessionData>(cookieStore, sessionOptions)
|
||||||
|
console.log('🚀 ~ Home ~ session:', session)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="container">
|
<div className="container">
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { axiosInstance } from '@/libs/axios'
|
import { useReducer, useState } from 'react'
|
||||||
|
import { useRouter } from 'next/navigation'
|
||||||
import { useQuery } from '@tanstack/react-query'
|
import { useQuery } from '@tanstack/react-query'
|
||||||
import { useEffect, useReducer, useState } from 'react'
|
import { axiosInstance } from '@/libs/axios'
|
||||||
import { AxiosResponse } from 'axios'
|
|
||||||
|
|
||||||
interface AccountState {
|
interface AccountState {
|
||||||
loginId: string
|
loginId: string
|
||||||
@ -11,6 +11,7 @@ interface AccountState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function Login() {
|
export default function Login() {
|
||||||
|
const router = useRouter()
|
||||||
//비밀번호 보이기 숨기기
|
//비밀번호 보이기 숨기기
|
||||||
const [pwShow, setPwShow] = useState(false)
|
const [pwShow, setPwShow] = useState(false)
|
||||||
//ID 저장 체크박스
|
//ID 저장 체크박스
|
||||||
@ -26,31 +27,31 @@ export default function Login() {
|
|||||||
pwd: '',
|
pwd: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
interface LoginData {
|
||||||
|
code: number
|
||||||
|
message: string | null
|
||||||
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: loginData,
|
data: loginData,
|
||||||
isPending,
|
isPending,
|
||||||
error,
|
error,
|
||||||
} = useQuery<AxiosResponse, Error>({
|
} = useQuery<LoginData, Error>({
|
||||||
queryKey: ['login', 'account'],
|
queryKey: ['login', 'account'],
|
||||||
queryFn: () => {
|
queryFn: async () => {
|
||||||
const result = axiosInstance('').post(`/api/auth`, {
|
const { data } = await axiosInstance('').post<LoginData>(`/api/auth`, {
|
||||||
loginId: account.loginId,
|
loginId: account.loginId,
|
||||||
pwd: account.pwd,
|
pwd: account.pwd,
|
||||||
})
|
})
|
||||||
return result
|
router.push('/')
|
||||||
|
|
||||||
|
return data
|
||||||
},
|
},
|
||||||
enabled: isLogin,
|
enabled: isLogin,
|
||||||
staleTime: 0,
|
staleTime: 0,
|
||||||
retry: false,
|
retry: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (loginData) {
|
|
||||||
console.log('🚀 ~ Login ~ loginData:', loginData)
|
|
||||||
setIsLogin(false)
|
|
||||||
}
|
|
||||||
}, [loginData])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="login-form-wrap">
|
<div className="login-form-wrap">
|
||||||
|
|||||||
@ -1,16 +1,27 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useHeaderStore } from '@/store/header'
|
import { useHeaderStore } from '@/store/header'
|
||||||
import { useRouter } from 'next/navigation'
|
import { useSideNavState } from '@/store/sideNavState'
|
||||||
|
import { usePathname, useRouter } from 'next/navigation'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
export default function Main() {
|
export default function Main() {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const pathname = usePathname()
|
||||||
const { setBackBtn } = useHeaderStore()
|
const { setBackBtn } = useHeaderStore()
|
||||||
|
const { reset } = useSideNavState()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 헤더 뒤로가기 버튼 컨트롤
|
||||||
|
* 사이드바 초기화 컨트롤
|
||||||
|
*/
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (pathname === '/') {
|
||||||
setBackBtn(false)
|
setBackBtn(false)
|
||||||
}, [])
|
}
|
||||||
|
//사이드바 초기화
|
||||||
|
reset()
|
||||||
|
}, [pathname])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@ -1,16 +1,17 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useEffect, useState } from 'react'
|
|
||||||
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { usePathname, useRouter } from 'next/navigation'
|
import { usePathname, useRouter } from 'next/navigation'
|
||||||
|
|
||||||
import { Swiper, SwiperSlide } from 'swiper/react'
|
import { Swiper, SwiperSlide } from 'swiper/react'
|
||||||
|
|
||||||
|
import { useSideNavState } from '@/store/sideNavState'
|
||||||
|
import { useHeaderStore } from '@/store/header'
|
||||||
|
|
||||||
import type { HeaderProps } from '@/types/Header'
|
import type { HeaderProps } from '@/types/Header'
|
||||||
|
|
||||||
import 'swiper/css'
|
import 'swiper/css'
|
||||||
import { useSideNavState } from '@/store/sideNavState'
|
import { axiosInstance } from '@/libs/axios'
|
||||||
|
|
||||||
// type HeaderProps = {
|
// type HeaderProps = {
|
||||||
// name: string //header 이름
|
// name: string //header 이름
|
||||||
@ -20,27 +21,26 @@ import { useSideNavState } from '@/store/sideNavState'
|
|||||||
export default function Header({ name }: HeaderProps) {
|
export default function Header({ name }: HeaderProps) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const pathname = usePathname()
|
const pathname = usePathname()
|
||||||
const { sideNavIsOpen, setSideNavIsOpen, reset } = useSideNavState()
|
const { sideNavIsOpen, setSideNavIsOpen } = useSideNavState()
|
||||||
const [isShowBackBtn, setIsShowBackBtn] = useState<boolean>(false)
|
const { backBtn } = useHeaderStore()
|
||||||
|
|
||||||
if (pathname === '/login') {
|
if (pathname === '/login') {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
const handleLogout = async () => {
|
||||||
if (pathname !== '/') {
|
const { data } = await axiosInstance(null).get('/api/auth/logout')
|
||||||
setIsShowBackBtn(true)
|
if (data.code === 200) {
|
||||||
|
router.push('/login')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//사이드바 초기화
|
|
||||||
reset()
|
|
||||||
}, [pathname])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="header-warp">
|
<div className="header-warp">
|
||||||
<header>
|
<header>
|
||||||
<div className="header-inner">
|
<div className="header-inner">
|
||||||
{isShowBackBtn && (
|
{backBtn && (
|
||||||
<div className="back-button-wrap">
|
<div className="back-button-wrap">
|
||||||
<button className="back-button" onClick={() => router.back()}></button>
|
<button className="back-button" onClick={() => router.back()}></button>
|
||||||
</div>
|
</div>
|
||||||
@ -112,7 +112,9 @@ export default function Header({ name }: HeaderProps) {
|
|||||||
<div className="side-nav-footer">
|
<div className="side-nav-footer">
|
||||||
<ul className="side-footer-list">
|
<ul className="side-footer-list">
|
||||||
<li className="side-footer-item">
|
<li className="side-footer-item">
|
||||||
<button className="bold">LOGOUT</button>
|
<button className="bold" onClick={handleLogout}>
|
||||||
|
LOGOUT
|
||||||
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li className="side-footer-item">
|
<li className="side-footer-item">
|
||||||
<button>Jynoadmin</button>
|
<button>Jynoadmin</button>
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
export const axiosInstance = (url: string) => {
|
export const axiosInstance = (url: string | null | undefined) => {
|
||||||
let baseURL = url !== '' || url === undefined ? url : process.env.NEXT_PUBLIC_API_URL
|
const baseURL = url || process.env.NEXT_PUBLIC_API_URL
|
||||||
|
|
||||||
return axios.create({
|
return axios.create({
|
||||||
baseURL,
|
baseURL,
|
||||||
headers: {
|
headers: {
|
||||||
@ -22,7 +23,7 @@ axios.interceptors.request.use(
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Response interceptor
|
// Response interceptor
|
||||||
axiosInstance.interceptors.response.use(
|
axios.interceptors.response.use(
|
||||||
(response) => transferResponse(response),
|
(response) => transferResponse(response),
|
||||||
(error) => {
|
(error) => {
|
||||||
// 에러 처리 로직
|
// 에러 처리 로직
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
|
import type { SessionData } from '@/types/Auth'
|
||||||
import { getIronSession, SessionOptions } from 'iron-session'
|
import { getIronSession, SessionOptions } from 'iron-session'
|
||||||
import { cookies } from 'next/headers'
|
import { cookies } from 'next/headers'
|
||||||
|
import { redirect } from 'next/navigation'
|
||||||
|
|
||||||
export const sessionOptions: SessionOptions = {
|
export const sessionOptions: SessionOptions = {
|
||||||
cookieName: 'onsitesurvey_session',
|
cookieName: 'onsitesurvey_session',
|
||||||
@ -14,15 +16,34 @@ export const sessionOptions: SessionOptions = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SessionData {
|
|
||||||
username: string | null
|
|
||||||
email: string | null
|
|
||||||
isLoggedIn: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export const defaultSession: SessionData = {
|
export const defaultSession: SessionData = {
|
||||||
username: '',
|
langCd: null,
|
||||||
email: '',
|
currPage: 0,
|
||||||
|
rowCount: 0,
|
||||||
|
startRow: 0,
|
||||||
|
endRow: 0,
|
||||||
|
compCd: null,
|
||||||
|
agencyStoreId: null,
|
||||||
|
storeId: null,
|
||||||
|
userId: null,
|
||||||
|
category: null,
|
||||||
|
userNm: null,
|
||||||
|
userNmKana: null,
|
||||||
|
telNo: null,
|
||||||
|
fax: null,
|
||||||
|
email: null,
|
||||||
|
lastEditUser: null,
|
||||||
|
storeGubun: null,
|
||||||
|
pwCurr: null,
|
||||||
|
pwdInitYn: null,
|
||||||
|
apprStatCd: null,
|
||||||
|
loginFailCnt: null,
|
||||||
|
loginFailMinYn: null,
|
||||||
|
priceViewStatCd: null,
|
||||||
|
groupId: null,
|
||||||
|
storeLvl: null,
|
||||||
|
custCd: null,
|
||||||
|
builderNo: null,
|
||||||
isLoggedIn: false,
|
isLoggedIn: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,3 +52,11 @@ export const getSession = async () => {
|
|||||||
const session = await getIronSession<SessionData>(cookieStore, sessionOptions)
|
const session = await getIronSession<SessionData>(cookieStore, sessionOptions)
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const logout = async () => {
|
||||||
|
const cookieStore = await cookies()
|
||||||
|
const session = await getIronSession<SessionData>(cookieStore, sessionOptions)
|
||||||
|
|
||||||
|
session.destroy()
|
||||||
|
return redirect('/login')
|
||||||
|
}
|
||||||
|
|||||||
@ -2,16 +2,17 @@ import { NextResponse } from 'next/server'
|
|||||||
import { cookies } from 'next/headers'
|
import { cookies } from 'next/headers'
|
||||||
import type { NextRequest } from 'next/server'
|
import type { NextRequest } from 'next/server'
|
||||||
import { getIronSession } from 'iron-session'
|
import { getIronSession } from 'iron-session'
|
||||||
import { SessionData, sessionOptions } from './libs/session'
|
import { sessionOptions } from './libs/session'
|
||||||
|
import type { SessionData } from './types/Auth'
|
||||||
|
|
||||||
export async function middleware(request: NextRequest) {
|
export async function middleware(request: NextRequest) {
|
||||||
const cookieStore = await cookies()
|
const cookieStore = await cookies()
|
||||||
const session = await getIronSession<SessionData>(cookieStore, sessionOptions)
|
const session = await getIronSession<SessionData>(cookieStore, sessionOptions)
|
||||||
|
|
||||||
// todo: 로그인 기능 추가 시 주석 해제
|
// todo: 로그인 기능 추가 시 주석 해제
|
||||||
// if (!session.isLoggedIn) {
|
if (!session.isLoggedIn) {
|
||||||
// return NextResponse.redirect(new URL('/login', request.url))
|
return NextResponse.redirect(new URL('/login', request.url))
|
||||||
// }
|
}
|
||||||
|
|
||||||
return NextResponse.next()
|
return NextResponse.next()
|
||||||
}
|
}
|
||||||
|
|||||||
30
src/types/Auth.ts
Normal file
30
src/types/Auth.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
export interface SessionData {
|
||||||
|
langCd: null
|
||||||
|
currPage: Number | null
|
||||||
|
rowCount: Number | null
|
||||||
|
startRow: Number | null
|
||||||
|
endRow: Number | null
|
||||||
|
compCd: null
|
||||||
|
agencyStoreId: null
|
||||||
|
storeId: null
|
||||||
|
userId: null
|
||||||
|
category: null
|
||||||
|
userNm: null
|
||||||
|
userNmKana: null
|
||||||
|
telNo: null
|
||||||
|
fax: null
|
||||||
|
email: null
|
||||||
|
lastEditUser: null
|
||||||
|
storeGubun: null
|
||||||
|
pwCurr: null
|
||||||
|
pwdInitYn: null
|
||||||
|
apprStatCd: null
|
||||||
|
loginFailCnt: Number | null
|
||||||
|
loginFailMinYn: null
|
||||||
|
priceViewStatCd: null
|
||||||
|
groupId: null
|
||||||
|
storeLvl: null
|
||||||
|
custCd: null
|
||||||
|
builderNo: null
|
||||||
|
isLoggedIn: boolean
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user