nodejs crypto md5MD5 要怎么弄

nodejs与java通用的cbc加密
最近用到nodejs与java之间相互通信,需要用到aes-cbc加密。在网上找到的资料,大多都是基于aes-ecb模式的,关于cbc方面的资料没找到几例有用的。
经过摸索发现,​nodejs使用"aes-128-ecb",java使用"AES/CBC/PKCS5Padding"。
一直不成功的原因,基本上就是密钥出了问题。写法与aes-128-ecb模式类似,字符串密钥转换为Buffer对象。
使用​aes-128-ecb模式,还需要对转换后的Buffer对象,计算MD5值,然后再转换成Buffer对象。
& 这里贴代码太难了,给大家一个传送门。我在oschina上也发了一份。
&NodeJS代码:
var&crypto&=&require("crypto");
function&cbcEncrypt(data,&secretKey,&iv)&{
&secretKey&=&new&Buffer(secretKey,&"utf8");
&secretKey&=&crypto.createHash("md5").update(secretKey).digest("hex");
&secretKey&=&new&Buffer(secretKey,&"hex");
&var&cipher&=&crypto.createCipheriv("aes-128-cbc",&secretKey,&iv),&coder&=&[];
&coder.push(cipher.update(data,&"utf8",&"hex"));
&coder.push(cipher.final("hex"));
&return&coder.join("");
function&cbcDecrypt(data,&secretKey,&iv)&{
&secretKey&=&Buffer(secretKey,&"utf8");
&secretKey&=&crypto.createHash("md5").update(secretKey).digest("hex");
&secretKey&=&new&Buffer(secretKey,&"hex");
&var&cipher&=&crypto.createDecipheriv("aes-128-cbc",&secretKey,&iv),&coder&=&[];
&coder.push(cipher.update(data,&"hex",&"utf8"));
&coder.push(cipher.final("utf8"));
&return&coder.join("");
var&iv&=&new&Buffer("abcdefgh","utf8");
var&key&=&"我是密钥";
var&aes_cbc1&=&cbcEncrypt("hello,我来自nodejs",key,&iv);
var&aes_cbc2&=&cbcDecrypt(aes_cbc1,key,&iv);
console.log("密文:"+&aes_cbc1,"&/&明文:"+aes_cbc2);
var&aes_cbc3&=&cbcDecrypt("a35e0e7ed1c879fcbbe7cf7c3d0ce46",key,&iv);
console.log("明文:"+aes_cbc3);
import&java.security.MessageD
import&java.security.spec.AlgorithmParameterS
import&javax.crypto.C
import&javax.crypto.spec.IvParameterS
import&javax.crypto.spec.SecretKeyS
public&class&test&{
&&public&static&String&cbcEncrypt(String&content,&String&secretKey,&byte[]&iv)&throws&Exception&{
&&&&MessageDigest&md&=&MessageDigest.getInstance("MD5");
&&&&byte[]&thedigest&=&md.digest(secretKey.getBytes("UTF-8"));
&&&&SecretKeySpec&skc&=&new&SecretKeySpec(thedigest,&"AES");
&&&&Cipher&cipher&=&Cipher.getInstance("AES/CBC/PKCS5Padding");
&&&&//算法参数
&&&&AlgorithmParameterSpec&paramSpec&=&new&IvParameterSpec(iv);
&&&&cipher.init(Cipher.ENCRYPT_MODE,&skc,&paramSpec);
&&&&byte[]&input&=&content.getBytes("UTF-8");
&&&&int&len&=&input.
&&&&byte[]&cipherText&=&new&byte[cipher.getOutputSize(len)];
&&&&int&ctLength&=&cipher.update(input,&0,&len,&cipherText,&0);
&&&&ctLength&+=&cipher.doFinal(cipherText,&ctLength);
&&&&return&byte2hex(cipherText);
&&public&static&String&cbcDecrypt(String&encrypted,&String&secretKey,&byte[]&iv)&throws&Exception&{
&&&&MessageDigest&md&=&MessageDigest.getInstance("MD5");
&&&&byte[]&thedigest&=&md.digest(secretKey.getBytes("UTF-8"));
&&&&SecretKeySpec&skey&=&new&SecretKeySpec(thedigest,&"AES");
&&&&Cipher&dcipher&=&Cipher.getInstance("AES/CBC/PKCS5Padding");
&&&&//算法参数
&&&&AlgorithmParameterSpec&paramSpec&=&new&IvParameterSpec(iv);
&&&&dcipher.init(Cipher.DECRYPT_MODE,&skey,&paramSpec);
&&&&byte[]&clearbyte&=&dcipher.doFinal(toByte(encrypted));
&&&&return&new&String(clearbyte);
&&public&static&byte[]&toByte(String&hex)&{
&&&&byte[]&binary&=&new&byte[hex.length()&/&2];
&&&&for&(int&i&=&0,&l&=&binary.&i&&&l;&i++)&{
&&&&&&binary[i]&=&(byte)&Integer.parseInt(hex.substring(2&*&i,&2&*&i&+&2),&16);
&&&&return&
&&public&static&String&byte2hex(byte[]&inStr)&{
&&&&StringBuilder&out&=&new&StringBuilder(inStr.length&*&2);
&&&&for&(int&i&=&0,&l&=&inStr.&i&&&l;&i++)&{
&&&&&&//&字节做"与"运算,去除高位置字节&
&&&&&&if&(((int)&inStr[i]&&&0xff)&&&0x10)&{
&&&&&&&&//小于十前面补零&&
&&&&&&&&out.append("0");
&&&&&&out.append(Long.toString((int)&inStr[i]&&&0xff,&16));
&&&&return&out.toString();
&&public&static&void&main(String[]&args)&{
&&&&&&byte[]&iv&=&"abcdefgh".getBytes("UTF-8");
&&&&&&String&key&=&"我是密钥";
&&&&&&String&enc&=&cbcEncrypt("hello,我来自java",&key,&iv);
&&&&&&System.out.println("1__"&+&enc);
&&&&&&System.out.println("2__"&+&cbcDecrypt(enc,&key,&iv));
&&&&&&//解密来自nodejs的密文
&&&&&&String&node_enc&=&"a35e0e7ed1c879fcbbe7cf6bde7aecdbc";
&&&&&&System.out.println("3__"&+&cbcDecrypt(node_enc,&key,&iv));
&&&&}&catch&(Exception&e)&{
&&&&&&e.printStackTrace();
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。12007人阅读
node.js(46)
MD5加密算法
MD5的全称是Message-Digest Algorithm 5(信息-摘要算法),在90年代初由Mit Laboratory for Computer Science和Rsa data security inc的Ronald l. rivest开发出来,经md2、md3和md4发展而来。它的作用是让大容量信息在用数字签名软件签署私人密匙前被“压缩”成一种保密的格式(就是把一个任意长度的字节串变换成一定长的大整数).不管是md2、md4还是md5,它们都需要获得一个随机长度的信息并产生一个128位的信息摘要.
MD5 算法的哈希值大小为 128 位。是一种不可逆的算法。
两个不同的明文不会得到相同的输出值MD5结果不能反推明文,不可逆
从安全的角度讲,MD5的输出为128位,若采用纯强力攻击寻找一个消息具有给定Hash值的计算困难性为2128,用每秒可试验个消息的计算机需时1.07×1022年。若采用生日攻击法,寻找有相同Hash值的两个消息需要试验264个消息,用每秒可试验个消息的计算机需时585年。
实际应用上,例如我知道‘password’的MD5值是5f4dcc3b5aa765d61d8327deb882cf99,那么我就用一个数据库存起来,只要我看到5f4dcc3b5aa765d61d8327deb882cf99,我就知道这个是口令‘password‘使用MD5处理之后的值,原来的口令就是’password'。MD5在身份鉴别系统中用于口令保护已经是很久了事情了,大部分黑客也有针对这种Hash方式准备相应的数据库进行反查,这种数据库称为彩虹表,MD5的安全性大大减弱。
MD5加密例程
var crypto = require('crypto');
var content = 'password'
var md5 = crypto.createHash('md5');
md5.update(content);
var d = md5.digest('hex');
SHA1的全称是Secure Hash Algorithm(安全哈希算法)。加密哈希函数将任意长度的二进制字符串映射为固定长度的小型二进制字符串。加密哈希函数有这样一个属性:在计算上不大可能找到散列为相同的值的两个不同的输入;也就是说,两组数据的哈希值仅在对应的数据也匹配时才会匹配。数据的少量更改会在哈希值中产生不可预知的大量更改。所以你很难从加密后的文字中找到蛛丝马迹。
SHA1 算法的哈希值大小为 160 位。是一种不可逆的算法。
SHA1加密例程
var crypto = require('crypto');
var content = 'password'
var shasum = crypto.createHash('sha1');
shasum.update(content);
var d = shasum.digest('hex');
MD5与sha1的不同点
MD5 使用小端排序LITTLE-ENDIAN,sha1 使用大端排序BIG-ENDIANMD5最后生成的摘要信息是16个字节,SHA1是20个字节。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:401093次
积分:5061
积分:5061
排名:第3334名
原创:112篇
转载:12篇
评论:79条
(9)(3)(3)(3)(2)(5)(10)(6)(9)(11)(6)(4)(5)(5)(6)(10)(15)(7)(1)(2)(2)Sponsered by
学习使用外部模块
建立一个 lesson2 项目,在其中编写代码。
当在浏览器中访问 http://localhost:3000/?q=alsotang 时,输出 alsotang 的 md5 值,即 bdd5e57b5cda3。
访问 http://localhost:3000/?q=alsotang 时,输出 alsotang 的 sha1 值,即 e3c766dff6a1b9ab9。
学习 req.query 的用法
学习建立 package.json 来管理 Node.js 项目。
卧槽,不写 package.json 就写项目我觉得好不爽啊,所以这个 lesson2 我就得跟大家介绍一下 package.json 这个文件的用法了。
简单说来呢,这个 package.json 文件就是定义了项目的各种元信息,包括项目的名称,git repo 的地址,作者等等。最重要的是,其中定义了我们项目的依赖,这样这个项目在部署时,我们就不必将 node_modules 目录也上传到服务器,服务器在拿到我们的项目时,只需要执行 npm install,则 npm 会自动读取 package.json 中的依赖并安装在项目的 node_modules 下面,然后程序就可以在服务器上跑起来了。
本课程的每个 lesson 里面的示例代码都会带上一份 package.json,大家可以去看看它的大概样子。
我们来新建一个 lesson2 项目,并生成一份它的 package.json。
$ mkdir lesson2 && cd lesson2
$ npm init
OK,这时会要求我们输入一些信息,乱填就好了,反正这个地方也不用填依赖关系。
npm init 这个命令的作用就是帮我们互动式地生成一份最简单的 package.json 文件,init 是 initialize 的意思,初始化。
当乱填信息完毕之后,我们的目录下就会有个 package.json 文件了。
这时我们来安装依赖,这次的应用,我们依赖 express 和 utility 两个模块。
$ npm install express utility --save
这次的安装命令与上节课的命令有两点不同,一是没有指定 registry,没有指定的情况下,默认从 npm 官方安装,上次我们是从淘宝的源安装的。二是多了个 --save 参数,这个参数的作用,就是会在你安装依赖的同时,自动把这些依赖写入 package.json。命令执行完成之后,查看 package.json,会发现多了一个 dependencies 字段,如下图:
这时查看 node_modules 目录,会发现有两个文件夹,分别是 express 和 utility
我们开始写应用层的代码,建立一个 app.js 文件,复制以下代码进去:
// 引入依赖
var express = require('express');
var utility = require('utility');
// 建立 express 实例
var app = express();
app.get('/', function (req, res) {
// 从 req.query 中取出我们的 q 参数。
// 如果是 post 传来的 body 数据,则是在 req.body 里面,不过 express 默认不处理 body 中的信息,需要引入 /expressjs/body-parser 这个中间件才会处理,这个后面会讲到。
// 如果分不清什么是 query,什么是 body 的话,那就需要补一下 http 的知识了
var q = req.query.q;
// 调用 utility.md5 方法,得到 md5 之后的值
// 之所以使用 utility 这个库来生成 md5 值,其实只是习惯问题。每个人都有自己习惯的技术堆栈,
// 我刚入职阿里的时候跟着苏千和朴灵混,所以也混到了不少他们的技术堆栈,仅此而已。
// utility 的 github 地址:/node-modules/utility
// 里面定义了很多常用且比较杂的辅助方法,可以去看看
var md5Value = utility.md5(q);
res.send(md5Value);
app.listen(3000, function (req, res) {
console.log('app is running at port 3000');
OK,运行我们的程序
$ node app.js
访问 http://localhost:3000/?q=alsotang,完成。
如果直接访问 http://localhost:3000/ 会抛错
可以看到,这个错误是从 crypto.js 中抛出的。
这是因为,当我们不传入 q 参数时,req.query.q 取到的值是 undefined,utility.md5 直接使用了这个空值,导致下层的 crypto 抛错。快速使用node.js进行web开发 - 推酷
快速使用node.js进行web开发
首先关于node.js的学习,这里推荐一本比较好的教程,
,该书通俗易懂地将node.js语言特性讲解完之后,又从一个项目角度带领读者使用node.js学习web开发。相信这是一个比较好的学习模式和过程。由于这本书是2012年出的,书中的一个web教学项目是开发一个微博。从2012到现在,node.js及其生态环境发生了很大改变,所以关于该书的学习如果照着书本显然是过于陈旧的。到目前为止,node.js的web开发框架已经升级到了Express4.12.1,对于MongoDB的操作更多是使用mongoose这个对象模型,而不是之前mongoDB 官方提供的原生node.js的API,所以本文将基于nodejsV0.1033 + MongoDBV3.0.2+ Jade1.9.2 + mogooseV4.0.1来重构该书中的微博项目,这个组合也是目前最新的使用node.js进行web开发的常用组合之一,如果需要入门使用node.js进行web开发,正在学习
的和想快速了解node.js web开发模式的朋友,相信本文是有一定帮助意义的。
1.express框架安装
1)在node命令行模式下输入以下命令
npm install -g express
该命令在全局环境下安装express框架,在安装完这一步之后,并不能直接使用express命令来生成express项目,需要再安装一个express项目生成器,在express2.X的版本中是不需要的,express4.X版本之后将项目生成器和express本身分离了出来,如果不安装express-generator这个生成器就使用express命令来生成项目,会遇到报express不是内部或外部命令这个错误,这是需要注意的地方,
原书中是没有安装express-generator这一步的。
2)安装express-generator
npm install -g express-generator
3)生成一个项目
mkdir microblog
cd microblog
express micorblog
这里随意在硬盘某个目录下创建一个microblog的文件夹,进入该文件夹,然后使用express microblog命令创建了一个microblog的express项目。
生成结构如下:
其中app.js是项目入口文件,package.json是npm 包管理文件,bin文件夹里面的www.js放一些全局配置项以及命令行配置等。public 文件夹是用来存放项目静态文件目录如js,css以及图片,routes文件夹是用来存放路由监听的代码相关文件。views文件夹用来存放模板文件,这里需要注意的是express4.X使用jade作为项目的默认模板引擎,而在原书中是使用ejs作为模板引擎的,所以这里默认生成的是jade文件。无可否认ejs是要简单些,但是原理都是一样的,我们使用jade作为开发的模板引擎。
4)启动项目并查看
cd microblog
npm install
进入到microblog文件夹,安装项目所需相关模块(根据pacakge.json文件),然后启动项目,这时候打开浏览器查看项目输入地址localhost:3000,结果如下说明一切正常,
到目前为止,我们已经拥有了一个在浏览器中运行的web项目雏形。下面进行开发,原书中的微博项目的主要功能是用户能够注册登录,权限控制并让用户发布微博在用户个人主页和项目首页分别显示,这些功能
会提供,由于篇幅原因,这里以用户注册登录模块来说明如何进行一个完整流程的web开发。
2.页面布局
依照web开发流程,我们首先来构建一个项目主页,项目主页是由布局文件layout.jade和内容文件index.jade组成,关于的jade的学习,这里提供两个地址,对于以前使用过类似模板引擎如smarty,razor等的,可以看看文档就能够上手做了,基本原理都是大同小异。
,看看这两个教程就基本可以掌握了,关于jade的学习,我认为主要是现学现用,对着文档编写页面即可,当然如果有很多时间也可深入学习。
打开views文件,将layout.jade文件代码改写如下:
doctype html
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
nav.header
a(href='/') Microblog
a(href='/') 首页
a(href='/login') 登录
a(href='/reg') 注册
div.container
block content
footer.footer
a(href='http://myzhibie.coding.io') myzhibie
需要注意父级元素和子元素的换行之间缩进,jade是利用缩进来区别代码层级的。
首页内容文件index.jade
extends layout
block content
section.intro
if message
h3.indexmes #{message}
//如果用户登录或者注册成功并且没有在登录状态下点击注册或者登录
if success&&user
h1.welcome #{success},欢迎 #{user} 来到 Microblog
else if !success&&user
h1.welcome 欢迎 #{user} 来到 Microblog
h1.welcome 欢迎来到 Microblog
h3.tech Microblog是一个基于Node.js,使用express4.12.1,jade1.9.2以及MongoDB搭建起来的微博系统,是对Node.js开发指南一书中教学项目的重构。
a.login(href='/logout') 退出
a.userlink(href='/users/#{user}') 发表文章
a.login(href='/login') 登录
a.register(href='/reg') 立即注册
section.show
each val in posts
article.col
h3.author #{val.user}说
| #{val.post}
首页内容是继承了模板文件layout.jade.原书中使用的bootstrap来构建页面的css布局和样式,这里我自己手写了一个仿bootstrap风格的布局样式,没有应用bootstrap,style.css文件如下:
padding: 50px;
font: 14px &Lucida Grande&, Helvetica, Arial, sans-serif;
html,body,ul,p,hr,h3{
padding: 0;
color: #00B7FF;
background:#337aB7;
width: 100%;
height: 60px;
color: #fff;
font-size: 22px;
overflow: hidden;
line-height: 60px;
.navigation{
overflow: hidden;
list-style: none;
float: left;
display: inline-block;
margin-left: 20px;
margin-right: 20px;
.list li a{
text-decoration: none;
color: #fff;
.list li a:hover{
.list li:not(:first-child) a:hover{
font-size: 26px;
color: #F5F5F5;
font-size: 26px;
font-weight: 700;
.container{
min-height: 500px;
text-align: center;
width: 100%;
width: 100%;
height: 50px;
font-size: 22px;
background:#F5F5F5 ;
line-height: 50px;
.footer a{
color:#337aB7;
text-decoration: none;
color: #000000;
width: 96%;
margin: 30px auto;
width: 100%;
margin:0 auto;
border-radius: 5px;
height: 300px;
background:#F5F5F5 ;
.userintro{
width: 100%;
margin:0 auto;
border-radius: 5px;
height: 200px;
background:#F5F5F5 ;
padding-top: 50px;
padding-left:50px;
font-size: 50px;
text-align: left;
padding-bottom: 0;
margin: 0;
text-align: left;
padding-left:50px;
margin: 0;
overflow: hidden;
width: 100%;
text-align: left;
font-size: 18px;
display: inline-block;
float: left;
width: 32%;
height: 100px;
overflow: hidden;
padding-right: 20px;
text-align: left;
text-overflow: ellipsis;
margin-top: 10px;
margin-bottom: 3px;
padding-left: 50px;
text-align: left;
display: inline-block;
padding-left: 15px;
padding-right: 15px;
height: 38px;
line-height: 40px;
background: -webkit-gradient(linear, left top, left bottom, from(#0068A6), to(#337aB7));
color: #fff;
text-align: center;
border-radius: 5px;
font-size: 20px;
font-weight: 600;
border: 1px solid #ccc;
text-decoration: none;
margin-right: 10px;
.register{
display: inline-block;
padding-left: 15px;
padding-right: 15px;
height: 38px;
line-height: 40px;
background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#F5F5F5));
color: #000;
text-align: center;
border-radius: 5px;
font-size: 20px;
font-weight: 600;
border: 1px solid #ccc;
text-decoration: none;
margin-top: 20px;
margin-left: 50px;
text-align: left;
margin-bottom: 20px;
border:none;
border-bottom: 1px solid #ccc;
font-size: 18px;
font-weight: 600;
line-height: 100%;
display: inline-block;
width: 10%;
vertical-align: middle;
text-align: right;
padding-right: 10px;
.regheader{
text-align: left;
font-size: 24px;
font-weight: 600;
text-align: left;
padding-left: 100px;
margin-bottom: 20px;
.regform input[type='text'],input[type='password']{
width: 200px;
height: 20px;
.regform input[type='submit']{
width: 120px;
height: 30px;
color: #fff;
background:-webkit-gradient(linear, left top, left bottom, from(#0068A6), to(#337aB7));
border-radius: 5px;
font-size: 20px;
margin:20px;
width: 100%;
font-size: 18px;
color: #E73C3C;
background: #F2DEDE;
border-radius: 5px;
width: 300px;
text-align: center;
margin-left: 100px;
.indexmes{
height: 30px;
line-height: 30px;
background: #F2DEDE;
color: #E73C3C;
width: 60%;
height: 30px;
border-radius: 3px;
border: 1px solid #A3C732;
margin-top: 5px;
font-size: 20px;
height: 40px;
vertical-align: middle;
padding: 0;
margin-top: -5px;
margin-left: 5px;
width: 80px;
background: #A3c732;
font-size: 20px;
border: none;
border-radius: 5px;
color: #fff;
.submitform{
margin-top: 25px;
margin-left: -10px;
.userlink{
display: inline-block;
text-decoration: none;
line-height: 38px;
height: 38px;
vertical-align: middle;
padding: 0;
margin-top: -8px;
margin-left: 5px;
width: 90px;
text-align: center;
background: #A3c732;
font-size: 20px;
font-weight: 600;
border-radius: 5px;
color: #fff;
border: 1px solid #ccc;
.usertitle{
text-align: left;
padding-top: 5px;
padding-bottom: 0;
padding-left: 5px;
margin-bottom: 8px;
.usersuccess{
height: 30px;
background: #DFF0D8;
line-height: 30px;
color: #3C7668;
这个css文件是项目中所有的css全部包含在这里,所以比较庞大。到目前为止,可以查看首页效果如下:
首页中的数据都是之前自己测试过程中加入的,这里主要为了查看首页效果,可以忽略这些数据。
由于这里要演示用户注册登录模块,用户注册模块的模板文件reg.jade如下:
extends layout
block content
h3.field.regheader #{title}
form.regform(method='post')
p.mess #{message}
label.label(for='username') 用户名
input(type='text',placeholder='输入注册用户名',id='username',name='username')
label.label(for='password') 用户密码
input(type='password',placeholder='用户密码',id='password',name='password')
label.label(for='passwordconf') 重复密码
input(type='password',placeholder='重复密码',id='passwordconf',name='passwordconf')
label.label
input(type='submit' id='sub',name='sub' value='注册')
用户登陆模板login.jade如下:
extends layout
block content
h3.field.regheader #{title}
form.regform(method='post')
p.mess #{message}
label.label(for='username') 用户名
input(type='text',placeholder='输入登陆用户名',id='username',name='username')
label.label(for='password') 用户密码
input(type='password',placeholder='用户密码',id='password',name='password')
label.label
input(type='submit' id='sub',name='sub' value='登陆')
最终用户注册效果如下:
用户登录模块和这个效果相仿,就不查看了,少了一个重复密码的input而已。
下面我们需要编写用户注册的逻辑,在编写用户注册逻辑的前,用户数据需要持久化,所以首先要安装MongoDB数据库在自己的机器上,关于其安装请参考之前的一篇博文-
MongoDB这种nosql类型的数据库,非常适合用户存储JSON对象类型的数据,有了mongoDB,就可以免去数据库表设计部分的工作,对比以前使用的mysql,sqlserver以及oracle还是非常方便的。关于mongoDB数据库的熟悉和学习,推荐其
,官网详细介绍了该数据库的一切。英文不好可以去
。同时为了使用nodejs来操作mongoDB数据库,我们使用mongoose这个对象模型,它是将mongoDB中的一个集合映射为nodejs中的一个model,然后在该model上提供操作这个集合的一些方法,使用它就可以避免我们自己利用nodejs提供的原生操作mongoDB数据库的语法去手写数据库CURD的方法,大大见晒了工作量,提高了开发效率。关于mongoose的学习,推荐去其
,里面详述了它的安装,使用以及API调用情况。
解决了mongoDB安装和操作问题,我们来对数据库操作的model类,首先在项目路径下建立一个db.js文件,用来连接数据库并对数据库进行全局配置,如下
var settings=require(&./settings&);
var mongoose=require('mongoose');
mongoose.connect(&mongodb://&+settings.ip+&/&+settings.db);
var db=mongoose.
module.exports={
&dbCon&:db,
&mongoose&:mongoose
这里首先加载了配置文件settings.js文件,为了数据库便于灵活修改,我们将某些信息存储在配置文件中。然后加在了之前安装的mongoose模块,然后调用该模块的connect方法来连接我们配置的数据库,然后将连接以对象的形式返回供外部调用。
settings.js
module.exports={
&ip&:&localhost&,
&db&:&microblog&,
&host&:27071
MongoDB的默认端口是27071,一般可以使用默认端口即可,数据库连接大时候可以不指定端口,数据库名为microblog.
然后以db.js返回的数据库连接对象为基础,我们在项目根目录下创建一个models文件夹,用来存放数据模型。创建一个user.js映射我们数据库中的user集合(可以理解为user表),代码如下:
var mongoose=require('../db').
var schema=new mongoose.Schema({
name:'string',
password:'string'
var User=mongoose.model('User',schema);
module.exports=U
这里首先获得db.js中定义的连接对象,并以该对象为基础构造一个Schema(架构),mogoose操作数据库是以架构为基础的,类似于我们其他ORM模型中属性和方法的定义。这里我们定义了一个架构,拥有两个属性,name和password,都是string类型,对应用户的用户名和密码。然后利用该架构去创建一个model,该model上定义了对数据集合的增删改查等方法,不用我们自己再去定义和编写其他代码。在原书中这一节是利用node.js操作MongoDB数据库的原生API去定义了一个user对象,然后在user对象上自定义了一些CRUD的方法。可以看出,直接使用Mongoose可以大大减少开发量并且拥有更好的效率和性能。
到目前为止,我们已经有了界面(view),数据模型(model),就差逻辑代码(controller)没有编写了。在编写逻辑代码之前需要先说下express框架的特点以及它的整体运行方式。由于本人使用过一些类似的如Asp.net mvc,Yii以及thinkphp等MVC框架,使用express之后最大的感觉是这个框架够轻量级,尤其是express4.X之后,它仅仅保留了静态文件路径映射模块作为该框架本身的内置模块,其他的功能都以中间件的形式采用require(modulename)进行引入,只有引入后才能够使用该模块提供的功能。
express的工作原理是客户端发送一个request,express接到该请求,可以将它进行处理之后传递给其他中间件进行处理,最终处理完成之后,采用respond.end或者response.render进行页面渲染或响应,进行页面渲染的时候,采用参数传递页面需要的数据给对应模板引擎,模板引擎收到数据然后按照自己的语法进行替换生成对应的html,最终返回给浏览器进行渲染。
在express中,最关键的部分就是路有机制,我们所有基于请求做出的响应都是对该路由进行监听捕获的结果。举个例子,如果我们请求一个路径为http://localhost:3000/user,那么必须在routes文件夹下面的路径监听(暂且叫做监听吧)的js文件中编写对该请求的响应代码,诸如app.post('/user',function(...){...})之类的代码,如果不存在这样的代码,就会报一个404错误,因为请求没有得到响应,express实例不知道怎么去响应这个请求。以上就是express大致的原理和工作流程,对于它的学习,推荐去
直接去看文档,讲的很详细。
现在回到用户注册模块,我们注册用户常见的做法是注册成功之后就默认用户已经登录,直接跳转到欢迎登陆界面。在这里我们需要将用户数据在注册成功之后保存在session中,express框架对于session的支持是通过中间件
来的,使用方式依然是在npm 下安装,然后在项目主文件中使用require加载,最后调用其提供的API,为了使用session,必须先安装cookie的支持,这里利用
这个中间件来为express框架提供cookie支持,它的具体使用方式可以去上面提供的地址自行查看。对于session,我们常见框架的做法是在服务器端将其存放到文件当中,由于这里我们有了MongoDB数据库,更理想的状态是将它存在数据库中,这样可以更灵活去控制。使用
中间件可以将session存储到mongoDB中,具体使用方式可按地址查看。
上述概念明确之后,我们在项目根目录下的app.js(项目入口文件)中加载我们需要的中间件模块和自定义的模块如下:
app.js模块加载代码:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var users = require('./routes/users');
var session = require(&express-session&);
var MongoStore=require('connect-mongo')(session);
var db = require('./db');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({
secret:&myzhibie&,
store:new MongoStore({
mongooseConnection:db.dbCon
app.use('/', routes);app.use('/users', users);
上述代码就是加载各个中间件模块并采用app.use来load这个模块,其中上述代码的最后一指定了将session存储在MongoDB数据库中,secret属性是对session的签名,通常是一个字符串,这是必选项,如果不写,
是无法完成将session存储进入数据库的,关于该功能的更详细介绍请
,最后两句app.use('/',routes)和app.use('/users',users)代表对于这两个路由的访问处理代码我们封装在了routes和users模块中,er这两个模块都在routes文件夹下面。
完成了模块引入加载和一些基本的设置,现在来编写用户注册的逻辑代码,上面说到对于路径/的访问处理在routes模块中,这个模块指的就是routes文件夹下面的index.js,部分代码如下:
1 var express = require('express');
2 var crypto = require('crypto');
3 var router = express.Router();
4 var db=require('../db');
5 var User=require('../models/user');
6 var Post=require('../models/post');
7 /* GET home page. */
8 router.get('/', function(req, res, next) {
Post.find({},function(err,posts){
req.session.message=err.
return res.redirect('/');
res.render('index',{
posts:posts
20 //发表微博
21 router.post('/post',function(req, res, next){
var currentUser=req.session.
var post=new Post({
user:currentUser.name,
post:req.body.article,
updated:getTime(new Date())
post.save(function(err){
req.session.message=err.
res.redirect('/reg');
req.session.success=&发表成功&;
res.redirect('/users/'+currentUser.name);
40 function getTime(date){
return date.getFullYear()+
&-&+date.getMonth()+1+&-&+
date.getDate()+& &+
date.getHours()+&:&+
date.getMinutes();
47 router.get('/reg', isLogin);
48 //用户进入注册页面
49 router.get('/reg',function(req,res){
res.render('reg',{title:&用户注册&});
52 router.post('/reg', isLogin);
53 //用户点击注册按钮
54 router.post('/reg',function(req,res){
if(req.body['password']!= req.body['passwordconf']){
req.session.error=&两次密码不一致&;
return res.redirect('/reg');
var md5=crypto.createHash('md5');
var password=md5.update(req.body.password).digest('base64');
var newUser=new User({
name:req.body['username'],
password:password
User.findOne({name:newUser.name},function(err,user){
err=&用户名已经存在&;
req.session.error=
res.redirect('/reg');
newUser.save(function(err){
req.session.error=err.
res.redirect('/reg');
req.session.user=newU
req.session.success=&注册成功&;
res.redirect('/');
84 router.get('/login',isLogin);
85 router.get('/login',function(req,res){
res.render('login',{title:&用户登陆&});
88 router.post('/login',isLogin);
89 router.post('/login',function(req,res){
var md5=crypto.createHash('md5');
var password=md5.update(req.body.password).digest('base64');
User.findOne({name:req.body.username},function(err,user){
if(!user){
req.session.error=&用户不存在&;
return res.redirect('/login');
if(user.password!=password){
req.session.error=&密码错误&;
res.redirect('/login');
req.session.user=
req.session.success=&登录成功&;
res.redirect('/');
106 router.get('/logout',function(req,res){
req.session.user=null;
res.redirect('/');
110 function isLogin(req,res,next){
if(req.session.user){
req.session.message=&用户已登录&;
return res.redirect('/');
117 module.exports =
上述代码1-6行都是对外部模块的引入,8-19行是对首页路由/的处理代码。117行将该模块定义为router供外部调用。我们主要看54-83行,这些代码就是用户注册的代码,54行监听来自用户对于/reg路由的post请求,首先判断两次密码是否一致,如果不一致在session中存储一个错误信息然后跳转到到当前页面显示错误信息,该错误信息供模板引擎显示给用户。如果两次密码一致首先对密码进行md5加密,使用的是nodejs提供的核心模块crypto,并生成一个对象模型User,该对象模型是mongoose中提供的一个model的实例,mongoose在它上面定义了一些操作数据库的方法。然后调用这个实例的findOne方法检测该用户是否已经存在,如果存在就保存错误信息到session并跳转到当前页显示错误。如果不存在这样一个用户就使用save方法进行用户信息保存,注册成功后将用户信息保存在session中,并保存一个success的提示信息,然后跳转到首页。这里需要注意一个坑,以前做php或者.net的时候,我们通常都是先查询数据库等数据库返回结果提示用户是否存在之后再进行用户的save然后在跳转,这是一种同步方式,跳转操作需要等待findOne操作返回结果之后才能进行。而nodejs中采用异步IO,最后的跳转操作需要放在findOne操作的回调函数中进行,跳转操作不必等待findone操作结束后执行,两者是异步的。如果将最后的redirect操作放在findOne操作外部而不是回调函数中,你会在控制台上得到一个
的错误,这是因为在fineOne以及save操作之前已经进行行了跳转,response响应已经结束,不能够重复响应请求。
到目前为止,用户注册模块基本上已经差不多完成了,最后需要说一下如何在页面上显示提示信息或者错误信息,之前我们将提示信息或者错误信息都保存在了session中,jade要显示错误信息,它是不能够直接访问session的,在express2.X即原书中是利用req.flash API+动态视图助手来实现的,就是发生错误的时候先将其利用req.flash方法存储下来,然后利用动态视图助手结合模板去渲染给用户。express4.X废弃了这种方式,我们可以利用req.flash 的原理来自己模拟一个这种机制,同时利用res.locals变量被保存起来,模板在渲染的时候是能够访问到服务端这个变量的。关于res.locals的更多介绍请查看
为了模拟这种req.flash机制,我们在项目入口文件app.js(项目根目录下)添加一段代码如下:
1 app.use(function(req,res,next){
res.locals.user=req.session.
var err=req.session.
var success=req.session.
var user=req.session.
var mess=req.session.
delete req.session.
req.session.
req.session.
res.locals.message=&*&+
res.locals.message=&*&+
if(success){
res.locals.success=
res.locals.user=user.
这段代码的意思是用户请求和响应的时候,捕获session中存储的错误信息和用户提示,将其存储在response.locals变量中,这样模板就能够获取。对于错误信息和提示,由于只使用一次,存储后立即使用delete删除,对于用户信息,需要持久保存下来,则不删除。
这样,就能够显示用户提示或者错误信息。
下面演示一下完整的用户注册流程以及错误信息提示。
当用户名存在或密码不一致时,
当注册成功后跳转到首页并显示用户注册成功
同时对于注册成功和登陆成功拥有不同提示,如果该用户已经是登录状态则显示退出和发表文章按钮,如果没有登录,则显示的是登陆和立即注册按钮。
以上就是利用nodejs及express,mongoose,mongoDB,jade进行web开发的主要流程,由于该项目是对
一书中微博项目的重构,所以完整版的项目代码还有用户权限控制(已登录用户不能够注册或登陆并提示),用户进入个人页面发布微博并列表显示,同时首页显示最近发布的微博信息等功能。完整版代码点
,由于篇幅以及时间问题,上述要点不可能一一展开讨论,本文就作为一个提纲,是对nodejs web开发的一个综述。
已发表评论数()
已收藏到推刊!
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
没有分页内容
图片无法显示
视频无法显示
与原文不一致

我要回帖

更多关于 nodejs md5加密 的文章

 

随机推荐