Angular.js与node.js项目里用cookie校验账户登录详解


Posted in Javascript onFebruary 22, 2017

前言

最近的新项目中,用户登录需要采用cookie来记住用户,校验身份。所以本文就把实现的过程总结出来分享给大家,需要的朋友们可以参考学习。

在header中携带authId登录

在之前老的项目里,没有采用cookie来记录用户登录状态,而是在请求的header中携带一个身份标识来校验,大致方案如下:

  1. 客户端使用post请求提交user、password给服务端进行登录操作;
  2. 服务端校验用户是否合法,如果合法将产生一个唯一的身份标识authId,返回给客户端,客户端将此authId存放本地(如localStorage);
  3. 客户端在每次需要校验身份的请求中,往header中加入这个authId;
  4. 服务端检测当前的authId是否有效,有效则表示当前用户合法,允许操作;
  5. 客户端用户登出的时候,发送一个delete请求,告诉服务端用户注销,同时删除本地的authId信息;
  6. 服务端收到注销请求后,删除当前的authId数据。

上面的方案,如果其他客户端知道了这个authId后,可以在其他客户端模拟身份,不安全,因此弃用。

用cookie记住用户

新项目中,将采用此文即将介绍的方案?利用cookie来记住用户。主要流程是:

  1. 客户端使用post请求提交user、password给服务端进行登录操作;
  2. 服务端校验用户是否合法,如果合法将产生一个唯一的身份标识authId,以cookie的形式返回给客户端;
  3. 客户端再次请求服务端时,会携带此前已经拿到的cookie给服务端,服务端校验是否合法,合法则可以继续操作;
  4. 客户端用户登出的时候,发送一个delete请求,告诉服务端用户注销,服务端删除登录标识。

     整个过程可以用下面这张图简单表示:

Angular.js与node.js项目里用cookie校验账户登录详解

前台用angular搭建单页客户端应用,后台用node搭建服务器,数据存放在mongodb中,这三个技术及cookie基础知识本文不做介绍,感兴趣的同学可以自行了解。

以下的代码都是最简单的get/post请求,但也是最核心的部分,其他有关登录的繁琐操作,感兴趣的同学可以自行补充。

从开始?>结束,遇到的问题

首先,我用的是最基础的post请求,服务端也只是简单的返回数据,部分简单但比较核心的代码如下:

// client
$http({
 method   : 'POST',
 url   : 'http://127.0.0.1:8888/rest/user',
 data   : {name: 'xxx',password:'***'}
 }).success(function (data) {
 console.log('login success,data is:'+data);
}).error(function (data) {
 console.log('login error');
}).then(function () {
 console.log(arguments);
});

// server
var cookie = "authId=" + authId;
res.setHeader('Content-Type', 'application/json;charset=utf-8');
res.setHeader('Set-Cookie', cookie + ';Max-Age=3600;HttpOnly=false;Path=/;');
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end();

查看chrome调试,发现虽然服务端的cookie推过来了,但整体出了问题,提示如下:

Angular.js与node.js项目里用cookie校验账户登录详解

XMLHttpRequest cannot load http://127.0.0.1:8888/rest/user. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:62427' is therefore not allowed access.

分析问题后,发现原因是来自客户端的请求不能跨域访问服务端的请求,请求的资源header中没有携带允许跨越请求的信息。根据这个提示,我们把服务端的代码稍加改进后,如下:

// server
var cookie = "authId=" + authId;
res.setHeader('Content-Type', 'application/json;charset=utf-8');
res.setHeader('Set-Cookie', cookie + ';Max-Age=3600;HttpOnly=false;Path=/;');

// 添加允许跨越的头信息
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');

res.writeHead(200, {'Content-Type': 'text/plain'});
res.end();

解释下上面代码什么意思,第一句主要是允许来自任何域的请求访问,第二句是允许哪些类型的请求访问。加上后再次运行,提示如下:

Angular.js与node.js项目里用cookie校验账户登录详解XMLHttpRequest

cannot load http://127.0.0.1:8888/rest/user. Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.

原因是来自客户端的请求中,Content-Type头字段,在服务端的响应信息的头中,没有携带,再次修改代码如下:

