7장 Frontend Authentication
안녕하세요? 죠니입니다.
이제 이번 React+Django+Redux Authentication의 마지막 주제가 되겠습니다.
- Login Functionality(로그인 기능)
- Login - get a token (토큰 발급 받기)
- Token 확인이 되어 인증 받기
- Register - 회원가입 하기
바로 시작해 보겠습니다.
(1) /src/actions/types.js
- 로그인 성공, 로그인 실패에 대한 type 추가하기
- Code on Color Scripter
(2) /src/actions/auth.js
- auth.js 파일 내에 로그인 성공, 실패에 대한 코드를 추가합니다.
- 5, 6번째 포스팅에서 진행했던 토큰에 대한 코드와 매우 유사합니다.(복붙 하고 수정하는게 제일 빠름)
- Request Body 추가
- axios 코드 작성
(3) /src/reducers/auth.js
- Login Success, Login Fail 가져오기
- 로그인 실패(Login fail)은 기본적으로 Auth error와 같은 동작을 합니다. 그러므로 auth reducer에선 두 case 모두 같은 동작을 하도록 case 코드(동작이 실행되는 조건을 명시하는 코드)만 추가해 줍니다.
- 로그인에 대한 reducer를 추가 작성합니다.
(4) /src/components/accounts/Login.js
- 이제 우리는 로그인에 관한 동작을 호출하는 것을 작성해야 합니다.
- onSubmit 항목 코드 수정
- login을 했을 때를 위해 render에 redirection 설정해주기
- 결과확인
- 인증받지 않은 정보로 로그인 시도시에는 로그인 실패 메세지 받고 로그인 요청 반려
- 현재는 redux tool로만 보임
- 정상 로그인 // 로그인 성공
- isAuthenticated: true // 인증이 정상적으로 받아졌습니다.
-User 정보입니다.
Codes
이번 포스팅에서 진행한 코드들의 결과물 입니다.
/src/actions/types.js
1
2
3
4
5
6
7
8
9
10
11
|
// /src/actions/types.js
export const GET_LEADS = "GET_LEADS";
export const DELETE_LEAD = "DELETE_LEAD";
export const ADD_LEAD = "ADD_LEAD";
export const GET_ERRORS = "GET_ERRORS";
export const CREATE_MESSAGE = "CREATE_MESSAGE";
export const USER_LOADING = "USER_LOADING";
export const USER_LOADED = "USER_LOADED";
export const AUTH_ERROR = "AUTH_ERROR";
export const LOGIN_SUCCESS = "LOGIN_SUCCESS";
export const LOGIN_FAIL = "LOGIN_FAIL";
|
cs |
/src/components/accounts/Login.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
|
// Login.js
import React, { Component } from "react";
import { Link, Redirect } from "react-router-dom";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import { login } from "../../actions/auth";
export class Login extends Component {
state = {
username: "",
password: "",
};
static propTypes = {
login: PropTypes.func.isRequired,
isAuthenticated: PropTypes.bool
}
onSubmit = e => {
e.preventDefault();
this.props.login(this.state.username,
this.state.password);
};
onChange = e =>this.setState({ [e.target.name]: e.target.value });
render() {
if (this.props.isAuthenticated) {
return <Redirect to="/" />;
}
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>
);
}
}
const mapStateToProps = state => ({
isAuthenticated: state.auth.isAuthenticated
});
export default connect(mapStateToProps, { login })(Login);
|
cs |
/src/reducers/auth.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
|
// src/reducers/auth.js
import {
USER_LOADING,
USER_LOADING,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL
} from '../actions/types';
const initialState = {
token: localStorage.getItem('token'),
isAuthenticated: null,
isLoading: false,
user: null
}
export default function(state = initialState, action) {
switch(action.type) {
case USER_LOADING:
return {
...state,
isLoading: true
}
case USER_LOADED:
return {
...state,
isAuthenticated: treu,
isLoading: false,
user: action.payload
}
case LOGIN_SUCCESS:
localStorage.setItem("token", action.payload.token);
return {
...state
...action.payload,
isAuthenticated: true,
isLoading: false
};
case AUTH_ERROR:
case LOGIN_FAIL:
localStorage.removeItem("token");
return {
...state,
token: null,
user: null,
isAuthenticated: false,
isLoading: false
};
default:
return state;
}
}
|
cs |
/src/actions/auth.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
|
// /src/actions/auth.js
import axios from 'axios';
import { returnErrors } from './messages';
import {
USER_LOADED,
USER_LOADING,
AUTH_ERROR
} from './typs';
// CHECK TOKEN & LOAD USER
export const loader = () => (dispatch, getState) => {
// User Loading
dispatch({ type: USER_LOADING });
// Get token from state
const token = getState().auth.token;
// Headers
const config = {
headers: {
'Content-Type': 'application/json'
}
}
// If token, add to headers config
if(token) {
config.headers['Authorization'] = `Toekn ${token}`;
}
axios.get('/api/auth/user', config)
.then(res => {
dispatch({
type: USER_LOADED,
payload: res.data
});
}).catch(err => {
dispatch(returnErrors(err.response.data,
erro.response.state));
dispatch({
type: AUTH_ERROR
});
});
};
// LOGIN USER
export const login = (username, password) => dispatch => {
// Headers
const config = {
headers: {
'Content-Type': 'application/json'
}
};
// Request Body
const body = JSON.stringify({ username, password });
axios.post('/api/auth/login', body, config)
.then(res => {
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
});
}).catch(err => {
dispatch(returnErrors(err.response.data,
erro.response.state));
dispatch({
type: LOGIN_FAIL
});
});
};
|
cs |
이상입니다.
다음 (7.2)는 로그아웃기능에 대하여 다룰 것 입니다.