├── .babelrc ├── README.md ├── index.html ├── login.gif ├── package.json ├── refresh.gif ├── server ├── app.js ├── bin │ └── www ├── package.json ├── public │ └── stylesheets │ │ └── style.css ├── routes │ ├── index.js │ └── users.js └── views │ ├── error.jade │ ├── index.jade │ └── layout.jade ├── src ├── App.vue ├── assets │ └── logo.png ├── components │ ├── home.vue │ ├── login.vue │ └── times.vue ├── config │ └── index.js ├── main.js └── routers │ └── index.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { "modules": false }] 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | >本项目是vue js框架 + express nodejs后台框架,利用express-session 模块添加session验证机制,session存储不涉及数据库存储,仅需内存存储;可以根据自己的项目需求来自行更改,简单易懂,前后端分离。server目录可单独做为后端项目运行,其他前端框架也适用; 3 | 4 | ## 效果图 5 | 6 |  登录 7 |  ![Alt text](/login.gif) 8 | 9 |  刷新 10 |  ![Alt text](/refresh.gif) 11 | 12 | ## 使用 13 | 这里需要打开两个node窗口,一个允许vue(开发模式)一个运行express 14 | 15 | 1. 运行后台服务 16 | 17 |    a) 进入项目目录中的server目录  
18 |        
cd xx\server
19 |    b) 安装依赖
20 |
npm install
21 |    c)  运行服务
22 |
nodemon bin\www
23 | 24 | 2. 运行vue 25 | 26 | a) 进入项目根目录
27 |
cd  xx
28 |    b) 安装依赖
29 |
npm install
30 | c) 运行服务
31 |
npm run dev
32 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | vue session验证框架 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /login.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chudongvip/vue_express_session_nodb/30c5d3c169e6e6b5cf50b17a46a7b8b0557679b3/login.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue_express_session_nodb", 3 | "description": "A Vue.js project", 4 | "version": "1.0.0", 5 | "author": "MarkC <604748948@qq.com>", 6 | "private": true, 7 | "scripts": { 8 | "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot", 9 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules" 10 | }, 11 | "dependencies": { 12 | "axios": "^0.16.2", 13 | "vue": "^2.4.2", 14 | "vue-router": "^2.7.0" 15 | }, 16 | "devDependencies": { 17 | "babel-core": "^6.25.0", 18 | "babel-loader": "^6.4.1", 19 | "babel-preset-env": "^1.6.0", 20 | "cross-env": "^3.2.4", 21 | "css-loader": "^0.25.0", 22 | "file-loader": "^0.9.0", 23 | "vue-loader": "^12.2.2", 24 | "vue-template-compiler": "^2.4.2", 25 | "webpack": "^2.7.0", 26 | "webpack-dev-server": "^2.7.1" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /refresh.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chudongvip/vue_express_session_nodb/30c5d3c169e6e6b5cf50b17a46a7b8b0557679b3/refresh.gif -------------------------------------------------------------------------------- /server/app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var favicon = require('serve-favicon'); 4 | var logger = require('morgan'); 5 | var cookieParser = require('cookie-parser'); 6 | var bodyParser = require('body-parser'); 7 | // 引用express-session模块 8 | var session = require('express-session'); 9 | 10 | var index = require('./routes/index'); 11 | var users = require('./routes/users'); 12 | 13 | var app = express(); 14 | 15 | // view engine setup 16 | app.set('views', path.join(__dirname, 'views')); 17 | app.set('view engine', 'jade'); 18 | 19 | // uncomment after placing your favicon in /public 20 | //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); 21 | app.use(logger('dev')); 22 | app.use(bodyParser.json()); 23 | app.use(bodyParser.urlencoded({extended: false})); 24 | app.use(cookieParser()); 25 | app.use(express.static(path.join(__dirname, 'public'))); 26 | 27 | /** 28 | * 使用session模块 29 | * 这里不使用数据库存储session, 不使用数据库存储session, 不使用数据库存储session 30 | * 使用内存的session存储 31 | **/ 32 | app.use(session({ 33 | secret: 'demo_test', 34 | name: 'mydemo', //这里的name值得是cookie的name,默认cookie的name是:connect.sid 35 | cookie: { maxAge: 30 * 60 * 1000 }, //设置maxAge是30分钟,即30分钟后session和相应的cookie失效过期 36 | resave: false, // 每次请求都重新设置session cookie 37 | saveUninitialized: true // 无论有没有session cookie,每次请求都设置个session cookie 38 | })); 39 | 40 | /** 41 | * 处理跨域请求,有点重要喔 42 | * 如果不涉及跨域,请忽略 43 | **/ 44 | app.all('*', function (req, res, next) { 45 | res.header('Access-Control-Allow-Origin', req.headers.origin); 46 | res.header('Access-Control-Allow-Credentials', true); 47 | res.header('Access-Control-Allow-Headers', 'Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-with, X_Requested_With'); 48 | res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS'); 49 | res.header('X-Powered-By', '3.2.1'); 50 | res.header('Content-Type', 'application/json; charset=utf-8'); 51 | 52 | if (req.method === 'OPTIONS') { 53 | res.end('options ok'); 54 | } else { 55 | next(); 56 | } 57 | }); 58 | 59 | /** 60 | * 中间件 61 | * 接口请求之后,更新session的时间 62 | * use this middleware to reset cookie expiration time 63 | * when user hit page every time 64 | **/ 65 | app.use(function (req, res, next) { 66 | req.session._garbage = Date(); 67 | req.session.touch(); 68 | next(); 69 | }); 70 | 71 | app.use('/', index); 72 | /** 73 | * 我们的登录就写在这里面 74 | **/ 75 | app.use('/users', users); 76 | 77 | // catch 404 and forward to error handler 78 | app.use(function (req, res, next) { 79 | var err = new Error('Not Found'); 80 | err.status = 404; 81 | next(err); 82 | }); 83 | 84 | // error handler 85 | app.use(function (err, req, res, next) { 86 | // set locals, only providing error in development 87 | res.locals.message = err.message; 88 | res.locals.error = req.app.get('env') === 'development' ? err : {}; 89 | 90 | // render the error page 91 | res.status(err.status || 500); 92 | res.render('error'); 93 | }); 94 | 95 | module.exports = app; 96 | -------------------------------------------------------------------------------- /server/bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('server:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '3000'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www" 7 | }, 8 | "dependencies": { 9 | "body-parser": "~1.17.1", 10 | "cookie-parser": "~1.4.3", 11 | "debug": "~2.6.3", 12 | "express": "~4.15.2", 13 | "express-session": "^1.15.5", 14 | "jade": "~1.11.0", 15 | "morgan": "~1.8.1", 16 | "nodemon": "^1.11.0", 17 | "serve-favicon": "~2.4.2", 18 | "vue-router": "^2.7.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /server/public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } 9 | -------------------------------------------------------------------------------- /server/routes/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | /* GET home page. */ 5 | router.get('/', function(req, res, next) { 6 | res.render('index', { title: 'Express' }); 7 | }); 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /server/routes/users.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | /* GET users listing. */ 5 | router.get('/', function(req, res, next) { 6 | if (req.session.views) { 7 | req.session.views++; 8 | res.send('第 ' + req.session.views + ' 次访问'); 9 | } else { 10 | req.session.views = 1; 11 | res.send('欢迎您,请刷新试试'); 12 | } 13 | }); 14 | 15 | 16 | router.get('/home', function (req, res, next) { 17 | console.log(req.session.id); 18 | if (req.session.token) { 19 | res.send(req.session.token) 20 | } else { 21 | res.send('授权过期重新登录') 22 | } 23 | }); 24 | 25 | /** 26 | * 登录 27 | **/ 28 | router.post('/login', function (req, res) { 29 | let _body = req.body, 30 | _pwd = typeof _body.pwd === 'string' ? _body.pwd : _body.pwd.toString(), 31 | _phone = typeof _body.telphone === 'string' ? _body.telphone : _body.telphone.toString(); 32 | 33 | if (_phone === '' || _phone === undefined) { 34 | res.send({ 35 | code: 3003, 36 | errmsg: '手机号为空' 37 | }); 38 | return 39 | } 40 | 41 | if (_pwd === '' || _pwd === undefined) { 42 | res.send({ 43 | code: 3001, 44 | errmsg: '密码为空' 45 | }); 46 | return 47 | } 48 | 49 | // 查询数据库,比对数据 50 | let phone = '10086'; 51 | let pwd = '123456'; 52 | 53 | if (_phone !== phone) { 54 | res.send({ 55 | code: -1, 56 | errmsg: '账号不存在' 57 | }); 58 | return 59 | } 60 | 61 | if (_pwd !== pwd) { 62 | res.send({ 63 | code: 3004, 64 | errmsg: '密码错误' 65 | }) 66 | } else { 67 | req.session.token = _phone + '_' + redomToken(); 68 | console.log(req.session.token); 69 | res.send({ 70 | code: 200, 71 | token: req.session.token, 72 | errmsg: '登录成功' 73 | }) 74 | } 75 | 76 | function redomToken(len) { 77 | var len = len || 32; 78 | var chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/ 79 | var maxpos = chars.length; 80 | var str = ''; 81 | 82 | for (var i=0; i < len; i++) { 83 | str += chars.charAt(Math.floor(Math.random() * maxpos)) 84 | } 85 | 86 | return str; 87 | } 88 | }); 89 | 90 | /** 91 | * 退出 92 | **/ 93 | router.post('/signout', function (req, res) { 94 | req.session.token = null; 95 | res.send({ 96 | c: 200, 97 | m: '感谢使用!' 98 | }); 99 | }); 100 | 101 | module.exports = router; 102 | -------------------------------------------------------------------------------- /server/views/error.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= message 5 | h2= error.status 6 | pre #{error.stack} 7 | -------------------------------------------------------------------------------- /server/views/index.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= title 5 | p Welcome to #{title} 6 | -------------------------------------------------------------------------------- /server/views/layout.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title= title 5 | link(rel='stylesheet', href='/stylesheets/style.css') 6 | body 7 | block content 8 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 23 | 24 | 52 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chudongvip/vue_express_session_nodb/30c5d3c169e6e6b5cf50b17a46a7b8b0557679b3/src/assets/logo.png -------------------------------------------------------------------------------- /src/components/home.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 14 | 15 | -------------------------------------------------------------------------------- /src/components/login.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | 13 | -------------------------------------------------------------------------------- /src/components/times.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 13 | 14 | -------------------------------------------------------------------------------- /src/config/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Mark.C on 2017/8/16. 3 | */ 4 | /** 5 | * 配置模块 6 | **/ 7 | module.exports = { 8 | Debug: true, 9 | }; -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import axios from 'axios'; 4 | // 引入配置 5 | import config from './config'; 6 | 7 | if (config.Debug) { 8 | axios.defaults.baseURL = 'http://localhost:3000/'; 9 | } else { 10 | 11 | } 12 | 13 | // 请求默认配置 14 | axios.defaults.withCredentials = true; 15 | //全局应用 16 | global.axios = axios; 17 | 18 | // 获取路由实例 19 | import router from './routers'; 20 | 21 | new Vue({ 22 | el: '#app', 23 | router, 24 | render: h => h(App) 25 | }) 26 | -------------------------------------------------------------------------------- /src/routers/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Mark.C on 2017/8/16. 3 | */ 4 | import Vue from 'vue'; 5 | import VueRouter from 'vue-router'; 6 | 7 | Vue.use(VueRouter); 8 | 9 | // 1. 定义路由组件 10 | import Login from '../components/login.vue'; 11 | import Home from '../components/home.vue'; 12 | import Times from '../components/times.vue'; 13 | 14 | // 2. 定义路由 15 | const routes = [ 16 | { path: '/', component: Login }, 17 | { path: '/home', component: Home }, 18 | { path: '/times', component: Times } 19 | ]; 20 | 21 | // 3. 创建路由实例 22 | const router = new VueRouter ({ 23 | mode: 'history', 24 | routes: routes 25 | }); 26 | 27 | export default router; -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | entry: './src/main.js', 6 | output: { 7 | path: path.resolve(__dirname, './dist'), 8 | publicPath: '/dist/', 9 | filename: 'build.js' 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.vue$/, 15 | loader: 'vue-loader', 16 | options: { 17 | loaders: { 18 | } 19 | // other vue-loader options go here 20 | } 21 | }, 22 | { 23 | test: /\.js$/, 24 | loader: 'babel-loader', 25 | exclude: /node_modules/ 26 | }, 27 | { 28 | test: /\.(png|jpg|gif|svg)$/, 29 | loader: 'file-loader', 30 | options: { 31 | name: '[name].[ext]?[hash]' 32 | } 33 | } 34 | ] 35 | }, 36 | resolve: { 37 | alias: { 38 | 'vue$': 'vue/dist/vue.esm.js' 39 | } 40 | }, 41 | devServer: { 42 | historyApiFallback: true, 43 | noInfo: true 44 | }, 45 | performance: { 46 | hints: false 47 | }, 48 | devtool: '#eval-source-map' 49 | } 50 | 51 | if (process.env.NODE_ENV === 'production') { 52 | module.exports.devtool = '#source-map' 53 | // http://vue-loader.vuejs.org/en/workflow/production.html 54 | module.exports.plugins = (module.exports.plugins || []).concat([ 55 | new webpack.DefinePlugin({ 56 | 'process.env': { 57 | NODE_ENV: '"production"' 58 | } 59 | }), 60 | new webpack.optimize.UglifyJsPlugin({ 61 | sourceMap: true, 62 | compress: { 63 | warnings: false 64 | } 65 | }), 66 | new webpack.LoaderOptionsPlugin({ 67 | minimize: true 68 | }) 69 | ]) 70 | } 71 | --------------------------------------------------------------------------------