Skip to content

Commit

Permalink
feat : access 토큰 만료시 refresh 토큰으로 재발급 #26
Browse files Browse the repository at this point in the history
- access 토큰 만료시 refresh 토큰으로 db의 토큰과 일치하는지 확인후
- 새로운 access 토큰과 refresh 토큰 발급후 db에 refresh 토큰 저장
- auth에서 access 토큰을 발급하면 front에서 다시 헤더에 access토큰 default로 설정
  • Loading branch information
sheepdog13 committed Feb 9, 2024
1 parent 5e59a01 commit 55955d6
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 24 deletions.
15 changes: 8 additions & 7 deletions client/src/_reducers/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const httpClientForCredentials = axios.create({
// 서버와 클라이언트가 다른 도메인일 경우 필수
withCredentials: true,
});

const asynsLoginFetch = createAsyncThunk(
"userSlice/asynLoginFetch",
async (formdata) => {
Expand All @@ -20,7 +21,6 @@ const asynsLoginFetch = createAsyncThunk(
const asynsRegisterFetch = createAsyncThunk(
"userSlice/asynsRegisterFetch",
async (formdata) => {
console.log("formdata", formdata);
const resp = await axios.post(
"https://nodestudy-34u2.onrender.com/api/users/register",
formdata
Expand All @@ -37,12 +37,7 @@ const asynsAuth = createAsyncThunk("userSlice/asynsAuth", async () => {
export const userSlice = createSlice({
name: "user",
initialState: { value: {}, auth: {} },
reducers: {
// login: async (state, action) => {
// const req = await axios.post("/api/users/login", action.payload);
// state.value = {};
// },
},
reducers: {},
extraReducers: (builder) => {
builder.addCase(asynsLoginFetch.pending, (state, action) => {
state.status = "Loading";
Expand All @@ -63,6 +58,12 @@ export const userSlice = createSlice({
});
builder.addCase(asynsAuth.fulfilled, (state, action) => {
state.auth = action.payload;
// refresh토큰으로 재발급 받은 accesstoken 헤더에 default로 넣기
if (action.payload.accesstoken) {
httpClientForCredentials.defaults.headers.common[
"Authorization"
] = `Bearer ${action.payload.accesstoken}`;
}
});
},
});
Expand Down
8 changes: 7 additions & 1 deletion client/src/components/views/Header/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,13 @@ function Header() {
<BurSpan></BurSpan>
<BurSpan></BurSpan>
</Burger>
<Logo src={`${process.env.PUBLIC_URL}/img/logo.png`} alt="home" />
<Logo
onClick={() => {
navigate("/");
}}
src={`${process.env.PUBLIC_URL}/img/logo.png`}
alt="home"
/>
<RightBox>
<SvgIcon component={NightlightIcon} fontSize={"large"} />
{isLogin ? (
Expand Down
6 changes: 3 additions & 3 deletions client/src/components/views/LandingPage/LandingPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Header from "../Header/Header";
import styled from "styled-components";
import { useSelector } from "react-redux";

const Wapper = styled.div`
const Wrapper = styled.div`
width: 100%;
height: 100vh;
display: flex;
Expand Down Expand Up @@ -33,10 +33,10 @@ function LandingPage() {
const isLogin = useSelector((state) => state.user.auth.isAuth);

return (
<Wapper>
<Wrapper>
<Header />
{isLogin && <H1>반갑습니다 {username}님!</H1>}
</Wapper>
</Wrapper>
);
}

Expand Down
42 changes: 29 additions & 13 deletions server/middleware/auth.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,50 @@
const { User } = require("../models/User");
const jwt = require("jsonwebtoken");

// 인증 처리를 하는곳
let auth = async (req, res, next) => {
// 클라이언트에서 헤더로 보내준 accesstoken
let accesstoken = req.headers.authorization;
// 클라이언트에 저장되어있는 refreshtoken
let refreshtoken = req.cookies.refreshtoken;
// accesstoken이 있을때 조작된 jwt인지 확인후 미들웨어 종료
if (accesstoken) {
try {
const userdata = jwt.verify(accesstoken.split(" ")[1], "secretToken");
req.name = userdata.username;
next();
} catch (err) {}
} else if (refreshtoken) {
// access 토큰이 만료 됐을때
try {
// 토큰을 복호화 한후 유저를 찾는다.
const user = await User.findByToken(refreshtoken);
// 유저가 업으면 no
if (!user) return res.json({ isAuth: false, message: "user가 없습니다" });
// db의 토큰과 client에서 준 refresh토큰을 비교한다.
if (user.token === refreshtoken) {
const [userdata, accesstoken] = await user.generateToken();
// refresh 토큰의 옵션
const options = {
httpOnly: true,
sameSite: "None",
secure: true,
// 2주
maxAge: 14 * 24 * 60 * 60 * 1000,
};
// access 토큰은 body로 넘겨주고 refresh 토큰은 cookie에 저장한다.
res.cookie("refreshtoken", userdata.token, options).status(200).json({
isAuth: true,
accesstoken,
name: userdata.name,
});
}
} catch (err) {
return res.json({ isAuth: false, error: err });
}
} else {
return res.json({ isAuth: false });
}
// try {
// // 토큰을 복호화 한후 유저를 찾는다.
// const userdata = await User.findByToken(token);
// // 유저가 업으면 no
// if (!userdata) return res.json({ isAuth: false, error: true });
// // 같은 유저가 있으면 ok
// // 미들웨어가 끝나고 req에서 사용할 수 있게 데이터를 보내준다.
// req.token = token;
// req.user = userdata;
// next();
// } catch (err) {
// return res.json({ isAuth: false, error: err });
// }
};

module.exports = { auth };

0 comments on commit 55955d6

Please sign in to comment.