一个关于vue+mysql+express的全栈项目(三)------ 登录注册功能的实现(已经密码安全的设计)
本系列文章,主要是一个前端的视角来实现一些后端的功能,所以不会讲太多的前端东西,主要是分享做这个项目学到的一些东西,,,,,
好了闲话不多说,我们开始搭建后端服务,这里我们采用node的express框架来做我们的后端服务
这里是官网地址:express
一、安装express框架
npm install express --save
二、先写一个测试的接口
在根目录下新建一个server的文件夹,并新建一个server.js
1 const express = require('express') 2 3 const app = express() 4 5 const Router = express.Router() 6 7 Router.get('/test', function(req, res) { 8 return res.json({ 9 code: 0, 10 data: 'hello world!' 11 }) 12 }) 13 14 app.use('/testRouter', Router) 15 16 app.listen(3001, function() { 17 console.log('express server is success') 18 });
接下来我们在node环境中运行server.js
打开浏览器,输入localhost://3001/testRouter/test;可以看到以下结果
接下来就是安装mysql,具体安装参照百度
三,使用node做为服务端,来操作数据库的话,我们最好选用一个orm,这样可以方便我们更好的操作数据库,想基于MongoDB有mongoose;mysql有sequelize
这里因为我们的数据库选用的是mysql,那么我们就选择sequelize,首先安装sequelize
npm install sequelize --save
npm install mysql2 --save
然后打开我们的数据库命令窗口mysql,输入密码,默认密码为root
创建一个数据库
CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name [DEFAULT] CHARACTER SET [=] charset_name
{}表示参数必选 | 表示选择一个 []表示参数可选 {DATABASE | SCHEMA}任选其一 [IF NOT EXISTS] 可以忽略创建重复数据库是,系统的报错信息(从而产生一个警告) CHARACTER SET [=] charset_name 指定数据库编码方式(DEFAULT可写可不写)
这里我们简单创建一个数据库vue_chat
CREATE DATABASE vue_chat;
查看数据库,使用:
SHOW DATABASES;
四,使用sequelize链接数据库
在server目录下新建db.js
const Sequelize = require('sequelize'); const sequelize = new Sequelize( 'vue_chat', // 数据库名 'root', // 用户名 'root', // 用户密码 { 'dialect': 'mysql', // 数据库使用mysql 'host': 'localhost', // 数据库服务器ip 'port': 3306, // 数据库服务器端口 'define': { // 字段以下划线(_)来分割(默认是驼峰命名风格) 'underscored': true } } );
新建一个模型(这里模型对应的就是mysql中的表的概念,这里直接使用我之前定义好的模型,不过多解释模型里面的字段(每个人设计模型或者表的思考方式都会有差异,这个东西根据项目来设计))const account = sequelize.define(
// tablename 'account', { 'user_name': { 'type': Sequelize.STRING, 'allowNull': false }, 'pwd': { 'type': Sequelize.STRING, 'allowNull': false }, 'email': { 'type': Sequelize.STRING, 'allowNull': true }, 'avatar': { 'type': Sequelize.STRING, 'allowNull': true }, 'user_info': { 'type': Sequelize.STRING, 'allowNull': true }, 'user_id': { 'type': Sequelize.CHAR(64), 'allowNull': false, 'unique': true }, 'create_temp': { 'type': Sequelize.DATE, 'defaultValue': Sequelize.NOW, }, 'user_fans': { 'type': Sequelize.INTEGER, 'allowNull': false, 'defaultValue': 0 }, 'attention': { 'type': Sequelize.BIGINT, 'allowNull': false, 'defaultValue': 0 }, 'poetry_num': { 'type': Sequelize.BIGINT, 'allowNull': false, 'defaultValue': 0 } } ) account.sync(); sequelize.authenticate().then(() => { console.log('Connection has been established successfully.'); }).catch(err => { console.error('Unable to connect to the database:', err); });
module.exports = sequelize
新建user.js
const express = require('express') const Router = express.Router() const sequelize = require('./db') const account = sequelize.model('account') const utility = require('utility') Router.post('/register', function(req, res) { // 用户注册 const body = req.body.userinfo const {user_name, pwd} = req.body.userinfo const data = { user_name: user_name, pwd: pwdMd5(pwd), create_temp: new Date().getTime(), user_id: pwdMd5(Date.now()) } account.create(data).then(doc => { const {user_name, user_id, user_info, avatar} = doc res.cookie('user_id', user_id) return res.json({ code: 0, data: { user_name: user_name, user_id: user_id, user_info: user_info, avatar: avatar } }) }) }) module.exports = Router
此时我们第一个接口也就是注册接口已经写完,接下来就是前后端联调了
首先先去我们的前端设置请求代理,因为前端服务端口和我们后端服务接口不是同一个,所以存在跨域的问题
在根目录下找到config文件夹,打开index.js文件进行修改
proxyTable: { '/api': { target: 'http://localhost:9094/', changeOrigin: true, pathRewrite: { '^/api': '/' } } },
紧接着,在我们之前新建好的api文件夹下,新建一个account.js
import * as axios from '../common/js/axios' // 用户注册 const register = params => axios.post('/user/register', params) export { register }
五.对接接口
打开store中的action.js
import * as types from './mutation-types' import { Loading } from '../Plugins/index' import { register} from 'api/account' const registerAccount = function ({commit, state}, {userinfo}) { // 用户注册 // 这里返回一个Promise函数,方便在组件中知道当前接口是否请求完成 return new Promise((resolve, reject) => { register({userinfo}).then(res => { if (res.status === 200 && res.data.code === 0) { resolve(res.data.data) } else { reject(new Error()) } }) }) } export { registerAccount, }
这里假设你已经写好了注册的前端的界面,下面是一个简单的注册界面
js交互假设你已经写好了
import { mapActions } from 'vuex' export default { data () { return { blurstate: false, user_name: '', pwd: '' } }, methods: { handlerLogin () { if (!this.user_name) { this.$toast({ state: true, desc: '请输入用户名' }) return } if (!this.pwd) { this.$toast({ state: true, desc: '请输入密码' }) return } let userinfo = { user_name: this.user_name, pwd: this.pwd } this.userLogin({userinfo}).then(res => { if (res.status === 200 && res.data.code === 0) { this.$router.push({path: '/'}) } }) }, toRgister () { this.$router.push({path: '/register'}) }, ...mapActions([ 'userLogin' ]) } }
点击注册,这个时候查看我们的数据库是否已经正确写入数据
切换到我们新建的数据库 use vue_chat; 查看数据表 show tables;
查看数据表结构; desc accounts;
查看数据表中的数据 select * from accounts;
六、登录注册的模型的安全设计
上面的登录注册只是一个简单的数据增删改查,对于用户的数据没有丝毫安全性可言,只要拦截我们的登录注册接口即可拿到我们的用户密码,那么下图就是我们改造后的登录注册模型
如上图这个模型,即使我们的登录接口被拦截了,那么也只能拿到一段MD5的加密字符串,根本无法获取我们真实的密码,而且这个加密串根本也和我们的数据库存的加密串是不一致的,所以根本无法破解