// server
var cookie = "authId=" + authId;
res.setHeader('Content-Type', 'application/json;charset=utf-8');
res.setHeader('Set-Cookie', cookie + ';Max-Age=3600;HttpOnly=false;Path=/;');

// 添加允许跨越的头信息
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');

// 添加支持Content-Type允许的头信息
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');

res.writeHead(200, {'Content-Type': 'text/plain'});
res.end();

再次运行代码,发现没有错误提示,但是当我们再次请求服务器时,发现客户端的请求并没有携带cookie信息,这显然不是我们想要的效果:

Angular.js与node.js项目里用cookie校验账户登录详解

在查阅了一段时间后了解到,客户端是会默认携带cookie给服务端的,但是当客户端的请求是跨域请求时,由于跨域请求本身就有风险,而携带给cookie同样有风险。

因此在进行跨域访问时,客户端不会将服务端返回的cookie携带。此时,我们需要同时在客户端和服务端都设置“withCredentials”为true,代码如下:

// client
$http({
 method   : 'POST',
 url   : 'http://127.0.0.1:8888/rest/user',
 withCredentials: true
 data   : {name: 'xxx',password:'***'}
 }).success(function (data) {
 console.log('login success,data is:'+data);
}).error(function (data) {
 console.log('login error');
}).then(function () {
 console.log(arguments);
});

// server
var cookie = "authId=" + authId;
res.setHeader('Content-Type', 'application/json;charset=utf-8');
res.setHeader('Set-Cookie', cookie + ';Max-Age=3600;HttpOnly=false;Path=/;');

// 添加允许跨越的头信息
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');

// 添加支持Content-Type允许的头信息
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');

// 设置已携带凭证为true
//res.setHeader('Access-Control-Allow-Credentials', true);

res.writeHead(200, {'Content-Type': 'text/plain'});
res.end();

运行后,发现又有错误提示,如下:

Angular.js与node.js项目里用cookie校验账户登录详解

XMLHttpRequest cannot load http://127.0.0.1:8888/rest/user. Response to preflight request doesn't pass access control check: A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. Origin 'http://localhost:62427' is therefore not allowed access.

分析错误后发现,原因是当设置了已携带凭证参数为true时,允许跨域请求的源不能设置为泛型的“*”,因此我们再次修改代码如下:(最终代码)

// client
$http({
 method   : 'POST',
 url   : 'http://127.0.0.1:8888/rest/user',
 withCredentials: true
 data   : {name: 'xxx',password:'***'}
 }).success(function (data) {
 console.log('login success,data is:'+data);
}).error(function (data) {
 console.log('login error');
}).then(function () {
 console.log(arguments);
});

// server
var cookie = "authId=" + authId;
res.setHeader('Content-Type', 'application/json;charset=utf-8');
res.setHeader('Set-Cookie', cookie + ';Max-Age=3600;HttpOnly=false;Path=/;');

// 添加允许跨越的头信息
// res.setHeader('Access-Control-Allow-Origin', '*');
// 用当前的客户端origin来取代泛型的“*”
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:62427');

res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');

// 添加支持Content-Type允许的头信息
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');

// 设置已携带凭证为true
res.setHeader('Access-Control-Allow-Credentials', true);

res.writeHead(200, {'Content-Type': 'text/plain'});
res.end();

此时,第一次请求服务端时,服务端返回cookie信息,以后每次客户端请求服务端,客户端的header中都会携带cookie信息,效果如下图:

Angular.js与node.js项目里用cookie校验账户登录详解

最后

以上就是在使用cookie记住用户身份时遇到的一些问题及简单解决方法,一般在angular应用中,可能使用较多的是resoure进行http通信,此时只要在GET/POST/PUT/DELETE等请求的参数中,将“withCredentials”设置为true即可。希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

