1.概述
这个程序的大致功能是通过网页注册,然后服务器将用户信息保存在mongodb中,如果是已经注册的,则服务器在mongodb中根据登录信息搜索,完成登录。
2.服务器端
服务器端需要先安装mongodb,并且运行起来。
a.package.json:
<pre name="code" class="javascript">{
"name":"user-auth-example"
,"version":"0.0.1"
,"dependencies":{
"express":"4.10.6"
,"express-session":"1.9.3"
,"mongodb":"1.4.25"
,"jade":"1.8.2"
,"body-parser":"1.10.0"
}
}
这里使用的都是写改程序时的最新版本。
“mongodb”包是支持nodejs访问mongodb的一系列接口。
b.服务器代码
var express = require('express');
var session = require('express-session');//之前是包括在express中,现在独立出来
var bodyParser = require('body-parser');//之前是包括在express 中,现在独立出来
var mongodb = require('mongodb');
var ObjectID = mongodb.ObjectID;//返回mongodb的_id一个结构,以便于查询
var app = express();
app.use(session(
{secret:'my secret'
,resave:false
,saveUninitialized: true}
));
app.use(bodyParser.urlencoded({ extended: true }));//只有这里是true才能正确解析出user[first]之类的POST信息
app.use(bodyParser.json());//处理客户端传来的参数,并且存储在req.body.user中
app.use(express.static('views'));//防止客户端资源的文件夹
app.set('view engine','jade');//设置HTML解析引擎是jade
app.set('view options',{layout:false});
//db
//初始化服务器(地址、端口)
var dbServer = new mongodb.Server('127.0.0.1',27017);
//连接数据库my-website
new mongodb.Db('my-website',dbServer).open(function(err,client){
if(err){
console.log('error:' + err);
}
console.log('\033[96m + \033[39m connected to mongodb');
//建立集合
app.users = new mongodb.Collection(client,'users');
//建立索引
client.ensureIndex('users','email',function(err){
if(err){
console.log("error:"+err);
throw err;
}
console.log('\033[96m + \033[39m ensured indexes');
});
//监听
app.listen(3000,function(){
console.log('\033[96m + \033[39m app listening on *:3000');
});
//自定义一个中间件,设置authenticated,和me(客户端文件会用到),注意,该中间件每个路由路径都会先调用
app.use(function(req,res,next){
console.log('-------session' );
if(req.session.loggedIn){//登录id是否存在
res.locals.authenticated = true;//给客户端使用的
console.log('req.session.loggedIn=' + req.session.loggedIn);
console.log('typeof='+typeof(req.session.loggedIn));
app.users.findOne(
{"_id":ObjectID(req.session.loggedIn)}//根据id查找
,{fields:{email:1,password:1,first:1,last:1}}//获取字段
,function(err,doc){
console.log('sesson find one callback');
console.log(doc);
if(err)
return next(err);
res.locals.me = doc;//设置变量me
next();
});
}else {
res.locals.authenticated = false;//未登录
next();
}
});
//获取主界面
app.get('/',function(req,res){
console.log("------------/");
res.render('index');
});
//获取登录界面
app.get('/login',function(req,res){
console.log("------------login");
res.render('login');
});
//提交登录信息
app.post('/login',function(req,res){
console.log("------------login post");
console.log("req.body.user:");
console.log(req.body.user);
//查找用户
app.users.findOne(
{email:req.body.user.email,password:req.body.user.password}//邮箱,密码
,{fields:{email:1,password:1}}//读取数据
,function(err,doc){
console.log(doc);
if(err){
console.log('error:'+err);
return next(err);
}
if(!doc){//找不到用户
return res.send('<p>User not found.Go back and try again</p>');
}
//存储登录数据的唯一id(这个_id是mongodb自动设置的)
req.session.loggedIn = doc._id.toString();
res.redirect('/');
});
});
//获取注册页面
app.get('/signup',function(req,res){
console.log("------------signup");
res.render('signup');
});
//提交注册信息
app.post('/signup',function(req,res,next){
console.log("------------signup post");
console.log(req.body.user);
//插入注册数据
app.users.insert(req.body.user,{w:1},function(err,items){
if(err)
return next(err);
console.log('result=');
console.log(items);
//重新登录,并且提供邮件参数
res.redirect('/login/' + items[0].email);
});
});
//获取带参数的登录页面
app.get('/login/:signupEmail',function(req,res){
console.log('----------/login/:signupEmail:');
console.log(req.params.signupEmail);
//登录页面,设置参数给客户端文件调用
res.render('login',{signupEmail:req.params.signupEmail});
});
//获取退出页面
app.get('/logout',function(req,res){
console.log("------------logout");
req.session.loggedIn = null;
//返回主界面
res.redirect('/');
});
});
3.客户端
jade 是一种nodejs体系中流行的模板格式,替代普通的html,有相应的引擎代码。缩进相当于标签的作用,用缩进代替嵌套。
a.layout.Jade
doctype html
html
head
title MongoDB example
body
h1 My first MongoDB app
block content
layout 是把所有jade文件相同的开头提取出来,文件之间用“block content”连接。
b.index.jade
extends ./layout
block content
if (authenticated)
p Welcome back,#{me.first}
a(href="/logout") Logout
else
p Welcome new visitor!
ul
li: a(href="/login") Login
li: a(href="/signup") Signup
如果登陆了(authenticated==ture),就显示欢迎信息和用户的姓氏(me.first),如果没有登录,就显示是个新访问者,显示登录和注册连接,用户可以选择。
c.signup.jade
extends layout
block content
form(action ="/signup",method="POST")
fieldset
legend Sign up
p
label First
input(name='user[first]',type="text")
p
label Last
input(name="user[last]",type="text")
p
label Email
input(name="user[email]",type="text")
p
label Password
input(name="user[password]",type="password")
p
button Submit
p
a(href="/") Go back
注册页面,input 标签的name信息将会被服务器端的bodyParser库转换成req.body中的json格式。
d.login.jade
extends ./layout
block content
if(signupEmail)
p Congratulations on signing up! Please login below.
form(action="/login", method="POST")
fieldset
legend Log in
p
label Email
if(signupEmail)
input(name="user[email]",type="text",value=signupEmail)
else
input(name="user[email]",type="text")
p
label Password
input(name="user[password]",type="password")
p
button Submit
p
a(href="/") Go back
登录界面,如果signupEmail存在,则登录页面显示邮箱信息,否则不显示。
4.运行
a.客户端
主界页面
注册页面
注册成功后转到登录页面
登录成功后转到主页面
b.服务器命令行