React에서 JWT(Json 웹 토큰)로 인증 - MERN 인증
49866 단어 webdevjavascriptreact
더 나은 이해를 위해 데모 비디오 및 지원 보기
Source code of this project
코딩을 시작하자...
React 앱 생성 및 의존성 설치
$ npx create-react-app react-auth-jwt
$ cd react-auth-jwt
$ npm install react-router-dom axios @material-ui/core jwt-decode
$ npm start
react-router-dom : 웹 앱에서 경로를 처리할 수 있는 도구
axios : 브라우저와 Node.js를 위한 약속 기반 HTTP 클라이언트입니다.
@material-ui/core (선택 사항) : 아름다운 UI 작성을 쉽게 해줍니다.
jwt-decode : JWT 토큰을 디코딩하는 데 도움이 됩니다.
환경 변수 구성
/.env
REACT_APP_API_URL = http://localhost:8080/api
인증 서비스 구성
/서비스/authServices.js
import axios from "axios";
import jwtDecode from "jwt-decode";
const apiUrl = process.env.REACT_APP_API_URL;
export function login(data) {
return axios.post(`${apiUrl}/auth`, data);
}
export function getCurrentUser() {
try {
const token = localStorage.getItem("token");
return jwtDecode(token);
} catch (error) {
return null;
}
}
export function logout() {
localStorage.removeItem("token");
}
사용자 서비스 구성
/서비스/userServices.js
import axios from "axios";
const apiUrl = process.env.REACT_APP_API_URL;
export function register(data) {
return axios.post(`${apiUrl}/users`, data);
}
App.css
a {
text-decoration: none;
}
.flex {
display: flex;
justify-content: center;
align-items: center;
}
.column {
flex-direction: column;
}
.full_screen {
width: 100vw;
height: 100vh;
}
.form {
display: flex;
flex-direction: column;
width: 300px;
padding: 20px;
}
.form_heading {
font-size: 25px;
font-weight: bold;
text-align: center;
margin-bottom: 15px;
}
.input {
width: 100% !important;
margin: 5px 0 !important;
}
홈 구성 요소
/src/components/Home.jsx
import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import { getCurrentUser } from "../services/authServices";
import { AppBar, Toolbar, Button } from "@material-ui/core";
const Home = () => {
const [user, setUser] = useState("");
useEffect(() => {
setUser(getCurrentUser());
}, []);
return (
<AppBar color="default">
<Toolbar>
<h3 style={{ flexGrow: "1" }}>Domain</h3>
{!user && (
<React.Fragment>
<Link to="/login">
<Button
style={{ marginRight: "10px" }}
variant="outlined"
color="secondary"
>
Login
</Button>
</Link>
<Link to="/signup">
<Button variant="outlined" color="secondary">
Signup
</Button>
</Link>
</React.Fragment>
)}
{user && (
<React.Fragment>
<h4 style={{ marginRight: "15px" }}>{user.name}</h4>
<Link to="/logout">
<Button variant="outlined" color="secondary">
Logout
</Button>
</Link>
</React.Fragment>
)}
</Toolbar>
</AppBar>
);
};
export default Home;
입력 구성 요소
/src/components/common/Input.jsx
import React from "react";
import { TextField } from "@material-ui/core";
const Input = ({ error, ...rest }) => {
return (
<React.Fragment>
{error ? (
<TextField
{...rest}
error
helperText={error}
size="small"
variant="outlined"
className="input"
/>
) : (
<TextField
{...rest}
variant="outlined"
size="small"
className="input"
/>
)}
</React.Fragment>
);
};
export default Input;
양식 구성 요소
/src/components/common/Form.js
import React, { Component } from "react";
import { Button } from "@material-ui/core";
import Input from "./Input";
class Form extends Component {
state = { data: {}, errors: {} };
handleChange = ({ currentTarget: input }) => {
const data = { ...this.state.data };
data[input.name] = input.value;
this.setState({ data });
};
handleSubmit = (event) => {
event.preventDefault();
this.doSubmit();
};
renderInput(name, label, type = "text", required = true) {
const { data, errors } = this.state;
return (
<Input
name={name}
label={label}
type={type}
required={required}
value={data[name]}
error={errors[name]}
onChange={this.handleChange}
/>
);
}
renderSubmitBtn(name) {
return (
<Button
type="submit"
style={{ marginLeft: "auto" }}
variant="outlined"
size="medium"
color="secondary"
>
{name}
</Button>
);
}
}
export default Form;
가입 구성 요소
/src/components/Signup.jsx
import React from "react";
import { Link } from "react-router-dom";
import { register } from "../services/userServices";
import { Paper } from "@material-ui/core";
import Form from "./common/Form";
class Signup extends Form {
state = { data: { name: "", email: "", password: "" }, errors: {} };
doSubmit = async () => {
try {
await register(this.state.data);
this.props.history.push("/login");
} catch (error) {
console.log(error);
}
};
render() {
return (
<form
onSubmit={this.handleSubmit}
className="full_screen flex column"
>
<Paper elevation={3} className="form">
<div className="form_heading">Signup</div>
{this.renderInput("name", "Name")}
{this.renderInput("email", "Email", "email")}
{this.renderInput("password", "Password", "password")}
{this.renderSubmitBtn("Signup")}
</Paper>
<div style={{ margin: "10px 0" }}>
Already have an account? <Link to="/login">Login</Link>
</div>
</form>
);
}
}
export default Signup;
로그인 구성 요소
/src/components/Login.jsx
import React from "react";
import { Link } from "react-router-dom";
import { login } from "../services/authServices";
import { Paper } from "@material-ui/core";
import Form from "./common/Form";
class Login extends Form {
state = { data: { email: "", password: "" }, errors: {} };
doSubmit = async () => {
try {
const { data } = await login(this.state.data);
window.localStorage.setItem("token", data);
window.location = "/";
} catch (error) {
const errors = { ...this.state.errors };
errors.email = error.response.data;
errors.password = error.response.data;
this.setState({ errors });
}
};
render() {
return (
<form
onSubmit={this.handleSubmit}
className="full_screen flex column"
>
<Paper className="form" elevation={3}>
<div className="form_heading">Login</div>
{this.renderInput("email", "Email", "email")}
{this.renderInput("password", "Password", "password")}
{this.renderSubmitBtn("Login")}
</Paper>
<div style={{ margin: "10px 0" }}>
Don't have an account? <Link to="/signup">Signup</Link>
</div>
</form>
);
}
}
export default Login;
로그아웃 구성 요소
/src/components/Logout.jsx
import { useEffect } from "react";
import { logout } from "../services/authServices";
const Logout = () => {
useEffect(() => {
logout();
window.location = "/";
}, []);
return null;
};
export default Logout;
라우터 돔 반응
Index.js에서
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import "./index.css";
import App from "./App";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>,
document.getElementById("root")
);
App.js에서
import {Switch, Route} from 'react-router-dom';
import Home from './components/Home';
import Signup from './components/Signup';
import Login from './components/Login';
import Logout from './components/Logout';
import "./App.css";
function App() {
return (
<Switch>
<Route path="/" exact component={Home} />
<Route path="/signup" component={Signup} />
<Route path="/login" component={Login} />
<Route path="/logout" component={Logout} />
</Switch>
);
}
export default App;
그게 다야 로컬 서버에서 실행하고 앱을 테스트하십시오. 실수를 발견했거나 코드를 개선한 경우 댓글로 알려주세요. 나는 당신이 무언가를 배웠기를 바랍니다.
고맙습니다...
Reference
이 문제에 관하여(React에서 JWT(Json 웹 토큰)로 인증 - MERN 인증), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/cyberwolves/authentication-with-jwt-json-web-token-in-react-mern-auth-caj텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)