├── .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 | 
8 |
9 | 刷新
10 | 
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 |
2 |
3 |

4 |
{{ msg }}
5 |
登录 一个小小的测试
6 |
7 |
8 |
9 |
10 |
11 |
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 |
6 |
7 |
Login
8 | {{ress}}
9 |
10 |
data为后台存储的token,此处为了测试,实际应用不必带回
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/components/login.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/components/times.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 | {{ ress }}
8 |
9 |
10 | 返回上一级
11 |
12 |
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 |
--------------------------------------------------------------------------------