mysql - 即使使用错误的凭据也能成功登录?
问题描述
我对 JavaScript 框架还是很陌生,我仍然对它的很多东西非常不确定。所以我的问题几乎是,当我单击登录表单的提交按钮时,它就像它成功登录一样。虽然在网络响应中检查时,它会说
“无法读取 null 的属性‘密码’”
如果您输入了一个不存在的用户,但是
“玩家不存在。”
输入错误密码时。
来自后端的模型/Players.js
players.post('/login', async (req, res) => {
console.log(req.body);
await Player.findOne({
where: {
username: req.body.username
}
})
.then(player => {
if(bcrypt.compareSync(req.body.password, player.password)) {
let playertoken = jwt.sign(player.dataValues, process.env.SECRET_KEY, { expiresIn: 1440 });
res.json({ playertoken: playertoken });
} else {
res.send("Player does not exist.");
}
})
.catch(err => {
res.send("Error: " + err);
})});
来自前端的 UserFunctions.js
export const login = player => {
return axios
.post('http://localhost:4000/players/login', {
username: player.username,
password: player.password
})
.then(response => {
localStorage.setItem('playertoken', response.data);
return response.data;
})
.catch(err => {
console.log(err);
throw err;
});};
主页.js
import React, { Component } from 'react';
import { login } from '../../UserFunctions'
import './HomePage.css';
class HomePage extends Component {
constructor(props){
super(props);
this.state = {
username: '',
password: '',
errors: {}
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value })
}
onSubmit(e) {
e.preventDefault();
const player = {
username: this.state.username,
password: this.state.password
};
login(player).then(res => {
if (res) {
this.props.history.push('/')
}
})
}
render() {
const nLoggedInText = (
<h4>Please Log in.</h4>
);
const loggedInText = (
<div>
<h4>In here you will be able to track your training progress, match stats and body comparisons.</h4>
<h4>You may now begin tracking your progress have fun!</h4>
</div>
);
const logInForm = (
<div className="row d-flex justify-content-center">
<div className="col-lg-3 rounded border">
<form onSubmit={this.onSubmit} className="m-3">
<div className="form-group">
<label htmlFor="username">Username</label>
<input
className="form-control"
name="username"
placeholder="username"
value={this.state.username}
onChange={this.onChange}
required
/>
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input
className="form-control"
type="password"
name="password"
placeholder="password"
value={this.state.password}
onChange={this.onChange}
required
/>
</div>
<button type="submit" className="btn btn-bulldogs">Log In</button>
</form>
</div>
</div>
);
return (
<div className="container">
<h1 className="nBrand">BULLDOGS</h1>
<h3>Welcome {}!</h3>
{localStorage.playertoken ? loggedInText : nLoggedInText}
{!localStorage.playertoken ? logInForm : null}
</div>
);
}}
export default HomePage;
解决方案
所以我的问题几乎是,当我单击登录表单的提交按钮时,它就像成功登录一样。[即使出现错误。]
我将假设正在发生的事情是您的 UserFunctions.js 正在运行,.then
即使您的服务器发送了错误。当您从服务器发送超出 200-299 范围的错误代码时,Axios 将拒绝请求的承诺。200 是在 express 中发送响应时的默认状态码。我们可以使用 将您的状态代码之一更改为未经授权的 http 状态代码(即 401)res.status(401)
,这基本上告诉您的前端在身份验证时出错了(它也可以用来表示用户未经过身份验证以使用特定资源)。以下是其他有用的状态代码及其含义的列表:Wikipedia's HTTP Status Code List。
对您的代码有帮助的另一种状态是 500 状态代码,它代表内部服务器错误。如果在请求期间发生意外并且服务器无法处理请求,您基本上会发送此消息。
接下来的两件事只是建议,所以请随意采取一粒盐。您收到“无法读取 null 的属性‘密码’”,因为player
inplayer.password
是null
. 这意味着您查找用户 Player.findOne 的调用找不到具有该用户名的用户,因此返回 null。您只需要添加一个检查以查看播放器是否存在。
最后一件事最好不要将意外的内部服务器错误和一般错误对象发送到客户端,而是将它们记录在服务器控制台中并发回一般响应。这主要是出于安全原因。
因此,让我们在您的服务器代码中更改这些内容:
players.post('/login', async (req, res) => {
console.log(req.body);
await Player.findOne({
where: {
username: req.body.username
}
})
.then(player => {
if(player && bcrypt.compareSync(req.body.password, player.password)) {
let playertoken = jwt.sign(player.dataValues, process.env.SECRET_KEY, { expiresIn: 1440 });
res.json({ playertoken: playertoken });
} else {
res.status(401).send("Wrong user password combination.");
}
})
.catch(err => {
console.error(err);
res.status(500).send("Something unexpected happened.");
})});
如果发生错误,您可能还想将错误发送给用户。这可以通过errors
您已经配置的状态来完成。下面的一些代码已经过编辑,只是为了更好地向您突出显示发生了什么变化。
// ...redacted...
class HomePage extends Component {
// ...redacted...
onSubmit(e) {
// ...redacted...
login(player).then(res => {
if (res) {
this.props.history.push('/')
}
})
.catch(err => {
this.setState({
errors: err,
})
})
}
render() {
// ...redacted...
return (
<div className="container">
<h1 className="nBrand">BULLDOGS</h1>
<h3>Welcome {}!</h3>
{this.state && this.state.errors && this.state.errors.message && <h4>Errors: {this.errors.message}}</h4>}
{/* ...redacted */}
</div>
);
}}
export default HomePage;
推荐阅读
- angular - 动态创建的对象发出的 Angular 捕捉事件
- c# - .NET Core 多个 IDbConnection 通过 AddTransient 实现
- javascript - 模态3主要问题
- excel - VBA - 单击按钮时删除 MultiUserEditing
- asp.net-web-api2 - Web Api 路由:找到多个与 URL 匹配的控制器类型
- java - Spring ConstraintValidator vs MultipartFile
- java - 通过java列出hadoop集群中的所有yarn应用
- tensorflow - 在 Google Colaboratory 中保存文件/图片
- ftp - 如何在终端中使用 url 读取远程文件
- angular - 如何创建发出动态请求的 http observable