Javascript 相关文章推荐
jquery学习笔记二 实现可编辑的表格
Apr 09 Javascript
jQuery的运行机制和设计理念分析
Apr 05 Javascript
JS在TextArea光标位置插入文字并实现移动光标到文字末尾
Jun 21 Javascript
首页图片漂浮效果示例代码
Jun 05 Javascript
通过原生JS实现为元素添加事件的方法
Nov 23 Javascript
JS实现太极旋转思路分析
Dec 09 Javascript
jQuery Ajax实现跨域请求
Jan 21 Javascript
jQuery时间验证和转换为标准格式的时间格式
Mar 06 Javascript
浅谈vue引用静态资源需要注意的事项
Sep 28 Javascript
Vue的双向数据绑定实现原理解析
Feb 17 Javascript
JS如何生成随机验证码
Mar 02 Javascript
javascript this指向相关问题及改变方法
Nov 19 Javascript
js实现无缝滚动图
Feb 22 #Javascript
JavaScript实现二分查找实例代码
Feb 22 #Javascript
浅谈jquery拼接字符串效率比较高的方法
Feb 22 #Javascript
微信小程序  TLS 版本必须大于等于1.2问题解决
Feb 22 #Javascript
原生JS实现幻灯片
Feb 22 #Javascript
微信小程序 解析网页内容详解及实例
Feb 22 #Javascript
从零学习node.js之简易的网络爬虫(四)
Feb 22 #Javascript
You might like
使用php shell命令合并图片的代码
2011/06/23 PHP
PHP版 汉字转码的实现详解
2013/06/09 PHP
PHP中怎样防止SQL注入分析
2014/10/23 PHP
PHP判断FORM表单或URL参数来的数据是否为整数的方法
2016/03/25 PHP
在laravel-admin中列表中禁止某行编辑、删除的方法
2019/10/03 PHP
基于jquery的高性能td和input切换并可修改内容实现代码
2011/01/09 Javascript
JavaScript实现找出数组中最长的连续数字序列
2014/09/03 Javascript
用jquery模仿的a的title属性的例子
2014/10/22 Javascript
JavaScript实现的链表数据结构实例
2015/04/02 Javascript
在JavaScript中操作时间之getUTCDate()方法的使用
2015/06/10 Javascript
bootstrap table 表格中增加下拉菜单末行出现滚动条的快速解决方法
2017/01/05 Javascript
Node.js+Express+MySql实现用户登录注册功能
2017/07/10 Javascript
Node.js五大应用性能技巧小结(必须收藏)
2017/08/09 Javascript
nodeJs实现基于连接池连接mysql的方法示例
2018/02/10 NodeJs
react-native android状态栏的实现
2018/06/15 Javascript
Angular6 Filter实现页面搜索的示例代码
2018/12/02 Javascript
微信小程序wx.navigateTo方法里的events参数使用详情及场景
2020/01/07 Javascript
Vue如何基于vue-i18n实现多国语言兼容
2020/07/17 Javascript
[02:27]2018DOTA2亚洲邀请赛趣味视频之钓鱼大赛 谁是垂钓冠军?
2018/04/05 DOTA
[54:47]Liquid vs VP Supermajor决赛 BO 第五场 6.10
2018/07/05 DOTA
python3读取MySQL-Front的MYSQL密码
2017/05/03 Python
python爬虫入门教程--快速理解HTTP协议(一)
2017/05/25 Python
PyCharm 设置SciView工具窗口的方法
2019/01/15 Python
python3使用matplotlib绘制条形图
2020/03/25 Python
元组列表字典(莫烦python基础)
2019/04/03 Python
Python爬虫实现“盗取”微信好友信息的方法分析
2019/09/16 Python
谷歌浏览器小字体处理方案即12px以下字体
2013/12/17 HTML / CSS
洛杉矶健身中心女性专用运动服饰品牌:Marika
2018/05/09 全球购物
澳大利亚最受欢迎的美发和美容在线商店:Catwalk
2018/12/12 全球购物
玛蒂尔达简服装:Matilda Jane Clothing
2019/02/13 全球购物
机电专业个人自荐信格式模板
2013/09/23 职场文书
大专生的学习自我评价
2013/12/04 职场文书
卫校毕业生自我鉴定
2014/09/28 职场文书
2014高三学生考试作弊检讨书
2014/12/14 职场文书
义诊活动总结
2015/02/04 职场文书
反腐倡廉影片观后感
2015/06/08 职场文书