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 相关文章推荐
获取URL地址中的文件名和参数的javascript代码
Sep 02 Javascript
扩展easyui.datagrid,添加数据loading遮罩效果代码
Nov 02 Javascript
自己实现string的substring方法 人民币小写转大写,数字反转,正则优化
Sep 02 Javascript
ie8 不支持new Date(2012-11-10)问题的解决方法
Jul 31 Javascript
javascript中undefined与null的区别
Aug 16 Javascript
微信小程序入门教程
Nov 18 Javascript
几行js代码实现自适应
Feb 24 Javascript
ES6中Proxy代理用法实例浅析
Apr 06 Javascript
webpack构建的详细流程探底
Jan 08 Javascript
elementUI Vue 单个按钮显示和隐藏的变换功能(两种方法)
Sep 04 Javascript
webpack4 升级迁移的实现
Sep 12 Javascript
vue中实现动态生成二维码的方法
Feb 21 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+MySQL5.0中文乱码解决方法
2006/11/20 PHP
php中模拟POST传递数据的两种方法分享
2011/09/16 PHP
PHP学习笔记 用户注册模块用户类以及验证码类
2011/09/20 PHP
php计算程序运行时间的简单例子分享
2014/05/10 PHP
php有效防止同一用户多次登录
2015/11/19 PHP
PHP中递归的实现实例详解
2017/11/14 PHP
XP折叠菜单&仿QQ2006菜单
2006/12/16 Javascript
Jquery实现无刷新DropDownList联动实现代码
2010/03/08 Javascript
js中查找最近的共有祖先元素的实现代码
2010/12/30 Javascript
FireFox下XML对象转化成字符串的解决方法
2011/12/09 Javascript
自动最大化窗口的Javascript代码
2013/05/22 Javascript
jquery遍历select元素(实例讲解)
2013/12/31 Javascript
超棒的响应式布局jQuery插件Freetile.js
2014/11/17 Javascript
javascript中键盘事件用法实例分析
2015/01/30 Javascript
jquery dialog获取焦点的方法
2017/02/09 Javascript
vue router学习之动态路由和嵌套路由详解
2017/09/21 Javascript
微信小程序将字符串生成二维码图片的操作方法
2018/07/17 Javascript
解决vue attr取不到属性值的问题
2018/09/18 Javascript
js中Array对象的常用遍历方法详解
2019/01/17 Javascript
浅谈JS和jQuery的区别
2019/03/27 jQuery
微信小程序第三方框架对比 之 wepy / mpvue / taro
2019/04/10 Javascript
Vue.js仿Select下拉框效果
2020/02/18 Javascript
15个简单的JS编码标准让你的代码更整洁(小结)
2020/07/16 Javascript
[00:36]DOTA2上海特级锦标赛 LGD战队宣传片
2016/03/04 DOTA
python 随机数生成的代码的详细分析
2011/05/15 Python
python+ffmpeg批量去视频开头的方法
2019/01/09 Python
Apache部署Django项目图文详解
2019/07/30 Python
提升python处理速度原理及方法实例
2019/12/25 Python
如何教少儿学习Python编程
2020/07/10 Python
HTML5如何为形状图上颜色怎么绘制具有颜色和透明度的矩形
2014/06/23 HTML / CSS
2014年商场超市庆元旦活动方案
2014/02/14 职场文书
大学班级学风建设方案
2014/05/01 职场文书
2014年社区卫生工作总结
2014/12/18 职场文书
结婚保证书
2015/01/16 职场文书
原生CSS实现文字无限轮播的通用方法
2021/03/30 HTML / CSS
python实现进度条的多种实现
2021/04/29 Python