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 相关文章推荐
excel操作之Add Data to a Spreadsheet Cell
Jun 12 Javascript
javascript的数据类型、字面量、变量介绍
May 23 Javascript
javascript 得到文件后缀名的思路及实现
May 09 Javascript
JavaScript字符串对象的concat方法实例(用于连接两个或多个字符串)
Oct 16 Javascript
Javascript中数组sort和reverse用法分析
Dec 30 Javascript
网页中JS函数自动执行常用三种方法
Mar 30 Javascript
javascript 判断页面访问方式电脑或者移动端
Sep 19 Javascript
jQuery 实现双击编辑表格功能
Jun 19 jQuery
解决vue处理axios post请求传参的问题
Mar 05 Javascript
vue2.0 自定义组件的方法(vue组件的封装)
Jun 05 Javascript
详解js访问对象的属性和方法
Oct 25 Javascript
layui 实现表格某一列显示图标
Sep 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常用的缓存技术汇总
2014/05/05 PHP
php处理带有中文URL的方法
2016/07/11 PHP
PHP实现支持CURL字符串证书传输的方法
2019/03/23 PHP
How to Auto Include a Javascript File
2007/02/02 Javascript
jQuery 隔行换色 支持键盘上下键,按Enter选定值
2009/08/02 Javascript
javascript闭包入门示例
2014/04/30 Javascript
关闭页面window.location事件未执行的原因及解决方法
2014/09/01 Javascript
bootstrap table 服务器端分页例子分享
2015/02/10 Javascript
javascript实现动态改变层大小的方法
2015/05/14 Javascript
Javascript实现获取及设置光标位置的方法
2015/07/21 Javascript
bootstrap datepicker限定可选时间范围实现方法
2016/09/28 Javascript
easyui messager alert 三秒后自动关闭提示的实例
2016/11/07 Javascript
javascript事件捕获机制【深入分析IE和DOM中的事件模型】
2016/12/15 Javascript
详解Angular2 关于*ngFor 嵌套循环
2017/05/22 Javascript
使用typescript开发angular模块并发布npm包
2018/04/19 Javascript
vue  自定义组件实现通讯录功能
2018/09/30 Javascript
vue.js 2.*项目环境搭建、运行、打包发布的详细步骤
2019/05/01 Javascript
vue 表单之通过v-model绑定单选按钮radio
2019/05/13 Javascript
vue项目启动出现cannot GET /服务错误的解决方法
2020/04/26 Javascript
详解Vue 数据更新了但页面没有更新的 7 种情况汇总及延伸总结
2020/05/28 Javascript
在js文件中引入(调用)另一个js文件的三种方法
2020/09/11 Javascript
Javascript执行上下文顺序的深入讲解
2020/11/04 Javascript
Python编码时应该注意的几个情况
2013/03/04 Python
python字符串替换示例
2014/04/24 Python
python用户管理系统的实例讲解
2017/12/23 Python
Python遍历numpy数组的实例
2018/04/04 Python
Python实现快速计算词频功能示例
2018/06/25 Python
python reverse反转部分数组的实例
2018/12/13 Python
利用Python查看微信共同好友功能的实现代码
2019/04/24 Python
python PyAUtoGUI库实现自动化控制鼠标键盘
2020/09/09 Python
韩国女装NO.1网店:STYLENANDA
2016/09/16 全球购物
华为俄罗斯官方网上商城:购买Huawei手机和平板
2017/04/21 全球购物
美国时尚假发购物网站:Wigsbuy
2019/04/06 全球购物
Vuori官网:运动服装的终级表现
2021/01/27 全球购物
德国珠宝和配件商店:Styleserver
2021/02/23 全球购物
优秀共产党员先进事迹材料
2014/05/06 职场文书