当我们构建一个网站时,经常需要设计一些管理页面来管理网站的不同部分,这些页面只有管理员才能够访问。为了防止其他人访问这些页面,我们需要一些方法来对这些页面进行保护。在这里,我将几种实现这个目标的方式,使用Node.js和React.js。
什么是Node.js和React.js
首先简单介绍一下Node.js和React.js。
Node.js是一个可运行在服务器端的JavaScript运行环境,可以运行JavaScript代码,也可以使用Node.js提供的许多模块进行服务器端开发。
React.js是Facebook开发的一个用于构建用户界面的JavaScript库,通过使用React,我们可以使用组件化的方式构建Web应用程序的用户界面。
通过路由实现页面访问控制
其中一种方式是通过路由实现页面访问控制。具体流程如下:
- 安装需要的包:
npm install express express-session
- 在Node.js的服务器端代码中添加路由:
“`javascript
const express = require(‘express’);
const session = require(‘express-session’);
const app = express();
// session中间件
app.use(session({
secret: ‘mySecret’,
resave: false,
saveUninitialized: true
}));
// 登陆页面
app.get(‘/login’, (req, res) => {
res.send(‘Please login’);
});
// 普通页面
app.get(‘/normal’, (req, res) => {
if (req.session.authenticated) {
res.send(‘This is a normal page’);
} else {
res.redirect(‘/login’);
}
});
// 管理页面
app.get(‘/admin’, (req, res) => {
if (req.session.authenticated && req.session.isAdmin) {
res.send(‘This is an admin page’);
} else {
res.status(401).send(‘Unauthorized’);
}
});
// 登录验证
app.post(‘/login’, (req, res) => {
if (req.body.username === ‘admin’ && req.body.password === ‘admin’) {
req.session.authenticated = true;
req.session.isAdmin = true;
res.redirect(‘/admin’);
} else if (req.body.username && req.body.password) {
req.session.authenticated = true;
res.redirect(‘/normal’);
} else {
res.redirect(‘/login’);
}
});
app.listen(3000, () => {
console.log(‘Server is running at http://localhost:3000’);
});
“`
- 在React.js的前端代码中,使用路由链接到Node.js的服务器代码:
“`javascript
import React from ‘react’;
import { BrowserRouter as Router, Switch, Route, Link, Redirect } from ‘react-router-dom’;
const Login = () => (
Login
);
const Normal = () => (
Normal
This is a normal page
);
const Admin = () => (
Admin
This is an admin page
);
class App extends React.Component {
constructor(props) {
super(props);
this.state = { authenticated: false };
}
componentDidMount() {
fetch('/auth', { credentials: 'include' })
.then(response => response.json())
.then(data => {
if (data.authenticated) {
this.setState({ authenticated: true });
}
});
}
render() {
return (
<div>
<h1>React.js and Node.js Example</h1>
<Router>
<nav>
<ul>
<li><Link to="/normal">Normal Page</Link></li>
<li><Link to="/admin">Admin Page</Link></li>
</ul>
</nav>
<Switch>
<Route exact path="/login" component={Login} />
<Route exact path="/normal" component={Normal} />
<Route exact path="/admin" render={() => (
this.state.authenticated ? (<Admin />) : (<Redirect to="/login" />)
)} />
</Switch>
</Router>
</div>
);
}
}
export default App;
“`
通过路由实现页面访问控制,我们可以设置一个路由,只有在用户已经通过身份验证之后,才可以访问管理页面。如上面的代码所示,我们在“/admin”路由上添加了身份验证的逻辑,只有在用户已经通过身份验证并且是管理员账户才可以访问该路由。
通过JWT实现页面访问控制
另一种方式是通过JWT实现页面访问控制。JWT是一种基于Token的用户身份验证和授权协议,用于在客户端和服务器之间传输安全凭证。
具体流程如下:
- 安装需要的包:
npm install express jsonwebtoken cookie-parser
- 在Node.js的服务器端代码中添加JWT验证功能:
“`javascript
const express = require(‘express’);
const jwt = require(‘jsonwebtoken’);
const cookieParser = require(‘cookie-parser’);
const app = express();
// 配置 cookie-parser 中间件
app.use(cookieParser());
// 登陆页面
app.get(‘/login’, (req, res) => {
const username = req.query.username;
const password = req.query.password;
if (username === 'admin' && password === 'admin') {
const token = jwt.sign({ username: 'admin' }, 'mySecret');
res.cookie('token', token);
res.send('Logged in');
} else {
res.status(401).send('Unauthorized');
}
});
// 普通页面
app.get(‘/normal’, (req, res) => {
const token = req.cookies.token;
if (token) {
try {
jwt.verify(token, 'mySecret');
res.send('This is a normal page');
} catch (err) {
res.status(401).send('Unauthorized');
}
} else {
res.status(401).send('Unauthorized');
}
});
// 管理页面
app.get(‘/admin’, (req, res) => {
const token = req.cookies.token;
if (token) {
try {
const decoded = jwt.verify(token, 'mySecret');
if (decoded.username === 'admin') {
res.send('This is an admin page');
} else {
res.status(401).send('Unauthorized');
}
} catch (err) {
res.status(401).send('Unauthorized');
}
} else {
res.status(401).send('Unauthorized');
}
});
app.listen(3000, () => {
console.log(‘Server is running at http://localhost:3000’);
});
“`
- 在React.js的前端代码中,使用Fetch API将JWT Token发送到Node.js的服务器代码:
“`javascript
import React from ‘react’;
import { BrowserRouter as Router, Switch, Route, Link } from ‘react-router-dom’;
class Login extends React.Component {
state = { username: ”, password: ” };
handleChange = (event) => {
const { name, value } = event.target;
this.setState({ [name]: value });
};
handleSubmit = (event) => {
event.preventDefault();
const tokenEndpoint = '/login?username=' + this.state.username + '&password=' + this.state.password;
fetch(tokenEndpoint)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response;
})
.then(response => { document.cookie = "token=" + response.text(); })
.catch(error => alert("Error occurred: " + error));
}
render() {
const { username, password } = this.state;
return (
<div>
<h2>Login</h2>
<form onSubmit={this.handleSubmit}>
<label htmlFor="username">Username:</label><br />
<input type="text" id="username" name="username" value={username} onChange={this.handleChange} /><br />
<label htmlFor="password">Password:</label><br />
<input type="password" id="password" name="password" value={password} onChange={this.handleChange} /><br /><br />
<input type="submit" value="Submit" />
</form>
</div>
);
}
}
const Normal = () => (
Normal
This is a normal page
);
const Admin = () => (
Admin
This is an admin page
);
class App extends React.Component {
constructor(props) {
super(props);
this.state = { authenticated: false };
}
componentDidMount() {
fetch('/auth', { credentials: 'include' })
.then(response => response.json())
.then(data => {
if (data.authenticated) {
this.setState({ authenticated: true });
}
});
}
render() {
return (
<div>
<h1>React.js and Node.js Example</h1>
<Router>
<nav>
<ul>
<li><Link to="/normal">Normal Page</Link></li>
<li><Link to="/admin">Admin Page</Link></li>
</ul>
</nav>
<Switch>
<Route exact path="/login" component={Login} />
<Route exact path="/normal" component={Normal} />
<Route exact path="/admin" render={() => (
this.state.authenticated ? (<Admin />) : (<Redirect to="/login" />)
)} />
</Switch>
</Router>
</div>
);
}
}
export default App;
“`
通过JWT实现页面访问控制,我们可以将用户身份验证的信息存储在一个JWT Token中,并将其发送到客户端。当用户访问受保护的页面时,客户端将Token发送给服务器进行身份验证,如果验证成功,则可以访问该页面。如上面的代码所示,我们在客户端使用Fetch API向Node.js服务器发送带有用户名和密码的请求,服务器会生成一个JWT Token,并将该Token存储在Cookie中。在后续请求中,客户端将Token从Cookie中读取,并发送到服务器端进行身份验证。