为什么res.jsonp会has no methodd

纯数据API服务,设置Access-Control-Allow-Origin: * 是否会有安全性隐患?
背景:1. 开发Android应用,用H5+WebView的方式,HTML打包在APK里。2. 需要读取服务端的数据,由于是本地页面,涉及到跨域问题,根据CORS()的介绍,服务端需要设置一些Header。3. 而正是因为本地页面,Access-Control-Allow-Origin只能设为为 * 4. 服务端为纯API服务,不会托管其他Web页面。问题: 此场景下服务端的Header配置会不会有什么安全隐患?3x
感觉楼主的标题把大家引到另一个方向了我觉得楼主这个问题可以拆分为两个问题:1、如何跨域调用API2、如何安全的开放API首先第一个问题,得分调用方式,如果只是简单的request请求获取数据那根本不需要设置什么,而如果是jsonp的方式去调用,在跨域的情况需要设置Access-Control-Allow-Origin: 但即使设置了Access-Control-Allow-Origin只是影响了jsonp的调用,不是说数据就是安全的,如果我需要爬取API的数据,我完全可以抓包,写个脚本直接请求,那么Access-Control-Allow-Origin的设置是对爬取完全没影响和限制的。其次,第二个问题,如何安全的开放API。首先需要定义这个API的用途和开放程度,如果开放的是无所谓的数据,那么完全可以不做任何限制,只需要在同个ip的请求上,也就是反爬取上进行限制,避免恶意爬取影响API服务的稳定性。如果这是一个不能对外开放,只允许那个APP调用的API,那么就有必要进行一些限制,比如:1、请求的时间有效性2、验证token3、验证ip4、验证来源等等这种校验需要是不可逆,比如:请求接口需要传入几个参数:{
'name': 用户名,
‘key: 加密的验证key,
‘timestamp’: 时间戳,}三个参数中,name是已知固定的key可以是由name+secret+timestamp来通过不可逆加密生成,比如先加上特定字段相连,再md5加密(也可以是其他加密方式,尽量采用不可逆的加密)timestamp:请求接口时的时间戳secret应该是不向外透露的服务端的验证应该是这样的:1、验证timestamp与服务接到请求的时间相差是否在指定范围内,比如5分钟内2、验证拿已知的secret+接口传的name+timestamp采用相同加密方式加密,看看生成的key是否与接口传的相同3、验证用户名是否在指定允许使用API服务的用户列表内还可以校验请求的header等等通过类似以上的方式,排除接口服务本身外的其他因素,接口的请求验证就是相对安全的
谢邀 在安卓本地的WebView的确无法不经过配置的访问远程API。解决方案大约有两种:1、用JSONP(这是目前我们使用的方式)2、用安卓提供的JavaScript Interface see: ,由原生代码进行网络操作,成功后进行回调。如果你一定要post,那么就用第二种方式。另外,在高版本安卓上进行了更多安全限制,因此你可能需要if (Build.VERSION.SDK_INT &= Build.VERSION_CODES.JELLY_BEAN) {
webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
至于安全问题,其实很好理解,跨域安全问题可以保护你的API不被滥用,或者不被XSS攻击,这个就是前端安全问题了,与安卓关系不大,也非常好理解了,就不展开了。
第一,Access-Control-Allow-Origin肯定有安全问题。不建议这么做。第二,WebView有一个settings参数,可以解决跨域的问题。
你这样设置会使任意网站都能在前端使用你的 API,和用 JSONP 差不多,如果你那个 API 没什么人用的话我觉得就没什么问题。但是你使用 CORS 的姿势和场合略别扭啊。跨域限制是浏览器给前端的限制,但是既然是在 webview 里,我猜可以不用这样吧,大不了直接原生代码拿数据呗。不怎么懂 Android 开发,在栈溢出里搜了搜 :排名第一的说不用采取什么跨域措施,直接改 webview 的设置就行了。@和林跃 求解。
若将Access-Control-Allow-Origin设置为 *,则表示其可以为所有其他域访问。res.header("Access-Control-Allow-Origin", "*");
存在一定的安全隐患。我想题主想问的是,:只设置自己指定的若干个域名或者端口可以调用接口。像下面这样:Access-Control-Allow-Origin: ,
可以考虑下面的做法:1.在进行跨域请求时,设置一个数组,用来存储允许的自定义域名。如下所示:var accessOriginArray = new Array(10);
accessOriginArray = ["http://localhost:8080","http://localhost:9090"];
2.获取请求头的域名,并比较是否在数组中,若存在则将响应的Access-Control-Allow-Origin设置为该域,否则置为空。如下所示:var origin = req.headers.
if (accessOriginArray.indexOf(origin) != -1){
// console.log(accessOriginArray.indexOf(origin));
// console.log(origin);
// console.log(res.getHeader("Access-Control-Allow-Origin"));
res.header("Access-Control-Allow-Origin", origin);
res.header("Access-Control-Allow-Origin", null);
3.最好将响应的数据返回: res.send(JSON.stringify(data));
如此即可 设置多个自定义域,来允许其跨域向服务器发送请求。
你的问题好模糊。没参与过Hybird App开发,也不知道你的具体场景是怎样,是多用户的App?file://也是域,本地域,协议是:file://协议。你的场景是:App里的file://android_asset/index.html去请求服务端API?然后API响应设置了:Access-Control-Allow-Origin: * ?为什么要设置Access-Control-Allow-Origin这个头,不明白。你提的这个场景,安全风险和「PLAY! Framework」没任何关系。如果这个API有用户隐私,做好token校验就好,如果要更安全就HTTPS化。
已有帐号?
无法登录?
社交帐号登录什么是跨域JSONPproxy代理corsxdr  由于浏览器同源策略,凡是发送请求url的协议、域名、端口三者之间任意一与当前页面地址不同即为跨域。具体可以查看下表(来源)    JSONP  这种方式主要是通过动态插入一个script标签。浏览器对script的资源引用没有同源限制,同时资源加载到页面后会立即执行(没有阻塞的情况下)。1 &script&2
var _script = document.createElement('script');3
_script.type = &text/javascript&;4
_script.src = &http://localhost:8888/jsonp?callback=f&;5
& & &document.head.appendChild(_script);6
&/script&  实际项目中JSONP通常用来获取json格式数据,这时前后端通常约定一个参数callback,该参数的值,就是处理返回数据的函数名称。 1 &!doctype html&
&meta charset=&utf-8&&
&meta name=&viewport& content=&initial-scale=1, maximum-scale=1,user-scalable=no&&
&title&jsonp_test&/title&
var f = function(data){10
& & & &alert(data.name);11
/*var xhr = new XMLHttpRequest();13
& & &xhr.onload = function(){14
& & & &alert(xhr.responseText);15
& & &xhr.open('POST', 'http://localhost:8888/cors', true);17
& & &xhr.setRequestHeader(&Content-Type&, &application/x-www-form-urlencoded&);18
& & &xhr.send(&f=json&);*/19
&/script&20
&script&22
var _script = document.createElement('script');23
_script.type = &text/javascript&;24
_script.src = &http://localhost:8888/jsonp?callback=f&;25
& & &document.head.appendChild(_script);26
&/script&27
&/head& 1 var query = _url.
& & & &console.log(query);
var params = qs.parse(query);
& & & &console.log(params);
var f = &&;
f = params.
res.writeHead(200, {&Content-Type&: &text/javascript&});10
res.write(f + &({name:'hello world'})&);11
res.end();    缺点:  1、这种方式无法发送post请求(这里)  2、另外要确定jsonp的请求是否失败并不容易,大多数框架的实现都是结合超时时间来判定。&  Proxy代理  这种方式首先将请求发送给后台服务器,通过服务器来发送请求,然后将请求的结果传递给前端。 1 &!doctype html&
&meta charset=&utf-8&&
&meta name=&viewport& content=&initial-scale=1, maximum-scale=1,user-scalable=no&&
&title&proxy_test&/title&
var f = function(data){10
& & & &alert(data.name);11
var xhr = new XMLHttpRequest();13
xhr.onload = function(){14
& & & &alert(xhr.responseText);15
xhr.open('POST', 'http://localhost:8888/proxy?/arcgis/rest/services/World/GeocodeServer', true);17
xhr.send(&f=json&);18
&/script&19
&/body&23 &/html& 1 var proxyUrl = &&;
if (req.url.indexOf('?') & -1) {
proxyUrl = req.url.substr(req.url.indexOf('?') + 1);
& & & & &console.log(proxyUrl);
if (req.method === 'GET') {
& & & & &request.get(proxyUrl).pipe(res);
} else if (req.method === 'POST') {
var post = '';
//定义了一个post变量,用于暂存请求体的信息10 11
req.on('data', function(chunk){
//通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中12
& & & &});14
req.on('end', function(){
//在end事件触发后,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回。16
post = qs.parse(post);17
& & & & & &request({18
method: 'POST',19
& & & & & & & & & & &url: proxyUrl,20
& & & & & & & & & & &form: post21
& & & & & & & & &}).pipe(res);22
& & & &});23
}   需要注意的是如果你代理的是https协议的请求,那么你的proxy首先需要信任该证书(尤其是自定义证书)或者忽略证书检查,否则你的请求无法成功。12306就提供了一个鲜活的例子。      还需要注意一点,对于同一请求浏览器通常会从缓存中读取数据,我们有时候不想从缓存中读取,所以会加一个preventCache参数,这个时候请求url变成:url?preventCache=....;这本身没有什么问题,问题出在当使用某些前端框架(比如jquery)发送proxy代理请求时,请求url为proxy?url,同时设置preventCache:true,框架不能正确处理这个参数,结果发出去的请求变成proxy?url&preventCache=123456(正长应为proxy?url?preventCache=12356);后端截取后发送的请求为url&preventCache=123456,根本没有这个地址,所以你得不到正确结果。&  CORS  这是现代浏览器支持跨域资源请求的一种方式。    当你使用XMLHttpRequest发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin,后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-O浏览器判断该相应头中是否包含Origin的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。 1 &!doctype html&
&meta charset=&utf-8&&
&meta name=&viewport& content=&initial-scale=1, maximum-scale=1,user-scalable=no&&
&title&jsonp_test&/title&
/*var f = function(data){10
& & & &alert(data.name);11
& & &}*/12
var xhr = new XMLHttpRequest();13
xhr.onload = function(){14
& & & &alert(xhr.responseText);15
xhr.open('POST', 'http://localhost:8888/cors', true);17
xhr.setRequestHeader(&Content-Type&, &application/x-www-form-urlencoded&);18
xhr.send(&f=json&);19
&/script&20
&script&22
/* var _script = document.createElement('script');23
& & &_script.type = &text/javascript&;24
& & &_script.src = &http://localhost:8888/jsonp?callback=f&;25
& & &document.head.appendChild(_script);*/26
&/script&27
&/body&31 &/html&   1 if (req.headers.origin) {
res.writeHead(200, {
&Content-Type&: &text/ charset=UTF-8&,
&Access-Control-Allow-Origin&:'http://localhost'/*,
& & & & & & & &'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
& & & & & & & &'Access-Control-Allow-Headers': 'X-Requested-With, Content-Type'*/
& & & & & &});
res.write('cors');10
& & & & & &res.end();11
}    如果我们把Access-Control-Allow-Origin去掉,浏览器会驳回响应,我们也就拿不到数据。    需要注意的一点是Preflighted Request的透明服务器验证机制支持开发人员使用自定义的头部、GET或POST之外的方法,以及不同类型的主题内容。总结如如:  1、非GET 、POST请求  2、POST请求的content-type不是常规的三个:application/x- www-form-urlencoded(使用 HTTP 的 POST 方法提交的表单)、multipart/form-data(同上,但主要用于表单提交时伴随文件上传的场合)、text/plain(纯文本)  3、POST请求的payload为text/html  4、设置自定义头部  OPTIONS请求头部中会包含以下头部:Origin、Access-Control-Request-Method、Access-Control-Request-Headers,发送这个请求后,服务器可以设置如下头部与浏览器沟通来判断是否允许这个请求。  Access-Control-Allow-Origin、Access-Control-Allow-Method、Access-Control-Allow-Headers1 var xhr = new XMLHttpRequest();2
xhr.onload = function(){3
& & & &alert(xhr.responseText);4
xhr.open('POST', 'http://localhost:8888/cors', true);6
xhr.setRequestHeader(&Content-Type&, &text/html&);7
xhr.send(&f=json&); 1 if (req.headers.origin) {
res.writeHead(200, {
&Content-Type&: &text/ charset=UTF-8&,
&Access-Control-Allow-Origin&:'http://localhost',
'Access-Control-Allow-Methods': 'GET,POST,OPTIONS',
'Access-Control-Allow-Headers': 'X-Requested-With, Content-Type'/**/
& & & & & &});
res.write('cors');10
& & & & & &res.end();&11
}    如果你在调试状态,你会发现后台代码执行了两遍,说明发送了两次请求。注意一下我们的onload代码只执行了一次,所以说OPTIONS请求对程序来说是透明的,他的请求结果会被缓存起来。  如果我们修改一下后台代码,把Content-Type去掉,你会发现OPTIONS请求失败。    通过setRequestHeader('X-Request-With', null)可以避免浏览器发送OPTIONS请求。  根据我的测试,当使用cors发送跨域请求时失败时,后台是接收到了这次请求,后台可能也执行了数据查询操作,只是响应头部不合符要求,浏览器阻断了这次请求。&  XDR  这是IE8、IE9提供的一种跨域解决方案,功能较弱只支持get跟post请求,而且对于协议不同的跨域是无能为力的,比如在http协议下发送https请求。看一下微软自己的例子就行 1 &!DOCTYPE html&
&h2&XDomainRequest&/h2&
&input type=&text& id=&tbURL& value=&/xdr.txt& style=&width: 300px&&&br&
&input type=&text& id=&tbTO& value=&10000&&&br&
&input type=&button& onclick=&mytest()& value=&Get&&&&&
&input type=&button& onclick=&stopdata()& value=&Stop&&&&&10
&input type=&button& onclick=&readdata()& value=&Read&&11
&div id=&dResponse&&&/div&13
&script&14
function readdata()16
var dRes = document.getElementById('dResponse');18
& & &dRes.innerText = xdr.responseT19
& & &alert(&Content-type: & + xdr.contentType);20
& & &alert(&Length: & + xdr.responseText.length);21
function err()24
& & &alert(&XDR onerror&);26
function timeo()29
& & &alert(&XDR ontimeout&);31
function loadd()34
& & &alert(&XDR onload&);36
& & &alert(&Got: & + xdr.responseText);37
function progres()40
& & &alert(&XDR onprogress&);42
& & &alert(&Got: & + xdr.responseText);43
function stopdata()46
& & &xdr.abort();48
function mytest()51
var url = document.getElementById('tbURL');53
var timeout <span style="line-height: 1.5 ! bac流应用(GoStream) 
 文章为作者独立观点,不代表微头条立场
的最新文章
跨境电子商务是指分属不同关境的交易主体,通过电子商务平台达成交易、进行支付结算,并通过跨境物流送达商品、完成交易的一种国际商业活动。跨境电子商务按照进出口方向分为:出口跨境电子商务和进口跨境电子商务。按照交易模式分为B2B跨境电子商务……用标准品的销售方式来贩卖非标准品是行不通的  艺典中国的副总经理张利剑如是说。艺典中国是一家非标艺术品电商平我认为O2O不会像淘宝那样一家独大,因为非标准化服务非常多。很多人谈O2O的时候会忽略的一个问题。我们知道零什么是非标品  非标品与标准品是反义词,指没有统一衡量标准和固定输出渠道,产品特性和服务形式相对个性化的消费线下非标服务的不可控成老大难,其一容易产生跳单,其二服务质量优劣平台没有跟踪的渠道,也没有衡量的标准。社区零售便利O2O指面向社区用户,基于移动互联网工具和LBS位置技术,将线下实体门店通过移动端与社区用户建立一、需求阶段 a、需求产生,产品设想需求产生有三种渠道:一,UI(User Interface用户界面)设计最近拜读了苏杰产品大神的佳作《淘宝十年产品事》,让我收益良多,产品视野得以拓宽,也初步了解到电商产品的一些特DDD - Persisting Aggregate Roots In A Unit Of WorkTher可维护的代码是一个业务优势3D打印步骤上传模型——>确认&支付——>打印&派送关于趋梦工厂-3D打印工厂趋梦工厂-3D打印工厂 是提供完整的【B2B2C】模式电商系统:特有的供应商入驻、买卖家分离、佣金结算、售后服务体系等功能更全面诠释了当今俗话说,人人心中有一个Hamlet,人人心中也都有一个领域模型的定义。  我曾经在很多场合谈到京东可以高速发展到今天的规模的原因,其中最核心的是坚持“倒三角”战略:建立出色的团队提起O2O,想必大家都会说:却,不就是团购、外卖配送、超市代购、上门洗车、上门按摩等等这样的鸟样吧?确实,看从单一的B2B和B2C网上商城逐渐演变为B2B2C网上商城,这个趋势是电子商务发展的必然结果。作为一家专业提一、汇总分析下阿里的电商架构阿里电商支撑架构模型二、阿里电商浅析1、一套模型支撑多个电商平台(1)独立的研发世界上有很多的意想不到。比如电解水,可以生产氢气和氧气。但反过来,就没几个人想到,将氢气和氧气“按配方”合成1. DCloud是怎么样的一家公司?你们主要做什么产品?能为用户提供什么服务?  DCloud是一家专注做随着红星美凯龙网上商城、齐家商城的正式试水,非标准品 (满足不同客户个性化需求的商品)正有望成为电商竞争的另什么是跨域JSONPproxy代理corsxdr  由于浏览器同源策略,凡是发送请求url的协议、域名、端口编者按:本文作者刘鑫,APICloud 移动应用云服务创始人兼 CEO,专注于国内外移动应用开发平台领域的研HTML 5 虽然只是一个技术标准,但是眼下更多承载着颠覆苹果与谷歌移动生态的理想。我并不想单纯从技术角度谈之前NativeScript 1.0发布的时候,就打算谈谈移动端跨平台开发这个话题。正好,今天国内技术专家“PC端地图工具无法捕捉到具体的用户位置(通过IP的话,用VPN或者代理工具,这个时候的位置和具体位置差别是非GoStream流应用、新体验热门文章最新文章GoStream流应用、新体验Json Web Tokens: Examples - Angular Tips
Join us in our way to learning Angular.js
Json Web Tokens: Examples
May 25th, 2014
So you liked my article about
and you want to see some examples right?
I have you covered with two basic but functional implementations of it both in Sails and Rails which you can adapt to you own framework of choice without hassle.
Sails implementation
First, I created a service to handle the encode / decode (this JWT implementation calls those methods sign and verify respectively), let&s see it:
api/services/sailsTokenAuth.js1
var jwt = require(&#39;jsonwebtoken&#39;);
module.exports.issueToken = function(payload) {
var token = jwt.sign(payload, process.env.TOKEN_SECRET || &our biggest secret&);
return token;
module.exports.verifyToken = function(token, verified) {
return jwt.verify(token, process.env.TOKEN_SECRET || &our biggest secret&, {}, verified);
We export two functions, one that will issue a token and one that will verify it. Here you can see how we pass our payload and the secret key. I suggest you to use an ENV variable to hold our secret, much better than a simple string. Also, a large random string is much harder to crack.
For the decoding, we pass there our token, our secret, no options (for advanced usages of JWT) and a callback that will be fired when the verifying is done.
Good, let&s see our AuthController:
First the authenticate method:
api/controllers/AuthController.js1
authenticate: function(req, res) {
var email = req.param(&#39;email&#39;);
var password = req.param(&#39;password&#39;);
if (!email || !password) {
return res.json(401, {err: &#39;email and password required&#39;});
User.findOneByEmail(email, function(err, user) {
if (!user) {
return res.json(401, {err: &#39;invalid email or password&#39;});
User.validPassword(password, user, function(err, valid) {
if (err) {
return res.json(403, {err: &#39;forbidden&#39;});
if (!valid) {
return res.json(401, {err: &#39;invalid email or password&#39;});
res.json({user: user, token: sailsTokenAuth.issueToken(user.id)});
We check that we passed credentials, then we find our user and we call a custom validPassword function (not interesting for this article but you can check it on the demo) to see if our user / pass combination is correct. So if our credentials are valid, we issue a token using our user.id as a payload and we also pass the complete user on the json (so angular can have it without hassle).
So: We send our credentials > we check its validity and if they are ok > we receive our user and a token via json.
Nothing fancy right? No special session stuff or code, just a normal function that returns a token.
The register method is not fancy either:
api/controllers/AuthController.js1
register: function(req, res) {
//TODO: Do some validation on the input
if (req.body.password !== req.body.confirmPassword) {
return res.json(401, {err: &#39;Password doesn\&#39;t match&#39;});
User.create({email: req.body.email, password: req.body.password}).exec(function(err, user) {
if (err) {
res.json(err.status, {err: err});
if (user) {
res.json({user: user, token: sailsTokenAuth.issueToken(user.id)});
We just create a user with those new credentials and if they are valid, we issue a token like we did on the authenticate method. We do that so the user doesn&t need to login by hand after registering.
So, how we manage incoming requests? Sails has a concept called Policies which are basically middlewares that runs before a controller. There we can check for our token, let&s see:
api/policies/tokenAuth.js1
module.exports = function(req, res, next) {
var token;
if (req.headers && req.headers.authorization) {
var parts = req.headers.authorization.split(&#39; &#39;);
if (parts.length == 2) {
var scheme = parts[0],
credentials = parts[1];
if (/^Bearer$/i.test(scheme)) {
token = credentials;
return res.json(401, {err: &#39;Format is Authorization: Bearer [token]&#39;});
} else if (req.param(&#39;token&#39;)) {
token = req.param(&#39;token&#39;);
// We delete the token from param to not mess with blueprints
delete req.query.token;
return res.json(401, {err: &#39;No Authorization header was found&#39;});
sailsTokenAuth.verifyToken(token, function(err, token) {
if (err) return res.json(401, {err: &#39;The token is not valid&#39;});
req.token = token;
First we check if we have the token on the header which basically is a header called authorization with the content Bearer token_string. If we have this kind of header we store the token_string part. If there is no header, we also check if we have it on the query string like: /api/foo?token=token_string.
When we finally have the token, we just verify it, extract its payload and assign it to req.token so we can access it from a controller. If there is no token, we just send an error json.
Now that we have our token verified and saved on the request object, we could do stuff like (this is not in the demo because Sails generates a virtual REST for you):
index: function(req, res) {
User.findOne(req.token).exec(function(err, message) {
// Work with the user here
Since our token is just our user id, we can use it to query it when needed.
There is nothing more to add. Surprised? We just needed a simple library to manage the encoding/decoding of the token and just issue it when we register or login and check for its existence before each request.
Rails implementation
You will be surprised to see that this implementation is almost the same (if we ignore my Rails ignorance this days). I created a lib for the encoding/decoding:
lib/auth_token.rb1
module AuthToken
def AuthToken.issue_token(payload)
JWT.encode(payload, Rails.application.secrets.secret_key_base)
def AuthToken.valid?(token)
JWT.decode(token, Rails.application.secrets.secret_key_base)
Basically it does the same as the sails one. The secret we are using here is the one that comes with the rails instalation. We can use what we want, I just took the advantage of having a good one already created.
So for the AuthController, let&s begin with register:
app/controllers/auth_controller.rb1
def register
user = User.new(user_params)
if user.save
token = AuthToken.issue_token({ user_id: user.id })
render json: { user: user,
token: token }
render json: { errors: user.errors }
We create an user and if all is correct, we issue a new token which we will return with our user via json.
For the authenticate method:
app/controllers/auth_controller.rb1
def authenticate
user = User.find_by(email: params[:email].downcase)
if user && user.authenticate(params[:password])
token = AuthToken.issue_token({ user_id: user.id })
render json: { user: user,
token: token }
render json: { error: &Invalid email/password combination& }, status: :unauthorized
No surprises here. If the credentials are valid, we issue the token and return it via json with our user.
How do we manage the request here? I created a base controller for all the API controllers (which I assume that all of them needs authentication) and there I created a method like:
app/controllers/api/base_controller.rb1
before_action :authenticate
def authenticate
token = request.headers[&#39;Authorization&#39;].split(&#39; &#39;).last
payload, header = AuthToken.valid?(token)
@current_user = User.find_by(id: payload[&#39;user_id&#39;])
render json: { error: &#39;Authorization header not valid&#39;}, status: :unauthorized
To be honest, my Sails implementation is far more complete, and we can certainly do all those checkings here, but for the demo I was simple. We split the header, we get the token and we verify it. If it is valid, we create our @current_user based on the payload we had on the token. We could just store the id as we did in Sails but I decided to always have our user ready too show you that all of this implementation is really flexible.
And that is all! We don&t need anything else. Of course we assume we have a User model with some password digest system like has_secure_password but that is really up to you. You can issue a token when you want to but the most common way is the login/pass. Nothing stops you of writing valid tokens on paper and give them away on the street like propaganda.
Angular consumption
Well, how we decide to work with the token on angular is really personal and I won&t lie, this is the first time I do auth on angular but I am quite happy with my approach.
I decided to store the token on the local storage, so I don&t need to login everytime I enter the page, but that is based on your personal use case.
Let&s see the auth service:
app.factory(&#39;Auth&#39;, function($http, LocalService, AccessLevels) {
authorize: function(access) {
if (access === AccessLevels.user) {
return this.isAuthenticated();
return true;
isAuthenticated: function() {
return LocalService.get(&#39;auth_token&#39;);
login: function(credentials) {
var login = $http.post(&#39;/auth/authenticate&#39;, credentials);
login.success(function(result) {
LocalService.set(&#39;auth_token&#39;, JSON.stringify(result));
return login;
logout: function() {
// The backend doesn&#39;t care about logouts, delete the token and you&#39;re good to go.
LocalService.unset(&#39;auth_token&#39;);
register: function(formData) {
LocalService.unset(&#39;auth_token&#39;);
var register = $http.post(&#39;/auth/register&#39;, formData);
register.success(function(result) {
LocalService.set(&#39;auth_token&#39;, JSON.stringify(result));
return register;
For the login, we make a post with our credentials and if it succeds, we store the token (and also the user, I got lazy here) into the localstorage. For the registering, we remove the token if any and well, same thing as login.
To see if we are authenticated I decided to check for the token existence. Since the backend doens&t know about logins, having the token means that we can query our stuff so if the token exist, we are &logged in&. Of course the server can reject it on the next request if the user no longer exist, it expired or we used the &rotate tokens& technique.
Look how the logout works! We just need to delete the token because as I said, the backend is not concerned about logins as there is no sessions or stuff like that.
The authorize method is a helper method I use to check if a user is authenticated or not before I enter a route (more on this later).
I also created a AuthInterceptor to handle the request/response:
app.factory(&#39;AuthInterceptor&#39;, function($q, $injector) {
request: function(config) {
var LocalService = $injector.get(&#39;LocalService&#39;);
var token;
if (LocalService.get(&#39;auth_token&#39;)) {
token = angular.fromJson(LocalService.get(&#39;auth_token&#39;)).token;
if (token) {
config.headers.Authorization = &#39;Bearer &#39; + token;
return config;
responseError: function(response) {
if (response.status === 401 || response.status === 403) {
LocalService.unset(&#39;auth_token&#39;);
$injector.get(&#39;$state&#39;).go(&#39;anon.login&#39;);
return $q.reject(response);
If there is a token saved, put it on a header so every request we make, will have it (just what we need!). For the response, if we get a 401 or 403, redirect me to login and delete the token if any.
The routes are like:
app.config(function($stateProvider, $urlRouterProvider, AccessLevels) {
$stateProvider
.state(&#39;anon&#39;, {
abstract: true,
template: &#39;&ui-view/&&#39;,
access: AccessLevels.anon
.state(&#39;anon.home&#39;, {
url: &#39;/&#39;,
templateUrl: &#39;home.html&#39;
.state(&#39;anon.login&#39;, {
url: &#39;/login&#39;,
templateUrl: &#39;auth/login.html&#39;,
controller: &#39;LoginController&#39;
.state(&#39;anon.register&#39;, {
url: &#39;/register&#39;,
templateUrl: &#39;auth/register.html&#39;,
controller: &#39;RegisterController&#39;
$stateProvider
.state(&#39;user&#39;, {
abstract: true,
template: &#39;&ui-view/&&#39;,
access: AccessLevels.user
.state(&#39;user.messages&#39;, {
url: &#39;/messages&#39;,
templateUrl: &#39;user/messages.html&#39;,
controller: &#39;MessagesController&#39;
$urlRouterProvider.otherwise(&#39;/&#39;);
We have a parent state for anonymous routes and a parent state for authenticated users. The important part here is that we have an access data there to give a nice UX on our page.
To handle the routes I do:
app.run(function($rootScope, $state, Auth) {
$rootScope.$on(&#39;$stateChangeStart&#39;, function(event, toState, toParams, fromState, fromParams) {
if (!Auth.authorize(toState.data.access)) {
event.preventDefault();
$state.go(&#39;anon.login&#39;);
If we are not authorized to enter the page (using the access data we put on the routes) we redirect to login. Here I use the method I have on the Auth service to basically check if the user is authenticated for the user routes. We can expand this implementation to put more roles like an admin one.
And that is it! Since the token goes via header, we can query our backend as we normally do. There is no need to do something extra.
I have a live demo . You can login with
/ 123123 or create your own user. About if the live demo is sails or rails& I forgot, they behave the same :)
Posted by Jesus Rodriguez
May 25th, 2014
Please enable JavaScript to view the
Copyright & 2016 - Jesus Rodriguez -
Powered by . Design by

我要回帖

更多关于 express res.jsonp 的文章

 

随机推荐