Showing
29 changed files
with
877 additions
and
40 deletions
... | @@ -6,10 +6,20 @@ | ... | @@ -6,10 +6,20 @@ |
6 | "@testing-library/jest-dom": "^4.2.4", | 6 | "@testing-library/jest-dom": "^4.2.4", |
7 | "@testing-library/react": "^9.3.2", | 7 | "@testing-library/react": "^9.3.2", |
8 | "@testing-library/user-event": "^7.1.2", | 8 | "@testing-library/user-event": "^7.1.2", |
9 | + "axios": "^0.19.2", | ||
10 | + "immer": "^7.0.1", | ||
11 | + "include-media": "^1.4.9", | ||
12 | + "open-color": "^1.7.0", | ||
9 | "react": "^16.13.1", | 13 | "react": "^16.13.1", |
10 | "react-dom": "^16.13.1", | 14 | "react-dom": "^16.13.1", |
15 | + "react-redux": "^7.2.0", | ||
11 | "react-router-dom": "^5.2.0", | 16 | "react-router-dom": "^5.2.0", |
12 | - "react-scripts": "3.4.1" | 17 | + "react-scripts": "3.4.1", |
18 | + "redux": "^4.0.5", | ||
19 | + "redux-actions": "^2.6.5", | ||
20 | + "redux-devtools-extension": "^2.13.8", | ||
21 | + "redux-saga": "^1.1.3", | ||
22 | + "styled-components": "^5.1.1" | ||
13 | }, | 23 | }, |
14 | "scripts": { | 24 | "scripts": { |
15 | "start": "react-scripts start", | 25 | "start": "react-scripts start", |
... | @@ -31,5 +41,6 @@ | ... | @@ -31,5 +41,6 @@ |
31 | "last 1 firefox version", | 41 | "last 1 firefox version", |
32 | "last 1 safari version" | 42 | "last 1 safari version" |
33 | ] | 43 | ] |
34 | - } | 44 | + }, |
45 | + "proxy": "http://localhost:4000" | ||
35 | } | 46 | } | ... | ... |
1 | import React from 'react'; | 1 | import React from 'react'; |
2 | -import logo from './logo.svg'; | 2 | +import { Route } from 'react-router-dom'; |
3 | import './App.css'; | 3 | import './App.css'; |
4 | +import LoginPage from './pages/LoginPage'; | ||
5 | +import RegisterPage from './pages/RegisterPage'; | ||
6 | +import HomePage from './pages/HomePage'; | ||
4 | 7 | ||
5 | function App() { | 8 | function App() { |
6 | return ( | 9 | return ( |
7 | - <div className="App"> | 10 | + <> |
8 | - <header className="App-header"> | 11 | + <Route component={HomePage} path={['/@:username', '/']} exact /> |
9 | - <img src={logo} className="App-logo" alt="logo" /> | 12 | + <Route component={LoginPage} path="/login" /> |
10 | - <p> | 13 | + <Route component={RegisterPage} path="/register" /> |
11 | - Edit <code>src/App.js</code> and save to reload. | 14 | + </> |
12 | - </p> | ||
13 | - <a | ||
14 | - className="App-link" | ||
15 | - href="https://reactjs.org" | ||
16 | - target="_blank" | ||
17 | - rel="noopener noreferrer" | ||
18 | - > | ||
19 | - Learn React | ||
20 | - </a> | ||
21 | - </header> | ||
22 | - </div> | ||
23 | ); | 15 | ); |
24 | } | 16 | } |
25 | 17 | ... | ... |
1 | +import React from 'react'; | ||
2 | +import styled from 'styled-components'; | ||
3 | +import { Link } from 'react-router-dom'; | ||
4 | +import palette from '../../lib/styles/palette'; | ||
5 | +import Button from '../common/Button'; | ||
6 | + | ||
7 | +const AuthFormBlock = styled.div` | ||
8 | + h3 { | ||
9 | + margin: 0; | ||
10 | + color: ${palette.gray[8]}; | ||
11 | + margin-bottom: 1rem; | ||
12 | + } | ||
13 | +`; | ||
14 | + | ||
15 | +const StyledInput = styled.input` | ||
16 | + font-size: 1rem; | ||
17 | + border: none; | ||
18 | + border-bottom: 1px solid ${palette.gray[5]}; | ||
19 | + padding-bottom: 0.5rem; | ||
20 | + outline: none; | ||
21 | + width: 100%; | ||
22 | + &:focus { | ||
23 | + color: $oc-teal-7; | ||
24 | + border-bottom: 1px solid ${palette.gray[7]}; | ||
25 | + } | ||
26 | + & + & { | ||
27 | + margin-top: 1rem; | ||
28 | + } | ||
29 | +`; | ||
30 | + | ||
31 | +const Footer = styled.div` | ||
32 | + margin-top: 2rem; | ||
33 | + text-align: right; | ||
34 | + a { | ||
35 | + color: ${palette.gray[6]}; | ||
36 | + text-decoration: underline; | ||
37 | + &:hover { | ||
38 | + color: ${palette.gray[9]}; | ||
39 | + } | ||
40 | + } | ||
41 | +`; | ||
42 | + | ||
43 | +const ButtonWithMarginTop = styled(Button)` | ||
44 | + margin-top: 1rem; | ||
45 | +`; | ||
46 | + | ||
47 | +const ErrorMessage = styled.div` | ||
48 | + color: red; | ||
49 | + text-align: center; | ||
50 | + font-size: 0.875rem; | ||
51 | + margin-top: 1rem; | ||
52 | +`; | ||
53 | + | ||
54 | +const textMap = { | ||
55 | + login: '로그인', | ||
56 | + register: '회원가입', | ||
57 | +}; | ||
58 | + | ||
59 | +const AuthForm = ({ type, form, onChange, onSubmit, error }) => { | ||
60 | + const text = textMap[type]; | ||
61 | + return ( | ||
62 | + <AuthFormBlock> | ||
63 | + <h3>{text}</h3> | ||
64 | + <form onSubmit={onSubmit}> | ||
65 | + <StyledInput | ||
66 | + autoComplete="username" | ||
67 | + name="username" | ||
68 | + placeholder="아이디" | ||
69 | + onChange={onChange} | ||
70 | + value={form.username} | ||
71 | + /> | ||
72 | + <StyledInput | ||
73 | + autoComplete="new-password" | ||
74 | + name="password" | ||
75 | + placeholder="비밀번호" | ||
76 | + type="password" | ||
77 | + onChange={onChange} | ||
78 | + value={form.password} | ||
79 | + /> | ||
80 | + {type === 'register' && ( | ||
81 | + <StyledInput | ||
82 | + autoComplete="new-password" | ||
83 | + name="passwordConfirm" | ||
84 | + placeholder="비밀번호 확인" | ||
85 | + type="password" | ||
86 | + onChange={onChange} | ||
87 | + value={form.passwordConfirm} | ||
88 | + /> | ||
89 | + )} | ||
90 | + {error && <ErrorMessage>{error}</ErrorMessage>} | ||
91 | + <ButtonWithMarginTop cyan fullWidth> | ||
92 | + {text} | ||
93 | + </ButtonWithMarginTop> | ||
94 | + </form> | ||
95 | + <Footer> | ||
96 | + {type === 'login' ? ( | ||
97 | + <Link to="/register">회원가입</Link> | ||
98 | + ) : ( | ||
99 | + <Link to="/login">로그인</Link> | ||
100 | + )} | ||
101 | + </Footer> | ||
102 | + </AuthFormBlock> | ||
103 | + ); | ||
104 | +}; | ||
105 | + | ||
106 | +export default AuthForm; |
1 | +import React from 'react'; | ||
2 | +import styled from 'styled-components'; | ||
3 | +import palette from '../../lib/styles/palette'; | ||
4 | +import { Link } from 'react-router-dom'; | ||
5 | +/* | ||
6 | +register/login Layout | ||
7 | +*/ | ||
8 | +const AuthTemplateBlock = styled.div` | ||
9 | + position: absolute; | ||
10 | + left: 0; | ||
11 | + top: 0; | ||
12 | + bottom: 0; | ||
13 | + right: 0; | ||
14 | + background: ${palette.gray[2]}; | ||
15 | + display: flex; | ||
16 | + flex-direction: column; | ||
17 | + justify-content: center; | ||
18 | + align-items: center; | ||
19 | +`; | ||
20 | + | ||
21 | +const WhiteBox = styled.div` | ||
22 | + .logo-area { | ||
23 | + display: block; | ||
24 | + padding-bottom: 2rem; | ||
25 | + text-align: center; | ||
26 | + font-weight: bold; | ||
27 | + letter-spacing: 2px; | ||
28 | + } | ||
29 | + box-shadow: 0 0 8px rgba(0, 0, 0, 0.025); | ||
30 | + padding: 2rem; | ||
31 | + width: 360px; | ||
32 | + background: white; | ||
33 | + border-radius: 2px; | ||
34 | +`; | ||
35 | + | ||
36 | +const AuthTemplate = ({ children }) => { | ||
37 | + return ( | ||
38 | + <AuthTemplateBlock> | ||
39 | + <WhiteBox> | ||
40 | + <div className="logo-area"> | ||
41 | + <Link to="/">작심삼일</Link> | ||
42 | + </div> | ||
43 | + {children} | ||
44 | + </WhiteBox> | ||
45 | + </AuthTemplateBlock> | ||
46 | + ); | ||
47 | +}; | ||
48 | + | ||
49 | +export default AuthTemplate; |
1 | +import React from 'react'; | ||
2 | +import styled, { css } from 'styled-components'; | ||
3 | +import palette from '../../lib/styles/palette'; | ||
4 | +import { withRouter } from 'react-router-dom'; | ||
5 | + | ||
6 | +const StyledButton = styled.button` | ||
7 | + border: none; | ||
8 | + border-radius: 4px; | ||
9 | + font-size: 1rem; | ||
10 | + font-weight: bold; | ||
11 | + padding: 0.25rem 1rem; | ||
12 | + color: white; | ||
13 | + outline: none; | ||
14 | + cursor: pointer; | ||
15 | + | ||
16 | + background: ${palette.gray[8]}; | ||
17 | + &:hover { | ||
18 | + background: ${palette.gray[6]}; | ||
19 | + } | ||
20 | + ${props => | ||
21 | + props.fullWidth && | ||
22 | + css` | ||
23 | + padding-top: 0.75rem; | ||
24 | + padding-bottom: 0.75rem; | ||
25 | + width: 100%; | ||
26 | + font-size: 1.125rem; | ||
27 | + `} | ||
28 | + | ||
29 | + ${props => | ||
30 | + props.cyan && | ||
31 | + css` | ||
32 | + background: ${palette.cyan[5]}; | ||
33 | + &:hover { | ||
34 | + background: ${palette.cyan[4]}; | ||
35 | + } | ||
36 | + `} | ||
37 | +`; | ||
38 | + | ||
39 | +const Button = ({ to, history, ...rest }) => { | ||
40 | + const onClick = e => { | ||
41 | + if (to) { | ||
42 | + history.push(to); | ||
43 | + } | ||
44 | + if (rest.onClick) { | ||
45 | + rest.onClick(e); | ||
46 | + } | ||
47 | + }; | ||
48 | + return <StyledButton {...rest} onClick={onClick} />; | ||
49 | +}; | ||
50 | +export default withRouter(Button); |
1 | +import React from 'react'; | ||
2 | +import styled from 'styled-components'; | ||
3 | +import Responsive from './Responsive'; | ||
4 | +import Button from './Button'; | ||
5 | +import { Link } from 'react-router-dom'; | ||
6 | + | ||
7 | +const HeaderBlock = styled.div` | ||
8 | + position: fixed; | ||
9 | + width: 100%; | ||
10 | + background: white; | ||
11 | + box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.08); | ||
12 | +`; | ||
13 | + | ||
14 | +const Wrapper = styled(Responsive)` | ||
15 | + height: 4rem; | ||
16 | + display: flex; | ||
17 | + align-items: center; | ||
18 | + justify-content: space-between; | ||
19 | + .logo { | ||
20 | + font-size: 1.125rem; | ||
21 | + font-weight: 800; | ||
22 | + letter-spacing: 2px; | ||
23 | + } | ||
24 | + .right { | ||
25 | + display: flex; | ||
26 | + align-items: center; | ||
27 | + } | ||
28 | +`; | ||
29 | + | ||
30 | +const Spacer = styled.div` | ||
31 | + height: 4rem; | ||
32 | +`; | ||
33 | +const UserInfo = styled.div` | ||
34 | + font-weight: 800; | ||
35 | + margin-right: 1rem; | ||
36 | +`; | ||
37 | + | ||
38 | +const Header = ({ user, onLogout }) => { | ||
39 | + return ( | ||
40 | + <> | ||
41 | + <HeaderBlock> | ||
42 | + <Wrapper> | ||
43 | + <Link to="/" className="logo"> | ||
44 | + 작심삼일 | ||
45 | + </Link> | ||
46 | + {user ? ( | ||
47 | + <div className="right"> | ||
48 | + <UserInfo>{user.username}</UserInfo> | ||
49 | + <Button onClick={onLogout}>로그아웃</Button> | ||
50 | + </div> | ||
51 | + ) : ( | ||
52 | + <div className="right"> | ||
53 | + <Button to="/login">로그인</Button> | ||
54 | + </div> | ||
55 | + )} | ||
56 | + </Wrapper> | ||
57 | + </HeaderBlock> | ||
58 | + <Spacer /> | ||
59 | + </> | ||
60 | + ); | ||
61 | +}; | ||
62 | + | ||
63 | +export default Header; |
1 | +import React from 'react'; | ||
2 | +import styled from 'styled-components'; | ||
3 | + | ||
4 | +const ResponsiveBlock = styled.div` | ||
5 | + padding-left: 1rem; | ||
6 | + padding-right: 1rem; | ||
7 | + width: 1024px; | ||
8 | + margin: 0 auto; | ||
9 | + | ||
10 | + @media (max-width: 1024px) { | ||
11 | + width: 768px; | ||
12 | + } | ||
13 | + @media (max-width: 768px) { | ||
14 | + width: 100%; | ||
15 | + } | ||
16 | +`; | ||
17 | + | ||
18 | +const Responsive = ({ children, ...rest }) => { | ||
19 | + return <ResponsiveBlock {...rest}>{children}</ResponsiveBlock>; | ||
20 | +}; | ||
21 | + | ||
22 | +export default Responsive; |
1 | +import React, { useEffect, useState } from 'react'; | ||
2 | +import { useDispatch, useSelector } from 'react-redux'; | ||
3 | +import { withRouter } from 'react-router-dom'; | ||
4 | +import { changeField, initializeForm, login } from '../../modules/auth'; | ||
5 | +import AuthForm from '../../components/auth/AuthForm'; | ||
6 | +import { check } from '../../modules/user'; | ||
7 | + | ||
8 | +const LoginForm = ({ history }) => { | ||
9 | + const dispatch = useDispatch(); | ||
10 | + const [error, setError] = useState(null); | ||
11 | + const { form, auth, authError, user } = useSelector(({ auth, user }) => ({ | ||
12 | + form: auth.login, | ||
13 | + auth: auth.auth, | ||
14 | + authError: auth.authError, | ||
15 | + user: user.user, | ||
16 | + })); | ||
17 | + | ||
18 | + const onChange = (e) => { | ||
19 | + const { value, name } = e.target; | ||
20 | + dispatch( | ||
21 | + changeField({ | ||
22 | + form: 'login', | ||
23 | + key: name, | ||
24 | + value, | ||
25 | + }), | ||
26 | + ); | ||
27 | + }; | ||
28 | + | ||
29 | + const onSubmit = (e) => { | ||
30 | + e.preventDefault(); | ||
31 | + const { username, password } = form; | ||
32 | + dispatch(login({ username, password })); | ||
33 | + }; | ||
34 | + | ||
35 | + useEffect(() => { | ||
36 | + dispatch(initializeForm('login')); | ||
37 | + }, [dispatch]); | ||
38 | + | ||
39 | + useEffect(() => { | ||
40 | + if (authError) { | ||
41 | + console.log('Error Occured'); | ||
42 | + console.log(authError); | ||
43 | + setError('로그인 실패'); | ||
44 | + return; | ||
45 | + } | ||
46 | + if (auth) { | ||
47 | + console.log('Login Success'); | ||
48 | + dispatch(check()); | ||
49 | + } | ||
50 | + }, [auth, authError, dispatch]); | ||
51 | + | ||
52 | + useEffect(() => { | ||
53 | + if (user) { | ||
54 | + history.push('/'); | ||
55 | + try { | ||
56 | + localStorage.setItem('user', JSON.stringify(user)); | ||
57 | + } catch (e) { | ||
58 | + console.log('localStorage is not working'); | ||
59 | + } | ||
60 | + console.log(user); | ||
61 | + } | ||
62 | + }, [history, user]); | ||
63 | + return ( | ||
64 | + <AuthForm | ||
65 | + type="login" | ||
66 | + form={form} | ||
67 | + onChange={onChange} | ||
68 | + onSubmit={onSubmit} | ||
69 | + error={error} | ||
70 | + ></AuthForm> | ||
71 | + ); | ||
72 | +}; | ||
73 | + | ||
74 | +export default withRouter(LoginForm); |
1 | +import React, { useEffect, useState } from 'react'; | ||
2 | +import { useDispatch, useSelector } from 'react-redux'; | ||
3 | +import { changeField, initializeForm, register } from '../../modules/auth'; | ||
4 | +import AuthForm from '../../components/auth/AuthForm'; | ||
5 | +import { check } from '../../modules/user'; | ||
6 | +import { withRouter } from 'react-router-dom'; | ||
7 | + | ||
8 | +const RegisterForm = ({ history }) => { | ||
9 | + const [error, setError] = useState(null); | ||
10 | + const dispatch = useDispatch(); | ||
11 | + const { form, auth, authError, user } = useSelector(({ auth, user }) => ({ | ||
12 | + form: auth.register, | ||
13 | + auth: auth.auth, | ||
14 | + authError: auth.authError, | ||
15 | + user: user.user, | ||
16 | + })); | ||
17 | + | ||
18 | + const onChange = (e) => { | ||
19 | + const { value, name } = e.target; | ||
20 | + dispatch( | ||
21 | + changeField({ | ||
22 | + form: 'register', | ||
23 | + key: name, | ||
24 | + value, | ||
25 | + }), | ||
26 | + ); | ||
27 | + }; | ||
28 | + | ||
29 | + const onSubmit = (e) => { | ||
30 | + e.preventDefault(); | ||
31 | + const { username, password, passwordConfirm } = form; | ||
32 | + if ([username, password, passwordConfirm].includes('')) { | ||
33 | + setError('빈 칸을 모두 입력하세요'); | ||
34 | + return; | ||
35 | + } | ||
36 | + if (password !== passwordConfirm) { | ||
37 | + setError('비밀번호가 일치하지 않습니다.'); | ||
38 | + changeField({ form: 'register', key: 'password', value: '' }); | ||
39 | + changeField({ form: 'register', key: 'passwordConfirm', value: '' }); | ||
40 | + return; | ||
41 | + } | ||
42 | + dispatch(register({ username, password })); | ||
43 | + }; | ||
44 | + | ||
45 | + useEffect(() => { | ||
46 | + dispatch(initializeForm('register')); | ||
47 | + }, [dispatch]); | ||
48 | + useEffect(() => { | ||
49 | + if (authError) { | ||
50 | + if (authError.response.status === 409) { | ||
51 | + setError('이미 존재하는 계정명입니다.'); | ||
52 | + return; | ||
53 | + } | ||
54 | + setError('회원가입 실패'); | ||
55 | + return; | ||
56 | + } | ||
57 | + | ||
58 | + if (auth) { | ||
59 | + console.log('Register Success!'); | ||
60 | + console.log(auth); | ||
61 | + dispatch(check()); | ||
62 | + } | ||
63 | + }, [auth, authError, dispatch]); | ||
64 | + | ||
65 | + useEffect(() => { | ||
66 | + if (user) { | ||
67 | + console.log('SUCCESS check API'); | ||
68 | + history.push('/'); | ||
69 | + try { | ||
70 | + localStorage.setItem('user', JSON.stringify(user)); | ||
71 | + } catch (e) { | ||
72 | + console.log('localStorage is not working'); | ||
73 | + } | ||
74 | + } | ||
75 | + }, [history, user]); | ||
76 | + return ( | ||
77 | + <AuthForm | ||
78 | + type="register" | ||
79 | + form={form} | ||
80 | + onChange={onChange} | ||
81 | + onSubmit={onSubmit} | ||
82 | + error={error} | ||
83 | + ></AuthForm> | ||
84 | + ); | ||
85 | +}; | ||
86 | + | ||
87 | +export default withRouter(RegisterForm); |
1 | +import React from 'react'; | ||
2 | +import { useSelector, useDispatch } from 'react-redux'; | ||
3 | +import Header from '../../components/common/Header'; | ||
4 | +import { logout } from '../../modules/user'; | ||
5 | +const HeaderContainer = () => { | ||
6 | + const { user } = useSelector(({ user }) => ({ user: user.user })); | ||
7 | + const dispatch = useDispatch(); | ||
8 | + const onLogout = () => { | ||
9 | + dispatch(logout()); | ||
10 | + }; | ||
11 | + return <Header user={user} onLogout={onLogout} />; | ||
12 | +}; | ||
13 | +export default HeaderContainer; |
... | @@ -5,6 +5,24 @@ body { | ... | @@ -5,6 +5,24 @@ body { |
5 | sans-serif; | 5 | sans-serif; |
6 | -webkit-font-smoothing: antialiased; | 6 | -webkit-font-smoothing: antialiased; |
7 | -moz-osx-font-smoothing: grayscale; | 7 | -moz-osx-font-smoothing: grayscale; |
8 | + box-sizing: border-box; | ||
9 | + min-height: 100%; | ||
10 | +} | ||
11 | + | ||
12 | +#root { | ||
13 | + min-height: 100%; | ||
14 | +} | ||
15 | + | ||
16 | +html { | ||
17 | + height: 100%; | ||
18 | +} | ||
19 | + | ||
20 | +a { | ||
21 | + color: inherit; | ||
22 | + text-decoration: none; | ||
23 | +} | ||
24 | +* { | ||
25 | + box-sizing: inherit; | ||
8 | } | 26 | } |
9 | 27 | ||
10 | code { | 28 | code { | ... | ... |
... | @@ -3,12 +3,41 @@ import ReactDOM from 'react-dom'; | ... | @@ -3,12 +3,41 @@ import ReactDOM from 'react-dom'; |
3 | import './index.css'; | 3 | import './index.css'; |
4 | import App from './App'; | 4 | import App from './App'; |
5 | import * as serviceWorker from './serviceWorker'; | 5 | import * as serviceWorker from './serviceWorker'; |
6 | +import { BrowserRouter } from 'react-router-dom'; | ||
7 | +import { Provider } from 'react-redux'; | ||
8 | +import { createStore, applyMiddleware } from 'redux'; | ||
9 | +import { composeWithDevTools } from 'redux-devtools-extension'; | ||
10 | +import createSagaMiddleware from 'redux-saga'; | ||
11 | +import rootReducer, { rootSaga } from './modules'; | ||
12 | +import { tempSetUser, check } from './modules/user'; | ||
13 | + | ||
14 | +const sagaMiddleware = createSagaMiddleware(); | ||
15 | +const store = createStore( | ||
16 | + rootReducer, | ||
17 | + composeWithDevTools(applyMiddleware(sagaMiddleware)), | ||
18 | +); | ||
19 | + | ||
20 | +function loadUser() { | ||
21 | + try { | ||
22 | + const user = localStorage.getItem('user'); | ||
23 | + if (!user) return; | ||
24 | + | ||
25 | + store.dispatch(tempSetUser(user)); | ||
26 | + store.dispatch(check()); | ||
27 | + } catch (e) { | ||
28 | + console.log('localStorage is not working'); | ||
29 | + } | ||
30 | +} | ||
31 | +sagaMiddleware.run(rootSaga); | ||
32 | +loadUser(); | ||
6 | 33 | ||
7 | ReactDOM.render( | 34 | ReactDOM.render( |
8 | - <React.StrictMode> | 35 | + <Provider store={store}> |
9 | - <App /> | 36 | + <BrowserRouter> |
10 | - </React.StrictMode>, | 37 | + <App /> |
11 | - document.getElementById('root') | 38 | + </BrowserRouter> |
39 | + </Provider>, | ||
40 | + document.getElementById('root'), | ||
12 | ); | 41 | ); |
13 | 42 | ||
14 | // If you want your app to work offline and load faster, you can change | 43 | // If you want your app to work offline and load faster, you can change | ... | ... |
jaksimsamil-page/src/lib/api/auth.js
0 → 100644
1 | +import client from './client'; | ||
2 | + | ||
3 | +export const login = ({ username, password }) => | ||
4 | + client.post('api/auth/login', { username, password }); | ||
5 | + | ||
6 | +export const register = ({ username, password }) => | ||
7 | + client.post('api/auth/register', { username, password }); | ||
8 | + | ||
9 | +export const check = () => client.get('api/auth/check'); | ||
10 | + | ||
11 | +export const logout = () => client.post('/api/auth/logout'); |
jaksimsamil-page/src/lib/api/client.js
0 → 100644
1 | +import { call, put } from 'redux-saga/effects'; | ||
2 | +import { startLoading, finishLoading } from '../modules/loading'; | ||
3 | + | ||
4 | +export const createRequestActionTypes = (type) => { | ||
5 | + const SUCCESS = `${type}_SUCCESS`; | ||
6 | + const FAILURE = `${type}_FAILURE`; | ||
7 | + return [type, SUCCESS, FAILURE]; | ||
8 | +}; | ||
9 | + | ||
10 | +export default function createRequestSaga(type, request) { | ||
11 | + const SUCCESS = `${type}_SUCCESS`; | ||
12 | + const FAILURE = `${type}_FAILURE`; | ||
13 | + | ||
14 | + return function* (action) { | ||
15 | + yield put(startLoading(type)); | ||
16 | + try { | ||
17 | + const response = yield call(request, action.payload); | ||
18 | + yield put({ | ||
19 | + type: SUCCESS, | ||
20 | + payload: response.data, | ||
21 | + }); | ||
22 | + } catch (e) { | ||
23 | + yield put({ | ||
24 | + type: FAILURE, | ||
25 | + payload: e, | ||
26 | + error: true, | ||
27 | + }); | ||
28 | + } | ||
29 | + yield put(finishLoading(type)); | ||
30 | + }; | ||
31 | +} |
jaksimsamil-page/src/lib/styles/palette.js
0 → 100644
1 | +// source: https://yeun.github.io/open-color/ | ||
2 | + | ||
3 | +const palette = { | ||
4 | + gray: [ | ||
5 | + '#f8f9fa', | ||
6 | + '#f1f3f5', | ||
7 | + '#e9ecef', | ||
8 | + '#dee2e6', | ||
9 | + '#ced4da', | ||
10 | + '#adb5bd', | ||
11 | + '#868e96', | ||
12 | + '#495057', | ||
13 | + '#343a40', | ||
14 | + '#212529', | ||
15 | + ], | ||
16 | + cyan: [ | ||
17 | + '#e3fafc', | ||
18 | + '#c5f6fa', | ||
19 | + '#99e9f2', | ||
20 | + '#66d9e8', | ||
21 | + '#3bc9db', | ||
22 | + '#22b8cf', | ||
23 | + '#15aabf', | ||
24 | + '#1098ad', | ||
25 | + '#0c8599', | ||
26 | + '#0b7285', | ||
27 | + ], | ||
28 | +}; | ||
29 | + | ||
30 | +export default palette; |
jaksimsamil-page/src/logo.svg
deleted
100644 → 0
1 | -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"> | ||
2 | - <g fill="#61DAFB"> | ||
3 | - <path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/> | ||
4 | - <circle cx="420.9" cy="296.5" r="45.7"/> | ||
5 | - <path d="M520.5 78.1z"/> | ||
6 | - </g> | ||
7 | -</svg> |
jaksimsamil-page/src/modules/auth.js
0 → 100644
1 | +import { createAction, handleActions } from 'redux-actions'; | ||
2 | +import produce from 'immer'; | ||
3 | +import { takeLatest } from 'redux-saga/effects'; | ||
4 | +import createRequestSaga, { | ||
5 | + createRequestActionTypes, | ||
6 | +} from '../lib/createRequestSaga'; | ||
7 | +import * as authAPI from '../lib/api/auth'; | ||
8 | +const CHAGE_FIELD = 'auth/CHANGE_FIELD'; | ||
9 | +const INITIALIZE_FORM = 'auth/INITIALIZE_FORM'; | ||
10 | + | ||
11 | +const REGISTER = 'auth/REGISTER'; | ||
12 | +const REGISTER_SUCCESS = 'auth/REGISTER_SUCCESS'; | ||
13 | +const REGISTER_FAILURE = 'auth/REGISTER_FAILURE'; | ||
14 | + | ||
15 | +const LOGIN = 'auth/LOGIN'; | ||
16 | +const LOGIN_SUCCESS = 'auth/LOGIN_SUCCESS'; | ||
17 | +const LOGIN_FAILURE = 'auth/LOGIN_FAILURE'; | ||
18 | + | ||
19 | +export const changeField = createAction( | ||
20 | + CHAGE_FIELD, | ||
21 | + ({ form, key, value }) => ({ | ||
22 | + form, | ||
23 | + key, | ||
24 | + value, | ||
25 | + }), | ||
26 | +); | ||
27 | +export const initializeForm = createAction(INITIALIZE_FORM, (form) => form); | ||
28 | + | ||
29 | +const initalState = { | ||
30 | + register: { | ||
31 | + username: '', | ||
32 | + password: '', | ||
33 | + passwordConfirm: '', | ||
34 | + }, | ||
35 | + login: { | ||
36 | + username: '', | ||
37 | + password: '', | ||
38 | + }, | ||
39 | + auth: null, | ||
40 | + authError: null, | ||
41 | +}; | ||
42 | + | ||
43 | +export const register = createAction(REGISTER, ({ username, password }) => ({ | ||
44 | + username, | ||
45 | + password, | ||
46 | +})); | ||
47 | +export const login = createAction(LOGIN, ({ username, password }) => ({ | ||
48 | + username, | ||
49 | + password, | ||
50 | +})); | ||
51 | + | ||
52 | +const registerSaga = createRequestSaga(REGISTER, authAPI.register); | ||
53 | +const loginSaga = createRequestSaga(LOGIN, authAPI.login); | ||
54 | + | ||
55 | +export function* authSaga() { | ||
56 | + yield takeLatest(REGISTER, registerSaga); | ||
57 | + yield takeLatest(LOGIN, loginSaga); | ||
58 | +} | ||
59 | + | ||
60 | +const auth = handleActions( | ||
61 | + { | ||
62 | + [CHAGE_FIELD]: (state, { payload: { form, key, value } }) => | ||
63 | + produce(state, (draft) => { | ||
64 | + draft[form][key] = value; | ||
65 | + }), | ||
66 | + [INITIALIZE_FORM]: (state, { payload: form }) => ({ | ||
67 | + ...state, | ||
68 | + [form]: initalState[form], | ||
69 | + authError: null, | ||
70 | + }), | ||
71 | + [REGISTER_SUCCESS]: (state, { payload: auth }) => ({ | ||
72 | + ...state, | ||
73 | + authError: null, | ||
74 | + auth, | ||
75 | + }), | ||
76 | + [REGISTER_FAILURE]: (state, { payload: error }) => ({ | ||
77 | + ...state, | ||
78 | + authError: error, | ||
79 | + }), | ||
80 | + [LOGIN_SUCCESS]: (state, { payload: auth }) => ({ | ||
81 | + ...state, | ||
82 | + authError: null, | ||
83 | + auth, | ||
84 | + }), | ||
85 | + [LOGIN_FAILURE]: (state, { payload: error }) => ({ | ||
86 | + ...state, | ||
87 | + authError: error, | ||
88 | + }), | ||
89 | + }, | ||
90 | + initalState, | ||
91 | +); | ||
92 | + | ||
93 | +export default auth; |
jaksimsamil-page/src/modules/index.js
0 → 100644
1 | +import { combineReducers } from 'redux'; | ||
2 | +import { all } from 'redux-saga/effects'; | ||
3 | +import auth, { authSaga } from './auth'; | ||
4 | +import loading from './loading'; | ||
5 | +import user, { userSaga } from './user'; | ||
6 | + | ||
7 | +const rootReducer = combineReducers({ | ||
8 | + auth, | ||
9 | + loading, | ||
10 | + user, | ||
11 | +}); | ||
12 | + | ||
13 | +export function* rootSaga() { | ||
14 | + yield all([authSaga(), userSaga()]); | ||
15 | +} | ||
16 | + | ||
17 | +export default rootReducer; |
jaksimsamil-page/src/modules/loading.js
0 → 100644
1 | +import { createAction, handleActions } from 'redux-actions'; | ||
2 | + | ||
3 | +const START_LOADING = 'loading/START_LOADING'; | ||
4 | +const FINISH_LOADING = 'loading/FINISH_LOADING'; | ||
5 | + | ||
6 | +export const startLoading = createAction( | ||
7 | + START_LOADING, | ||
8 | + (requestType) => requestType, | ||
9 | +); | ||
10 | + | ||
11 | +export const finishLoading = createAction( | ||
12 | + FINISH_LOADING, | ||
13 | + (requestType) => requestType, | ||
14 | +); | ||
15 | + | ||
16 | +const initialState = {}; | ||
17 | + | ||
18 | +const loading = handleActions( | ||
19 | + { | ||
20 | + [START_LOADING]: (state, action) => ({ | ||
21 | + ...state, | ||
22 | + [action.payload]: true, | ||
23 | + }), | ||
24 | + [FINISH_LOADING]: (state, action) => ({ | ||
25 | + ...state, | ||
26 | + [action.payload]: false, | ||
27 | + }), | ||
28 | + }, | ||
29 | + initialState, | ||
30 | +); | ||
31 | + | ||
32 | +export default loading; |
jaksimsamil-page/src/modules/user.js
0 → 100644
1 | +import { createAction, handleActions } from 'redux-actions'; | ||
2 | +import { takeLatest, call } from 'redux-saga/effects'; | ||
3 | +import * as authAPI from '../lib/api/auth'; | ||
4 | +import createRequestSaga, { | ||
5 | + createRequestActionTypes, | ||
6 | +} from '../lib/createRequestSaga'; | ||
7 | + | ||
8 | +const TEMP_SET_USER = 'user/TEMP_SET_USER'; | ||
9 | +const [CHECK, CHECK_SUCCESS, CHECK_FAILURE] = createRequestActionTypes( | ||
10 | + 'user/CHECK', | ||
11 | +); | ||
12 | +const LOGOUT = 'user/LOGOUT'; | ||
13 | + | ||
14 | +export const tempSetUser = createAction(TEMP_SET_USER, (user) => user); | ||
15 | +export const check = createAction(CHECK); | ||
16 | +export const logout = createAction(LOGOUT); | ||
17 | +const checkSaga = createRequestSaga(CHECK, authAPI.check); | ||
18 | +function checkFailureSaga() { | ||
19 | + try { | ||
20 | + localStorage.removeItem('user'); | ||
21 | + } catch (e) { | ||
22 | + console.log('localStroage is not working'); | ||
23 | + } | ||
24 | +} | ||
25 | +function* logoutSaga() { | ||
26 | + try { | ||
27 | + yield call(authAPI.logout); | ||
28 | + console.log('logout'); | ||
29 | + localStorage.removeItem('user'); | ||
30 | + } catch (e) { | ||
31 | + console.log(e); | ||
32 | + } | ||
33 | +} | ||
34 | +export function* userSaga() { | ||
35 | + yield takeLatest(CHECK, checkSaga); | ||
36 | + yield takeLatest(CHECK_FAILURE, checkFailureSaga); | ||
37 | + yield takeLatest(LOGOUT, logoutSaga); | ||
38 | +} | ||
39 | + | ||
40 | +const initialState = { | ||
41 | + user: null, | ||
42 | + checkError: null, | ||
43 | +}; | ||
44 | + | ||
45 | +export default handleActions( | ||
46 | + { | ||
47 | + [TEMP_SET_USER]: (state, { payload: user }) => ({ | ||
48 | + ...state, | ||
49 | + user, | ||
50 | + }), | ||
51 | + [CHECK_SUCCESS]: (state, { payload: user }) => ({ | ||
52 | + ...state, | ||
53 | + user, | ||
54 | + checkError: null, | ||
55 | + }), | ||
56 | + [CHECK_FAILURE]: (state, { payload: error }) => ({ | ||
57 | + ...state, | ||
58 | + user: null, | ||
59 | + checkError: error, | ||
60 | + }), | ||
61 | + [LOGOUT]: (state) => ({ | ||
62 | + ...state, | ||
63 | + user: null, | ||
64 | + }), | ||
65 | + }, | ||
66 | + initialState, | ||
67 | +); |
jaksimsamil-page/src/pages/HomePage.js
0 → 100644
1 | +import React from 'react'; | ||
2 | +import HeaderContainer from '../containers/common/HeaderContainer'; | ||
3 | +import Button from '../components/common/Button'; | ||
4 | + | ||
5 | +const HomePage = () => { | ||
6 | + return ( | ||
7 | + <div> | ||
8 | + <HeaderContainer /> | ||
9 | + <Button>test</Button> | ||
10 | + </div> | ||
11 | + ); | ||
12 | +}; | ||
13 | + | ||
14 | +export default HomePage; |
jaksimsamil-page/src/pages/LoginPage.js
0 → 100644
1 | +import React from 'react'; | ||
2 | +import AuthTemplate from '../components/auth/AuthTemplate'; | ||
3 | +import LoginForm from '../containers/auth/LoginForm'; | ||
4 | + | ||
5 | +const LoginPage = () => { | ||
6 | + return ( | ||
7 | + <AuthTemplate> | ||
8 | + <LoginForm type="login" /> | ||
9 | + </AuthTemplate> | ||
10 | + ); | ||
11 | +}; | ||
12 | + | ||
13 | +export default LoginPage; |
jaksimsamil-page/src/pages/RegisterPage.js
0 → 100644
1 | +import React from 'react'; | ||
2 | +import AuthTemplate from '../components/auth/AuthTemplate'; | ||
3 | +import RegisterForm from '../containers/auth/RegisterForm'; | ||
4 | + | ||
5 | +const RegisterPage = () => { | ||
6 | + return ( | ||
7 | + <AuthTemplate> | ||
8 | + <RegisterForm type="register" /> | ||
9 | + </AuthTemplate> | ||
10 | + ); | ||
11 | +}; | ||
12 | + | ||
13 | +export default RegisterPage; |
This diff could not be displayed because it is too large.
... | @@ -32,6 +32,6 @@ | ... | @@ -32,6 +32,6 @@ |
32 | | profile | 추천 문제 조회 | GET | api/profile/recommend:id | 바로가기 | None | | 32 | | profile | 추천 문제 조회 | GET | api/profile/recommend:id | 바로가기 | None | |
33 | | notify | 슬랙 메시지 전송 요청 | POST | api/notify/slack | 바로가기 | Jwt Token | | 33 | | notify | 슬랙 메시지 전송 요청 | POST | api/notify/slack | 바로가기 | Jwt Token | |
34 | | auth | 로그인 | POST | api/auth/login | 바로가기 | None | | 34 | | auth | 로그인 | POST | api/auth/login | 바로가기 | None | |
35 | -| auth | 로그아웃 | GET | api/auth/logout | 바로가기 | JWT Token | | 35 | +| auth | 로그아웃 | POST | api/auth/logout | 바로가기 | JWT Token | |
36 | | auth | 회원가입 | POST | api/auth/register | 바로가기 | None | | 36 | | auth | 회원가입 | POST | api/auth/register | 바로가기 | None | |
37 | | auth | 로그인 확인 | GET | api/auth/check | 바로가기 | None | | 37 | | auth | 로그인 확인 | GET | api/auth/check | 바로가기 | None | | ... | ... |
... | @@ -40,7 +40,7 @@ exports.register = async (ctx) => { | ... | @@ -40,7 +40,7 @@ exports.register = async (ctx) => { |
40 | ctx.body = user.serialize(); | 40 | ctx.body = user.serialize(); |
41 | 41 | ||
42 | const token = user.generateToken(); | 42 | const token = user.generateToken(); |
43 | - ctx.cookies.set("acces_token", token, { | 43 | + ctx.cookies.set("access_token", token, { |
44 | //3일동안 유효 | 44 | //3일동안 유효 |
45 | maxAge: 1000 * 60 * 60 * 24 * 3, | 45 | maxAge: 1000 * 60 * 60 * 24 * 3, |
46 | httpOnly: true, | 46 | httpOnly: true, |
... | @@ -75,7 +75,7 @@ exports.login = async (ctx) => { | ... | @@ -75,7 +75,7 @@ exports.login = async (ctx) => { |
75 | } | 75 | } |
76 | ctx.body = user.serialize(); | 76 | ctx.body = user.serialize(); |
77 | const token = user.generateToken(); | 77 | const token = user.generateToken(); |
78 | - ctx.cookies.set("acces_token", token, { | 78 | + ctx.cookies.set("access_token", token, { |
79 | //7일동안 유효 | 79 | //7일동안 유효 |
80 | maxAge: 1000 * 60 * 60 * 24 * 7, | 80 | maxAge: 1000 * 60 * 60 * 24 * 7, |
81 | httpOnly: true, | 81 | httpOnly: true, |
... | @@ -88,6 +88,7 @@ exports.login = async (ctx) => { | ... | @@ -88,6 +88,7 @@ exports.login = async (ctx) => { |
88 | GET api/auth/check | 88 | GET api/auth/check |
89 | */ | 89 | */ |
90 | exports.check = async (ctx) => { | 90 | exports.check = async (ctx) => { |
91 | + console.log(ctx.state); | ||
91 | const { user } = ctx.state; | 92 | const { user } = ctx.state; |
92 | if (!user) { | 93 | if (!user) { |
93 | ctx.status = 401; | 94 | ctx.status = 401; | ... | ... |
... | @@ -2,7 +2,8 @@ const Router = require("koa-router"); | ... | @@ -2,7 +2,8 @@ const Router = require("koa-router"); |
2 | const auth = new Router(); | 2 | const auth = new Router(); |
3 | const authCtrl = require("./auth.ctrl"); | 3 | const authCtrl = require("./auth.ctrl"); |
4 | auth.post("/login", authCtrl.login); | 4 | auth.post("/login", authCtrl.login); |
5 | -auth.get("/logout", authCtrl.logout); | 5 | +auth.post("/logout", authCtrl.logout); |
6 | auth.post("/register", authCtrl.register); | 6 | auth.post("/register", authCtrl.register); |
7 | +auth.get("/check", authCtrl.check); | ||
7 | 8 | ||
8 | module.exports = auth; | 9 | module.exports = auth; | ... | ... |
1 | const jwt = require("jsonwebtoken"); | 1 | const jwt = require("jsonwebtoken"); |
2 | const User = require("../models/user"); | 2 | const User = require("../models/user"); |
3 | + | ||
3 | const jwtMiddleware = async (ctx, next) => { | 4 | const jwtMiddleware = async (ctx, next) => { |
4 | const token = ctx.cookies.get("access_token"); | 5 | const token = ctx.cookies.get("access_token"); |
6 | + console.log("1"); | ||
7 | + console.log(token); | ||
5 | if (!token) { | 8 | if (!token) { |
6 | - //토큰이 없을 때 | 9 | + console.log("1"); |
7 | return next(); | 10 | return next(); |
8 | } | 11 | } |
9 | try { | 12 | try { |
10 | - const decoded = jwt.verify(token, process.env.JWT_TOKEN); | 13 | + console.log("1"); |
14 | + const decoded = jwt.verify(token, process.env.JWT_SECRET); | ||
11 | ctx.state.user = { | 15 | ctx.state.user = { |
12 | _id: decoded._id, | 16 | _id: decoded._id, |
13 | username: decoded.username, | 17 | username: decoded.username, |
14 | }; | 18 | }; |
15 | - //토큰의 남은 유효 기간이 2일 이하라면 재발급 | 19 | + const now = Math.floor(Date.now() / 1000); |
16 | - if (decoded.exp - Date.now() / 1000 < 60 * 60 * 24 * 2) { | 20 | + if (decoded.exp - now < 60 * 60 * 24 * 3.5) { |
17 | const user = await User.findById(decoded._id); | 21 | const user = await User.findById(decoded._id); |
18 | const token = user.generateToken(); | 22 | const token = user.generateToken(); |
19 | ctx.cookies.set("access_token", token, { | 23 | ctx.cookies.set("access_token", token, { |
20 | - maxAge: 1000 * 60 * 60 * 24 * 7, | 24 | + maxAge: 1000 * 60 * 60 * 24 * 7, //7days |
21 | httpOnly: true, | 25 | httpOnly: true, |
22 | }); | 26 | }); |
23 | } | 27 | } |
28 | + console.log(decoded); | ||
24 | return next(); | 29 | return next(); |
25 | } catch (e) { | 30 | } catch (e) { |
26 | return next(); | 31 | return next(); |
27 | } | 32 | } |
28 | }; | 33 | }; |
29 | - | ||
30 | module.exports = jwtMiddleware; | 34 | module.exports = jwtMiddleware; | ... | ... |
-
Please register or login to post a comment