Written on
·
562
0
frontend => LoginForm.js reducers/user.js, sagas/user.js config/config.js
backend => app.js, passport/index.js passport/local.js
위의 파일들이 에러가 예상되지만 backend 쪽 인증관련 에러로 보입니다.
BACK
app.js
const express = require('express');
const cors = require('cors');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const passport = require('passport');
const dotenv = require('dotenv');
const morgan = require('morgan');
// const path = require('path');
const postRouter = require('./routes/post');
const postsRouter = require('./routes/posts');
const userRouter = require('./routes/user');
const db = require('./models');
const passportConfig = require('./passport');
dotenv.config();
const app = express();
db.sequelize.sync()
.then(() => {
console.log('db 연결 성공');
})
.catch(console.error);
passportConfig();
app.use(morgan('dev'));
app.use(cors({
origin: '*',
// origin: 'http://localhost:3060',
// credentials: true,
}));
// app.use('/', express.static(path.join(__dirname, 'uploads')));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(session({
saveUninitialized: false,
resave: false,
secret: process.env.COOKIE_SECRET,
}));
app.use(passport.initialize());
app.use(passport.session());
app.get('/', (req, res) => {
res.send('hello express');
});
// API는 다른 서비스가 내 서비스의 기능을 실행할 수 있게 열어둔 창구
app.use('/posts', postsRouter);
app.use('/post', postRouter);
app.use('/user', userRouter);
app.listen(3065, () => {
console.log('서버 실행 중!');
});
passport/index.js
const passport = require('passport');
const local = require('./local');
const { User } = require('../models');
module.exports = () => {
passport.serializeUser((user, done) => { // 서버쪽에 [{ id: 1, cookie: 'clhxy' }]
done(null, user.id);
});
passport.deserializeUser(async (id, done) => {
try {
const user = await User.findOne({ where: { id }});
done(null, user); // req.user
} catch (error) {
console.error(error);
done(error);
}
});
local();
};
passport/local.js
const passport = require('passport');
const { Strategy: LocalStrategy } = require('passport-local');
const bcrypt = require('bcrypt');
const { User } = require('../models');
module.exports = () => {
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
}, async (email, password, done) => {
try {
const user = await User.findOne({
where: { email }
});
if (!user) {
return done(null, false, { reason: '존재하지 않는 이메일입니다!' });
}
const result = await bcrypt.compare(password, user.password);
if (result) {
return done(null, user);
}
return done(null, false, { reason: '비밀번호가 틀렸습니다.' });
} catch (error) {
console.error(error);
return done(error);
}
}));
};
routes/middlewares.js
exports.isLoggedIn = (req, res, next) => {
if (req.isAuthenticated()) {
next();
} else {
res.status(401).send('로그인이 필요합니다.');
}
};
exports.isNotLoggedIn = (req, res, next) => {
if (!req.isAuthenticated()) {
next();
} else {
res.status(401).send('로그인하지 않은 사용자만 접근 가능합니다.');
}
};
routes/user.js
const express = require('express');
const bcrypt = require('bcrypt');
const passport = require('passport');
const { User, Post } = require('../models');
const { isLoggedIn, isNotLoggedIn } = require('./middlewares');
const router = express.Router();
router.get('/', async (req, res, next) => { // GET /user
try {
if (req.user) {
const fullUserWithoutPassword = await User.findOne({
where: { id: req.user.id },
attributes: {
exclude: ['password']
},
include: [{
model: Post,
attributes: ['id'],
}, {
model: User,
as: 'Followings',
attributes: ['id'],
}, {
model: User,
as: 'Followers',
attributes: ['id'],
}]
})
res.status(200).json(fullUserWithoutPassword);
} else {
res.status(200).json(null);
}
} catch (error) {
console.error(error);
next(error);
}
});
router.post('/login', isNotLoggedIn, (req, res, next) => {
passport.authenticate('local', (err, user, info) => {
if (err) {
console.error(err);
return next(err);
}
if (info) {
return res.status(401).send(info.reason);
}
return req.login(user, async (loginErr) => {
if (loginErr) {
console.error(loginErr);
return next(loginErr);
}
const fullUserWithoutPassword = await User.findOne({
where: { id: user.id },
attributes: {
exclude: ['password']
},
include: [{
model: Post,
attributes: ['id'],
}, {
model: User,
as: 'Followings',
attributes: ['id'],
}, {
model: User,
as: 'Followers',
attributes: ['id'],
}]
})
return res.status(200).json(fullUserWithoutPassword);
});
})(req, res, next);
});
router.post('/', isNotLoggedIn, async (req, res, next) => { // POST /user/
try {
const exUser = await User.findOne({
where: {
email: req.body.email,
}
});
if (exUser) {
return res.status(403).send('이미 사용 중인 아이디입니다.');
}
const hashedPassword = await bcrypt.hash(req.body.password, 12);
await User.create({
email: req.body.email,
nickname: req.body.nickname,
password: hashedPassword,
});
res.status(201).send('ok');
} catch (error) {
console.error(error);
next(error); // status 500
}
});
router.post('/logout', isLoggedIn, (req, res) => {
req.logout();
req.session.destroy();
res.send('ok');
});
router.patch('/nickname', isLoggedIn, async (req, res, next) => {
try {
await User.update({
nickname: req.body.nickname,
}, {
where: { id: req.user.id },
});
res.status(200).json({ nickname: req.body.nickname });
} catch (error) {
console.error(error);
next(error);
}
});
router.patch('/:userId/follow', isLoggedIn, async (req, res, next) => { // PATCH /user/1/follow
try {
const user = await User.findOne({ where: { id: req.params.userId }});
if (!user) {
res.status(403).send('없는 사람을 팔로우하려고 하시네요?');
}
await user.addFollowers(req.user.id);
res.status(200).json({ UserId: parseInt(req.params.userId, 10) });
} catch (error) {
console.error(error);
next(error);
}
});
router.delete('/:userId/follow', isLoggedIn, async (req, res, next) => { // DELETE /user/1/follow
try {
const user = await User.findOne({ where: { id: req.params.userId }});
if (!user) {
res.status(403).send('없는 사람을 언팔로우하려고 하시네요?');
}
await user.removeFollowers(req.user.id);
res.status(200).json({ UserId: parseInt(req.params.userId, 10) });
} catch (error) {
console.error(error);
next(error);
}
});
router.delete('/follower/:userId', isLoggedIn, async (req, res, next) => { // DELETE /user/follower/2
try {
const user = await User.findOne({ where: { id: req.params.userId }});
if (!user) {
res.status(403).send('없는 사람을 차단하려고 하시네요?');
}
await user.removeFollowings(req.user.id);
res.status(200).json({ UserId: parseInt(req.params.userId, 10) });
} catch (error) {
console.error(error);
next(error);
}
});
router.get('/followers', isLoggedIn, async (req, res, next) => { // GET /user/followers
try {
const user = await User.findOne({ where: { id: req.user.id }});
if (!user) {
res.status(403).send('없는 사람을 찾으려고 하시네요?');
}
const followers = await user.getFollowers();
res.status(200).json(followers);
} catch (error) {
console.error(error);
next(error);
}
});
router.get('/followings', isLoggedIn, async (req, res, next) => { // GET /user/followings
try {
const user = await User.findOne({ where: { id: req.user.id }});
if (!user) {
res.status(403).send('없는 사람을 찾으려고 하시네요?');
}
const followings = await user.getFollowings();
res.status(200).json(followings);
} catch (error) {
console.error(error);
next(error);
}
});
module.exports = router;
FRONT
config/config.js
export const domainUrl = 'http://api.nodebird.com';
export const localhostUrl = 'http://localhost:3065';
LoginForm.js
import React, { useCallback, useEffect } from 'react';
import { Form, Input, Button } from 'antd';
import Link from 'next/link';
import styled from 'styled-components';
import { useDispatch, useSelector } from 'react-redux';
import useInput from '../hooks/useInput';
// import { loginRequestAction } from '../reducers/user';
import { LOG_IN_REQUEST } from '../reducers/user';
const ButtonWrapper = styled.div`
margin-top: 10px;
`;
const FormWrapper = styled(Form)`
padding: 10px;
`;
const LoginForm = () => {
const dispatch = useDispatch();
const { logInLoading, logInError } = useSelector((state) => state.user);
const [email, onChangeEmail] = useInput('');
const [password, onChangePassword] = useInput('');
useEffect(() => {
if (logInError) {
alert(logInError);
}
}, [logInError]);
// const onSubmitForm = useCallback(() => {
// console.log(email, password);
// dispatch(loginRequestAction({ email, password }));
// }, [email, password]);
const onSubmitForm = useCallback(() => {
console.log(email, password);
dispatch({
type: LOG_IN_REQUEST,
data: { email, password },
});
}, [email, password]);
return (
<FormWrapper onFinish={onSubmitForm}>
<div>
<label htmlFor="user-email">이메일</label>
<br />
<Input name="user-email" type="email" value={email} onChange={onChangeEmail} required />
</div>
<div>
<label htmlFor="user-password">비밀번호</label>
<br />
<Input
name="user-password"
type="password"
value={password}
onChange={onChangePassword}
required
/>
</div>
<ButtonWrapper>
<Button type="primary" htmlType="submit" loading={logInLoading}>로그인</Button>
<Link href="/signup"><a><Button>회원가입</Button></a></Link>
</ButtonWrapper>
</FormWrapper>
);
};
export default LoginForm;
sagas/index.js
import { all, fork } from 'redux-saga/effects';
import axios from 'axios';
import postSaga from './post';
import userSaga from './user';
import { localhostUrl } from '../config/config';
// axios.defaults.baseURL = 'http://localhost:3065';
axios.defaults.baseURL = localhostUrl;
// axios.defaults.withCredentials = true;
axios.defaults.baseURL = localhostUrl;
export default function* rootSaga() {
yield all([
fork(postSaga),
fork(userSaga),
]);
}
reducers/user.js
import produce from '../util/produce';
export const initialState = {
loadUserLoading: false, // 유저 정보 가져오기 시도중
loadUserDone: false,
loadUserError: null,
followLoading: false, // 팔로우 시도중
followDone: false,
followError: null,
unfollowLoading: false, // 언팔로우 시도중
unfollowDone: false,
unfollowError: null,
logInLoading: false, // 로그인 시도중
logInDone: false,
logInError: null,
logOutLoading: false, // 로그아웃 시도중
logOutDone: false,
logOutError: null,
signUpLoading: false, // 회원가입 시도중
signUpDone: false,
signUpError: null,
changeNicknameLoading: false, // 닉네임 변경 시도중
changeNicknameDone: false,
changeNicknameError: null,
loadFollowingsLoading: false,
loadFollowingsDone: false,
loadFollowingsError: null,
loadFollowersLoading: false,
loadFollowersDone: false,
loadFollowersError: null,
removeFollowerLoading: false,
removeFollowerDone: false,
removeFollowerError: null,
me: null,
signUpData: {},
loginData: {},
};
export const LOAD_USER_REQUEST = 'LOAD_USER_REQUEST';
export const LOAD_USER_SUCCESS = 'LOAD_USER_SUCCESS';
export const LOAD_USER_FAILURE = 'LOAD_USER_FAILURE';
export const LOG_IN_REQUEST = 'LOG_IN_REQUEST';
export const LOG_IN_SUCCESS = 'LOG_IN_SUCCESS';
export const LOG_IN_FAILURE = 'LOG_IN_FAILURE';
export const LOG_OUT_REQUEST = 'LOG_OUT_REQUEST';
export const LOG_OUT_SUCCESS = 'LOG_OUT_SUCCESS';
export const LOG_OUT_FAILURE = 'LOG_OUT_FAILURE';
export const SIGN_UP_REQUEST = 'SIGN_UP_REQUEST';
export const SIGN_UP_SUCCESS = 'SIGN_UP_SUCCESS';
export const SIGN_UP_FAILURE = 'SIGN_UP_FAILURE';
export const CHANGE_NICKNAME_REQUEST = 'CHANGE_NICKNAME_REQUEST';
export const CHANGE_NICKNAME_SUCCESS = 'CHANGE_NICKNAME_SUCCESS';
export const CHANGE_NICKNAME_FAILURE = 'CHANGE_NICKNAME_FAILURE';
export const FOLLOW_REQUEST = 'FOLLOW_REQUEST';
export const FOLLOW_SUCCESS = 'FOLLOW_SUCCESS';
export const FOLLOW_FAILURE = 'FOLLOW_FAILURE';
export const UNFOLLOW_REQUEST = 'UNFOLLOW_REQUEST';
export const UNFOLLOW_SUCCESS = 'UNFOLLOW_SUCCESS';
export const UNFOLLOW_FAILURE = 'UNFOLLOW_FAILURE';
export const REMOVE_FOLLOWER_REQUEST = 'REMOVE_FOLLOWER_REQUEST';
export const REMOVE_FOLLOWER_SUCCESS = 'REMOVE_FOLLOWER_SUCCESS';
export const REMOVE_FOLLOWER_FAILURE = 'REMOVE_FOLLOWER_FAILURE';
export const LOAD_FOLLOWINGS_REQUEST = 'LOAD_FOLLOWINGS_REQUEST';
export const LOAD_FOLLOWINGS_SUCCESS = 'LOAD_FOLLOWINGS_SUCCESS';
export const LOAD_FOLLOWINGS_FAILURE = 'LOAD_FOLLOWINGS_FAILURE';
export const LOAD_FOLLOWERS_REQUEST = 'LOAD_FOLLOWERS_REQUEST';
export const LOAD_FOLLOWERS_SUCCESS = 'LOAD_FOLLOWERS_SUCCESS';
export const LOAD_FOLLOWERS_FAILURE = 'LOAD_FOLLOWERS_FAILURE';
export const ADD_POST_TO_ME = 'ADD_POST_TO_ME';
export const REMOVE_POST_OF_ME = 'REMOVE_POST_OF_ME';
export const loginRequestAction = (data) => ({
type: LOG_IN_REQUEST,
data,
});
export const logoutRequestAction = () => ({
type: LOG_OUT_REQUEST,
});
const reducer = (state = initialState, action) => produce(state, (draft) => {
switch (action.type) {
case REMOVE_FOLLOWER_REQUEST:
draft.removeFollowerLoading = true;
draft.removeFollowerError = null;
draft.removeFollowerDone = false;
break;
case REMOVE_FOLLOWER_SUCCESS:
draft.removeFollowerLoading = false;
draft.me.Followers = draft.me.Followers.filter((v) => v.id !== action.data.UserId);
draft.removeFollowerDone = true;
break;
case REMOVE_FOLLOWER_FAILURE:
draft.removeFollowerLoading = false;
draft.removeFollowerError = action.error;
break;
case LOAD_FOLLOWINGS_REQUEST:
draft.loadFollowingsLoading = true;
draft.loadFollowingsError = null;
draft.loadFollowingsDone = false;
break;
case LOAD_FOLLOWINGS_SUCCESS:
draft.loadFollowingsLoading = false;
draft.me.Followings = action.data;
draft.loadFollowingsDone = true;
break;
case LOAD_FOLLOWINGS_FAILURE:
draft.loadFollowingsLoading = false;
draft.loadFollowingsError = action.error;
break;
case LOAD_FOLLOWERS_REQUEST:
draft.loadFollowersLoading = true;
draft.loadFollowersError = null;
draft.loadFollowersDone = false;
break;
case LOAD_FOLLOWERS_SUCCESS:
draft.loadFollowersLoading = false;
draft.me.Followers = action.data;
draft.loadFollowersDone = true;
break;
case LOAD_FOLLOWERS_FAILURE:
draft.loadFollowersLoading = false;
draft.loadFollowersError = action.error;
break;
case LOAD_USER_REQUEST:
draft.loadUserLoading = true;
draft.loadUserError = null;
draft.loadUserDone = false;
break;
case LOAD_USER_SUCCESS:
draft.loadUserLoading = false;
draft.me = action.data;
draft.loadUserDone = true;
break;
case LOAD_USER_FAILURE:
draft.loadUserLoading = false;
draft.loadUserError = action.error;
break;
case FOLLOW_REQUEST:
draft.followLoading = true;
draft.followError = null;
draft.followDone = false;
break;
case FOLLOW_SUCCESS:
draft.followLoading = false;
draft.me.Followings.push({ id: action.data.UserId });
draft.followDone = true;
break;
case FOLLOW_FAILURE:
draft.followLoading = false;
draft.followError = action.error;
break;
case UNFOLLOW_REQUEST:
draft.unfollowLoading = true;
draft.unfollowError = null;
draft.unfollowDone = false;
break;
case UNFOLLOW_SUCCESS:
draft.unfollowLoading = false;
draft.me.Followings = draft.me.Followings.filter((v) => v.id !== action.data.UserId);
draft.unfollowDone = true;
break;
case UNFOLLOW_FAILURE:
draft.unfollowLoading = false;
draft.unfollowError = action.error;
break;
case LOG_IN_REQUEST:
draft.logInLoading = true;
draft.logInError = null;
draft.logInDone = false;
break;
case LOG_IN_SUCCESS:
draft.logInLoading = false;
draft.me = action.data;
draft.logInDone = true;
break;
case LOG_IN_FAILURE:
draft.logInLoading = false;
draft.logInError = action.error;
break;
case LOG_OUT_REQUEST:
draft.logOutLoading = true;
draft.logOutError = null;
draft.logOutDone = false;
break;
case LOG_OUT_SUCCESS:
draft.logOutLoading = false;
draft.logOutDone = true;
draft.me = null;
break;
case LOG_OUT_FAILURE:
draft.logOutLoading = false;
draft.logOutError = action.error;
break;
case SIGN_UP_REQUEST:
draft.signUpLoading = true;
draft.signUpError = null;
draft.signUpDone = false;
break;
case SIGN_UP_SUCCESS:
draft.signUpLoading = false;
draft.signUpDone = true;
break;
case SIGN_UP_FAILURE:
draft.signUpLoading = false;
draft.signUpError = action.error;
break;
case CHANGE_NICKNAME_REQUEST:
draft.changeNicknameLoading = true;
draft.changeNicknameError = null;
draft.changeNicknameDone = false;
break;
case CHANGE_NICKNAME_SUCCESS:
draft.me.nickname = action.data.nickname;
draft.changeNicknameLoading = false;
draft.changeNicknameDone = true;
break;
case CHANGE_NICKNAME_FAILURE:
draft.changeNicknameLoading = false;
draft.changeNicknameError = action.error;
break;
case ADD_POST_TO_ME:
draft.me.Posts.unshift({ id: action.data });
break;
// return {
// ...state,
// me: {
// ...state.me,
// Posts: [{ id: action.data }, ...state.me.Posts],
// },
// };
case REMOVE_POST_OF_ME:
draft.me.Posts = draft.me.Posts.filter((v) => v.id !== action.data);
break;
// return {
// ...state,
// me: {
// ...state.me,
// Posts: state.me.Posts.filter((v) => v.id !== action.data),
// },
// };
default:
break;
}
});
export default reducer;
브라우저 login 시 성공
브라우저 로그아웃 에러
브라우저 로그아웃 에러메세지
Answer 1
0
미안합니다. . 도움을 드리고 싶은데.. 오래전이라서 기억이 잘 안나네요..
작성하신 코드를 github 코드와 대체해서 복붙해보시면 될것 같습니다.
저도 같은 에러가 나는데 해결을 못하고 있습니다. 어디서 오타가 있엇나요?