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 相关文章推荐
javascript之dhDataGrid Ver2.0.0代码
Jul 01 Javascript
Javascript 去除数组的重复元素
May 04 Javascript
基于jquery的让textarea自适应高度的插件
Aug 03 Javascript
JQuery 图片滚动轮播示例代码
Mar 24 Javascript
jquery中attr和prop的区别分析
Mar 16 Javascript
静态页面html中跳转传值的JS处理技巧
Jun 22 Javascript
JavaScript实现二叉树的先序、中序及后序遍历方法详解
Oct 26 Javascript
详解Node使用Puppeteer完成一次复杂的爬虫
Apr 18 Javascript
js中apply()和call()的区别与用法实例分析
Aug 14 Javascript
vue中axios实现数据交互与跨域问题
May 12 Javascript
js实现列表向上无限滚动
Jan 13 Javascript
vue实现列表拖拽排序的示例代码
Apr 08 Vue.js
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实现的获取URL信息的类
2007/01/02 PHP
工厂模式在Zend Framework中应用介绍
2012/07/10 PHP
探讨php define()函数及defined()函数使用详解
2013/06/09 PHP
php 过滤英文标点符号及过滤中文标点符号代码
2014/06/12 PHP
浅析PHP程序设计中的MVC编程思想
2014/07/28 PHP
PHP输出一个等腰三角形的方法
2015/05/12 PHP
PHP表单数据写入MySQL数据库的代码
2016/05/31 PHP
学习ExtJS 访问容器对象
2009/10/07 Javascript
javascript轻松实现当鼠标移开时已弹出子菜单自动消失
2013/12/29 Javascript
javascript在当前窗口关闭前检测窗口是否关闭
2014/09/29 Javascript
js实现鼠标经过表格行变色的方法
2015/05/12 Javascript
javascript字符串函数汇总
2015/12/06 Javascript
js HTML5手机刮刮乐代码
2020/09/29 Javascript
vue.js+Element实现表格里的增删改查
2017/01/18 Javascript
jQuery插件FusionCharts绘制的2D帕累托图效果示例【附demo源码】
2017/03/28 jQuery
axios封装,使用拦截器统一处理接口,超详细的教程(推荐)
2019/05/02 Javascript
解决LayUI数据表格复选框不居中显示的问题
2019/09/25 Javascript
[40:55]Liquid vs LGD 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
python 编程之twisted详解及简单实例
2017/01/28 Python
Python利用Beautiful Soup模块搜索内容详解
2017/03/29 Python
python enumerate函数的使用方法总结
2017/11/15 Python
Python简单生成随机姓名的方法示例
2017/12/27 Python
Python使用统计函数绘制简单图形实例代码
2019/05/15 Python
使用Python实现毫秒级抢单功能
2019/06/06 Python
python字符串的拼接方法总结
2019/11/18 Python
python实现逆滤波与维纳滤波示例
2020/02/26 Python
Python实现检测文件的MD5值来查找重复文件案例
2020/03/12 Python
python thrift 实现 单端口多服务的过程
2020/06/08 Python
英国奢侈品在线精品店:Hervia
2020/09/03 全球购物
在C#中如何实现多态
2014/07/02 面试题
一名毕业生的自我鉴定
2013/12/04 职场文书
婚前协议书范本
2014/04/15 职场文书
护理学院专科毕业生求职信
2014/06/28 职场文书
找规律教学反思
2016/02/23 职场文书
何时使用Map来代替普通的JS对象
2021/04/29 Javascript
15个值得收藏的JavaScript函数
2021/09/15 Javascript