(6.1) 권한주기(Auth State & Private Routes)_
영어쌤이 만드는 회원가입, 인증[CRUD] 만들어욤! 리액트와 파이썬 장고
안녕하세요? 영어쨈 죠니 입니다.
저번 포스팅에선 백엔드에서 토큰을 발급받고 이를 활용해 로그인 등을(백엔드 에서) 구현하는 법과
등록, 로그인 그리고, 토큰을 받고 해당 토큰을 이용하여 보호된 루트들로 접근하는 것을 알아보았습니다.
이번 포스팅에선 로그인, 등록 컴포넌트들로 Interface에 띄울 수 있게 하고, react router를 설치하고, 인증 권한에 따른 페이지 접근 등을 알아봅니다.
로그인을 해야만 서비스 페이지에 접근 및 서비스를 이용 가능하게 하는 것과 같습니다.
- 인증 받은 예정으로 접근해야만 다음의 페이지에 접근해 이후 작업을 진행할 수 있게 하는 것 입니다.
- 또한, 그렇지 않은 상태에서 위의 페이지에 접근을 시도할 시 로그인 페이지로 넘겨줄 것 입니다.
- 이제 시작해 보겠습니다.
(1) React Router 설치하기
- 다음의 명령어로 react router를 설치해 주세요.
$ npm i react-router-dom
- 서버를 재실행 시켜줍니다.
$ npm run dev
(2) /src/components/App.js 수정
- Router 를 위한 기능들 가져오기
- Router와 Switch 태크로 코드 감싸주기(사전작업)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
// App.js
import React, { Component, Fragment } from "react";
import ReactDOM from "react-dom";
import { HashRouter as Router, Route, Switch, Redirect } from "react-router-dom";
import { Provider as Alert Provider } from 'react-alert';
import AlertTemplate from 'react-alert-template-basic';
import Header from "./layout/Header";
import Dashboard from "./leads/Dashboard";
import Alerts from "./layout/Alerts";
import { Provider } from "react-redux";
import store from "../store";
// Alert Options
const alertOptions = {
timeout: 3000,
position: 'top center'
}
class App extends Component {
render() {
return (
<Provider store={store}>
<AlertProvider template={AlertTemplate}
{...alertOptions}>
<Router>
<Fragment>
<Header />
<Alerts />
<div className="container">
<Switch>
<Route exact path="/" component={Dashboard} />
</Switch>
</div>
</Fragment>
</Router>
</AlertProvider>
</Provider>
);
}
}
|
cs |
(3) /src/components/accounts/Register.js 파일 생성 및 작성 시작
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
// Register.js
import React, { Component } from 'react'
import { Link } from "react-router-dom";
export class Register extends Component {
state = {
username: "",
email: "",
password: "",
password2: ""
}
onSubmit = e => {
e.preventDefault();
console.log("submit");
};
onChange = e =>this.setState({ [e.target.name]: e.target.value });
render() {
const { username, email, password, password2 } = this.state;
return (
<div className="col-md-6 m-auto">
<div className="card card-body mt-5">
<h2 className="text-center">Register</h2>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Username</label>
<input
type="text"
className="form-control"
name="username"
onChange={this.onChange}
value={username}
/>
</div>
<div className="form-group">
<label>Email</label>
<input
type="email"
className="form-control"
name="email"
onChange={this.onChange}
value={email}
/>
</div>
<div className="form-group">
<label>Password</label>
<input
type="password"
className="form-control"
name="password"
onChange={this.onChange}
value={password}
/>
</div>
<div className="form-group">
<label>Confirm Password</label>
<input
type="password"
className="form-control"
name="password2"
onChange={this.onChange}
value={password2}
/>
</div>
<div className="form-group">
<button type="submit" className="btn btn-primary">
Register
</button>
</div>
<p>
Already have an account? <Link to="/login">Login</Link>
</p>
</form>
</div>
</div>
)
}
}
export default Register;
|
cs |
(4) /src/components/accounts/Login.js 파일 생성 및 작성 시작
- 다음과 같이 코드를 작성해 줍니다.
- Login.js는 Register.js 와 유사합니다.
- 다음과 같이 Register 폼을 그대로 복사해서 Login.js에 붙여넣은 뒤 로그인 폼으로 수정해 줍니다.
- Register 코드 중 HTML 태그에서 email과 password2 관련 코드들도 제거합니다.
- 그 아래엔 계정이 없을 시 등록(Register) 화면으로 전환을 유도하도록 하는 Interface를 제공할 수 있게 수정합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
// /src/components/accounts/Login.js
import React, { Component } from 'react'
import { Link } from "react-router-dom";
export class Login extends Component {
state = {
username: "",
password: "",
}
onSubmit = e => {
e.preventDefault();
console.log("submit");
};
onChange = e =>this.setState({ [e.target.name]: e.target.value });
render() {
const { username, password } = this.state;
return (
<div className="col-md-6 m-auto">
<div className="card card-body mt-5">
<h2 className="text-center">Login</h2>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Username</label>
<input
type="text"
className="form-control"
name="username"
onChange={this.onChange}
value={username}
/>
</div>
<div className="form-group">
<label>Password</label>
<input
type="password"
className="form-control"
name="password"
onChange={this.onChange}
value={password}
/>
</div>
<div className="form-group">
<button type="submit" className="btn btn-primary">
Login
</button>
</div>
<p>
Do not have an account? <Link to="/register">Register</Link>
</p>
</form>
</div>
</div>
)
}
}
export default Login;
|
cs |
(5) /src/components/App.js 수정
- Register와 Login 기능이 추가되었으니 App.js에도 해당 기능이 추가되었음으 명시합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
// App.js
import React, { Component, Fragment } from "react";
import ReactDOM from "react-dom";
import { HashRouter as Router, Route, Switch, Redirect } from "react-router-dom";
import { Provider as Alert Provider } from 'react-alert';
import AlertTemplate from 'react-alert-template-basic';
import Header from "./layout/Header";
import Dashboard from "./leads/Dashboard";
import Alerts from "./layout/Alerts";
import Login from "./accounts/Login";
import Register from "./account/Register";
import { Provider } from "react-redux";
import store from "../store";
// Alert Options
const alertOptions = {
timeout: 3000,
position: 'top center'
}
class App extends Component {
render() {
return (
<Provider store={store}>
<AlertProvider template={AlertTemplate}
{...alertOptions}>
<Router>
<Fragment>
<Header />
<Alerts />
<div className="container">
<Switch>
<Route exact path="/" component={Dashboard} />
<Route exact path="/register" component={Register} />
<Route exact path="/login" component={Login} />
</Switch>
</div>
</Fragment>
</Router>
</AlertProvider>
</Provider>
);
}
}
|
cs |
(6) /src/components/layout/Header.js 추가 코드 작성
- Header 파일에도 해당 기능들의 위하여 약간의 코드 작업을 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
// Header.js
import React, { Component } from "react";
import { Link } from "react-router-dom";
export class Header extends Component {
render() {
return(
<nav className="navbar navbar-expand-sm navbar-light bg-light">
<button
className="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarTogglerDemo01"
aria-controls="navbarTogglerDemo01"
aria-expanded="false"
aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarTogglerDemo01">
<a className="navbar-brand" href="#">Lead Manager</a>
<ul className="navbar-nav mr-auto mt-2 mt-lg-0">
<li className="nav-item">
<Link to="/register" className="nav-link">Register</Link>
</li>
<li className="nav-item">
<Link to="/login" className="nav-link">Login</Link>
</li>
</ul>
</div>
</nav>
);
}
}
export default Header;
|
cs |
결과화면
- 위의 결과화면과 같이 로그인과 등록 화면과 링크에 대한 작업을 하였습니다.
(7) 인증 폼 크기, 위치 고정시키기
- 화면을 늘렸을 때 인증 폼이 위와 같이 어색하게 늘어나 있는 것을 방지해주면(보기에) 더 좋습니다.
- 간단하게 Header.js 파일에 프레임워크를 적용시킵니다.
- container 클래스를 적용시킬 것 입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
// Header.js
import React, { Component } from "react";
import { Link } from "react-router-dom";
export class Header extends Component {
render() {
return(
<nav className="navbar navbar-expand-sm navbar-light bg-light">
<div className="container">
<button
className="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarTogglerDemo01"
aria-controls="navbarTogglerDemo01"
aria-expanded="false"
aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarTogglerDemo01">
<a className="navbar-brand" href="#">Lead Manager</a>
<ul className="navbar-nav mr-auto mt-2 mt-lg-0">
<li className="nav-item">
<Link to="/register" className="nav-link">Register</Link>
</li>
<li className="nav-item">
<Link to="/login" className="nav-link">Login</Link>
</li>
</ul>
</div>
</div>
</nav>
);
}
}
export default Header;
|
cs |
(8) Auth reducer 추가 _ /src/reducers/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// /leadmanager/frontend/src/reducer/index.js
import { combineReducers } from 'redux';
import leads from './leads';
import errors from "./errors";
import messages from "./messages";
import auth from "./auth";
export default combineReducers({
leads,
errors,
messages,
auth
});
|
cs |
(9) /src/reducers/auth.js 파일 생성 및 작성
- 인증 기능을 위해 다음과 같이 auth reducer 파일을 작성합니다.
- auth reducer 작성을 통해 Redux로 state(상태)를 보내 보여주도록 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// src/reducers/auth.js
const initialState = {
token: localStorage.getItem('token'),
isAuthenticated: null,
isLoading: false,
user: null
}
export default function(state = initialState, action) {
switch(action.type) {
default:
return state;
}
}
|
cs |
결과화면
- 결과는 다음과 같이 redux tool에서 확인할 수 있습니다.
우선 내용이 많이 길어져서 저녁 식사 후 다음 포스팅으로 작성하도록 하겠습니다.
간략하게 다음 내용을 미리 명시해 두도록 하겠습니다.
- 아직까진 Add Lead(data 생성)과 Lead list(data list) 페이지가 숨겨지지 않고 전면에 공개되어 있습니다. 있어서는 안될 일이죠.
- 그래서 당연하지만 인증 받은 계정으로 접속시에만 해당 기능이 가능한 페이지로 넘기도록 작업을 할 것 입니다.
(10) Lead data 생성 화면 숨기기
입니다.